Skip to content

feat: Enhance AddMember feature with form validation and state manage…#146

Merged
abhishek-nexgen-dev merged 1 commit into
masterfrom
dev
Jun 9, 2026
Merged

feat: Enhance AddMember feature with form validation and state manage…#146
abhishek-nexgen-dev merged 1 commit into
masterfrom
dev

Conversation

@abhishek-nexgen-dev

Copy link
Copy Markdown
Member

…ment using react-hook-form

@abhishek-nexgen-dev abhishek-nexgen-dev merged commit 2091d2c into master Jun 9, 2026
2 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates react-hook-form and zod validation into the 'Add Member' feature, replacing local component state with form context and adding error displays. While the form integration is a solid improvement, several issues need to be addressed: a logic error in DropDown prevents it from opening when in an error state; redundant local state in Community_Involvement should be removed; syntax errors exist in InterestBox's Tailwind classes and CSS variables; invalid fractional Tailwind classes are used in PersonalInfoCard; the Zod URL validator will fail on raw domains without a protocol; the membershipStatus error message breaks the radio button layout; and SkillChip is left unstyled after class removal.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

</button>

{open && options.length > 0 && (
{!error && open && options.length > 0 && (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The conditional check !error prevents 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 !error from the condition restores normal dropdown functionality in error states.

Suggested change
{!error && open && options.length > 0 && (
{open && options.length > 0 && (


const {errors} = formState

const [internalNotes, setInternalNotes] = useState(watch("internalNotes") ?? "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Duplicating the form state with local useState for internalNotes will cause the UI to get out of sync when the form is reset (e.g., when clicking 'Discard Draft'), because useState only initializes on the first render. Instead, you should read the value directly from watch('internalNotes').

Suggested change
const [internalNotes, setInternalNotes] = useState(watch("internalNotes") ?? "");
const internalNotes = watch("internalNotes") ?? "";

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)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are syntax errors in the Tailwind classes here: bg-[cd-surface] is missing var() and brackets, and text-[--cd-text) has a mismatched closing parenthesis ) instead of ]. Since these colors are defined in your Tailwind theme configuration (--color-cd-surface and --color-cd-text), you can use the standard Tailwind classes bg-cd-surface and text-cd-text directly.

Suggested change
: "bg-[cd-surface] border-gray-300 text-[--cd-text)"
: "bg-cd-surface border-gray-300 text-cd-text"

<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"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The CSS variable reference var(cd-border-subtle) is missing the double dashes (--). Additionally, since --color-cd-border-subtle is defined in your Tailwind theme, you can use the standard class border-cd-border-subtle instead of an arbitrary value.

Suggested change
Clicked ? "border-blue-500 bg-blue-500" : "border-[var(cd-border-subtle)] bg-transparent"
Clicked ? "border-blue-500 bg-blue-500" : "border-cd-border-subtle bg-transparent"

<div className="w-[18%] flex flex-col gap-2 mb-4">
<div
className="w-[130px] h-[150px] border-2 border-dashed rounded-xl flex flex-col items-center justify-center"
className="w-32.5 h-37.5 border-2 border-dashed rounded-xl flex flex-col items-center justify-center"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Tailwind's default spacing scale does not include fractional values like 32.5 or 37.5. Using these classes will result in no width or height being applied. You should keep the original arbitrary values w-[130px] h-[150px] or use standard Tailwind spacing classes like w-32 h-36 or w-32 h-40.

Suggested change
className="w-32.5 h-37.5 border-2 border-dashed rounded-xl flex flex-col items-center justify-center"
className="w-[130px] h-[150px] border-2 border-dashed rounded-xl flex flex-col items-center justify-center"

Comment on lines +14 to +17
const optionalUrl = z.preprocess(
(value) => (value === "" ? undefined : value),
z.string().url("Invalid URL").optional(),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Zod's .url() validator requires a protocol (e.g., http:// or https://). Since the UI input only captures the domain (e.g., example.com) and prepends the protocol visually, validating the raw form value with .url() will always fail. You should update the preprocessor to prepend a default protocol if one is missing, so that it passes URL validation.

const optionalUrl = z.preprocess(
  (value) => {
    if (value === "") return undefined;
    if (typeof value === "string" && !/^https?:\/\//i.test(value)) {
      return `http://${value}`;
    }
    return value;
  },
  z.string().url("Invalid URL").optional(),
);

Comment on lines 62 to +67
value={internalNotes}
onChange={(_, value) => setInternalNotes(value)}
error={errors.internalNotes?.message}
onChange={(_, value) => {
setInternalNotes(value);
setValue("internalNotes", value, { shouldDirty: true });
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since internalNotes is now read directly from watch, we can remove the local state setter setInternalNotes.

Suggested change
value={internalNotes}
onChange={(_, value) => setInternalNotes(value)}
error={errors.internalNotes?.message}
onChange={(_, value) => {
setInternalNotes(value);
setValue("internalNotes", value, { shouldDirty: true });
}}
value={internalNotes}
error={errors.internalNotes?.message}
onChange={(_, value) => {
setValue("internalNotes", value, { shouldDirty: true });
}}

Comment on lines +40 to +42
{errors.membershipStatus && (
<p className="text-red-500 text-sm">{errors.membershipStatus.message}</p>
)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error message for membershipStatus is currently rendered in the middle of the radio options (between 'Active' and 'Inactive'). It should be moved to the bottom of the radio group container (after the 'Suspended' option) to avoid breaking the layout and grouping of the radio buttons.

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>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Removing bg-blue-100 text-blue-800 leaves the SkillChip component without any background or text color styling, making it look like plain text. If you want to make it theme-compatible, you should use theme classes like bg-cd-primary-subtle text-cd-primary-text or similar.

Suggested change
<div className="px-3 py-1 rounded-full text-sm">{props.skill}</div>
<div className="bg-cd-primary-subtle text-cd-primary-text px-3 py-1 rounded-full text-sm">{props.skill}</div>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant