-
Notifications
You must be signed in to change notification settings - Fork 17
feat: Enhance AddMember feature with form validation and state manage… #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,9 +3,24 @@ import { GrGroup } from "react-icons/gr"; | |||||||||||||||||||||||||
| import InterestBox from "./InterestBox"; | ||||||||||||||||||||||||||
| import AREA_OF_INTEREST from "../Constant/Interest.constant"; | ||||||||||||||||||||||||||
| import { TextArea } from "../../../../Component/ui/TextArea"; | ||||||||||||||||||||||||||
| import { useFormContext } from "react-hook-form"; | ||||||||||||||||||||||||||
| import type { MemberFormValues } from "../Validator/AddMember.Validator"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const Community_Involvement = () => { | ||||||||||||||||||||||||||
| const [internalNotes, setInternalNotes] = useState(""); | ||||||||||||||||||||||||||
| const { watch, setValue , formState} = useFormContext<MemberFormValues>(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const {errors} = formState | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const [internalNotes, setInternalNotes] = useState(watch("internalNotes") ?? ""); | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicating the form state with local
Suggested change
|
||||||||||||||||||||||||||
| const areaOfInterest = watch("areaOfInterest") ?? []; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| const toggleInterest = (interest: string, isChecked: boolean) => { | ||||||||||||||||||||||||||
| const nextInterests = isChecked | ||||||||||||||||||||||||||
| ? [...areaOfInterest, interest] | ||||||||||||||||||||||||||
| : areaOfInterest.filter((value) => value !== interest); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| setValue("areaOfInterest", nextInterests, { shouldDirty: true }); | ||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||
|
|
@@ -30,7 +45,13 @@ const Community_Involvement = () => { | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| <div className="flex flex-wrap gap-4 mt-3"> | ||||||||||||||||||||||||||
| {AREA_OF_INTEREST.map((interest, index) => ( | ||||||||||||||||||||||||||
| <InterestBox key={index} label={interest} isChecked={false} onClick={() => {}} /> | ||||||||||||||||||||||||||
| <InterestBox | ||||||||||||||||||||||||||
| key={index} | ||||||||||||||||||||||||||
| label={interest} | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| isChecked={areaOfInterest.includes(interest)} | ||||||||||||||||||||||||||
| onClick={(clicked) => toggleInterest(interest, clicked)} | ||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
@@ -39,7 +60,11 @@ const Community_Involvement = () => { | |||||||||||||||||||||||||
| name="internalNotes" | ||||||||||||||||||||||||||
| placeholder="Enter internal notes" | ||||||||||||||||||||||||||
| value={internalNotes} | ||||||||||||||||||||||||||
| onChange={(_, value) => setInternalNotes(value)} | ||||||||||||||||||||||||||
| error={errors.internalNotes?.message} | ||||||||||||||||||||||||||
| onChange={(_, value) => { | ||||||||||||||||||||||||||
| setInternalNotes(value); | ||||||||||||||||||||||||||
| setValue("internalNotes", value, { shouldDirty: true }); | ||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||
|
Comment on lines
62
to
+67
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since
Suggested change
|
||||||||||||||||||||||||||
| className="mt-[3vh]" | ||||||||||||||||||||||||||
| rows={5} | ||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -15,7 +15,7 @@ const InterestBox = (props: InterestBoxProps) => { | |||||
| className={`InterestBox flex p-3 font-bold ${ | ||||||
| Clicked | ||||||
| ? "bg-blue-100 border-blue-500 text-blue-600" | ||||||
| : "bg-gray-100 border-gray-300 text-black" | ||||||
| : "bg-[cd-surface] border-gray-300 text-[--cd-text)" | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are syntax errors in the Tailwind classes here:
Suggested change
|
||||||
| } border rounded-lg cursor-pointer`} | ||||||
| onClick={() => { | ||||||
| props.onClick(!Clicked); | ||||||
|
|
@@ -24,7 +24,7 @@ const InterestBox = (props: InterestBoxProps) => { | |||||
| > | ||||||
| <div | ||||||
| className={`rounded-md border-2 w-6 h-6 flex items-center justify-center ${ | ||||||
| Clicked ? "border-blue-500 bg-blue-500" : "border-gray-300" | ||||||
| Clicked ? "border-blue-500 bg-blue-500" : "border-[var(cd-border-subtle)] bg-transparent" | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The CSS variable reference
Suggested change
|
||||||
| }`} | ||||||
| > | ||||||
| {Clicked && <TiTick className="text-white text-lg" />} | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,11 @@ | ||
| import { useState } from "react"; | ||
|
|
||
| import { useFormContext } from "react-hook-form"; | ||
| import type { MemberFormValues } from "../Validator/AddMember.Validator"; | ||
|
|
||
| type MembershipStatus = "Active" | "Inactive" | "Pending" | "Suspended" | "On Boarding"; | ||
|
|
||
| const MemberShip_Status = () => { | ||
| const [membershipStatus, setMembershipStatus] = useState<MembershipStatus>("Active"); | ||
|
|
||
| const statusColorMap: Record<MembershipStatus, string> = { | ||
| Active: "bg-green-500", | ||
| Inactive: "bg-gray-400", | ||
|
|
@@ -13,10 +14,12 @@ const MemberShip_Status = () => { | |
| "On Boarding": "bg-blue-400", | ||
| }; | ||
|
|
||
| const { watch, setValue , formState} = useFormContext<MemberFormValues>(); | ||
| const {errors} = formState | ||
| const membershipStatus = (watch("membershipStatus") ?? "On Boarding") as MembershipStatus; | ||
|
|
||
| return ( | ||
| <div className="MemberShip_Status flex flex-col gap-2 mt-4 text-lg"> | ||
| <p className="text-md font-semibold">Membership Status</p> | ||
|
|
||
| {/* Active */} | ||
| <div className="flex items-center gap-4"> | ||
| <input | ||
|
|
@@ -25,7 +28,7 @@ const MemberShip_Status = () => { | |
| id="Active" | ||
| value="Active" | ||
| checked={membershipStatus === "Active"} | ||
| onChange={() => setMembershipStatus("Active")} | ||
| onChange={() => setValue("membershipStatus", "Active", { shouldDirty: true })} | ||
| /> | ||
|
|
||
| <span | ||
|
|
@@ -34,15 +37,20 @@ const MemberShip_Status = () => { | |
| <label htmlFor="Active">Active</label> | ||
| </div> | ||
|
|
||
| {errors.membershipStatus && ( | ||
| <p className="text-red-500 text-sm">{errors.membershipStatus.message}</p> | ||
| )} | ||
|
Comment on lines
+40
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| {/* Inactive */} | ||
| <div className="flex items-center gap-4"> | ||
| <input | ||
| type="radio" | ||
| id="Inactive" | ||
| name="membershipStatus" | ||
|
|
||
| value="Inactive" | ||
| checked={membershipStatus === "Inactive"} | ||
| onChange={() => setMembershipStatus("Inactive")} | ||
| onChange={() => setValue("membershipStatus", "Inactive", { shouldDirty: true })} | ||
| /> | ||
|
|
||
| <span | ||
|
|
@@ -60,7 +68,7 @@ const MemberShip_Status = () => { | |
| value="Pending" | ||
| id="Pending" | ||
| checked={membershipStatus === "Pending"} | ||
| onChange={() => setMembershipStatus("Pending")} | ||
| onChange={() => setValue("membershipStatus", "Pending", { shouldDirty: true })} | ||
| /> | ||
|
|
||
| <span | ||
|
|
@@ -77,7 +85,7 @@ const MemberShip_Status = () => { | |
| id="OnBoarding" | ||
| value="On Boarding" | ||
| checked={membershipStatus === "On Boarding"} | ||
| onChange={() => setMembershipStatus("On Boarding")} | ||
| onChange={() => setValue("membershipStatus", "On Boarding", { shouldDirty: true })} | ||
| /> | ||
| <span | ||
| className={`w-4 h-4 rounded-full ${statusColorMap["On Boarding"]} border border-gray-300`} | ||
|
|
@@ -93,7 +101,7 @@ const MemberShip_Status = () => { | |
| id="Suspended" | ||
| value="Suspended" | ||
| checked={membershipStatus === "Suspended"} | ||
| onChange={() => setMembershipStatus("Suspended")} | ||
| onChange={() => setValue("membershipStatus", "Suspended", { shouldDirty: true })} | ||
| /> | ||
|
|
||
| <span | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,7 @@ type SkillChipProps = { | |||||
|
|
||||||
| const SkillChip = (props: SkillChipProps) => { | ||||||
| return ( | ||||||
| <div className="bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm">{props.skill}</div> | ||||||
| <div className="px-3 py-1 rounded-full text-sm">{props.skill}</div> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing
Suggested change
|
||||||
| ); | ||||||
| }; | ||||||
|
|
||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditional check
!errorprevents the dropdown list from rendering when there is an active validation error. This makes it impossible for the user to open the dropdown and select a different option to correct the error. Removing!errorfrom the condition restores normal dropdown functionality in error states.