Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ body {
--cd-surface-2: #f1f5f9;
--cd-surface-3: #eef2f7;
--cd-border: #d8e1ee;
--cd-border-subtle: #e9eef6;
--cd-border-subtle: rgb(165, 166, 167);
--cd-text: #1e293b;
--cd-text-2: #53657d;
--cd-text-muted: #8392a8;
Expand Down
14 changes: 11 additions & 3 deletions src/Component/ui/DropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useTheme } from "@/theme";
type DropDownProps = {
options: string[];
label?: string;
error?: string;
onSelect: (option: string) => void;
className?: string;
value?: string;
Expand All @@ -20,6 +21,7 @@ const DropDown: React.FC<DropDownProps> = ({
value,
placeholder = "Select an option",
disabled = false,
error,
}) => {
const { theme } = useTheme();
const [open, setOpen] = useState(false);
Expand Down Expand Up @@ -69,7 +71,7 @@ const DropDown: React.FC<DropDownProps> = ({
className="w-full rounded-lg px-3 py-2 text-left flex justify-between items-center text-sm transition-all duration-150 disabled:cursor-not-allowed disabled:opacity-60"
style={{
backgroundColor: theme.bg.surface,
border: `1px solid ${theme.border.default}`,
border: `1px solid ${error ? "var(--cd-danger)" : "var(--cd-border)"}`,
color: selected ? theme.text.primary : theme.text.muted,
}}
>
Expand All @@ -80,12 +82,12 @@ const DropDown: React.FC<DropDownProps> = ({
/>
</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 && (

<div
className="absolute mt-1 w-full rounded-lg z-20 overflow-hidden max-h-60 overflow-y-auto"
style={{
backgroundColor: theme.bg.surface,
border: `1px solid ${theme.border.default}`,
border: `1px solid ${error ? "var(--cd-danger)" : "var(--cd-border)"}`,
boxShadow: `0 8px 24px ${theme.shadow.md}`,
}}
role="listbox"
Expand Down Expand Up @@ -115,6 +117,12 @@ const DropDown: React.FC<DropDownProps> = ({
))}
</div>
)}

{error && (
<p className="text-xs mt-1 text-[var(--cd-danger)]">
{error}
</p>
)}
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/Component/ui/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type InputType = "text" | "email" | "password" | "number" | "url" | "tel" | "tim
type InputProps = {
label?: string;
name: string;

placeholder?: string;
value?: string | number;
type?: InputType;
Expand Down
2 changes: 1 addition & 1 deletion src/Component/ui/Url.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";

interface UrlProps {
protocol?: string;
domain: string;
domain: string | undefined;
themeMode?: "light" | "dark";
className?: string;
style?: React.CSSProperties;
Expand Down
15 changes: 8 additions & 7 deletions src/features/AddMember/v1/Component/AddMemberHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { Link } from "react-router";
import Button from "../../../../Component/ui/Button";
import { memo } from "react";

const AddMemberHeader = () => {
type AddMemberHeaderProps = {
onCreate: () => void;
onDiscard: () => void;
};

const AddMemberHeader = ({ onCreate, onDiscard }: AddMemberHeaderProps) => {
return (
<div
className="py-[3vh] w-full border-b flex text-xl font-bold justify-between"
Expand All @@ -20,12 +25,8 @@ const AddMemberHeader = () => {
</Link>

<div className="w-[40%] h-full mr-[3vw] flex justify-end gap-3">
<Button
text="Discard Draft"
variant="secondary"
onClick={() => alert("Discard Draft clicked")}
/>
<Button text="Create Member" onClick={() => alert("Create Member clicked")} />
<Button text="Discard Draft" variant="secondary" onClick={onDiscard} />
<Button text="Create Member" onClick={onCreate} />
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const Administrative_MetaData = () => {
Administrative Metadata
</p>
<MemberShip_Status />
<AccessLevel />
{/* <AccessLevel /> */}
</div>
);
};
Expand Down
31 changes: 28 additions & 3 deletions src/features/AddMember/v1/Component/Community_Involment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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") ?? "");

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

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
Expand All @@ -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>

Expand All @@ -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

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 });
}}

className="mt-[3vh]"
rows={5}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/features/AddMember/v1/Component/InterestBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)"

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"

} border rounded-lg cursor-pointer`}
onClick={() => {
props.onClick(!Clicked);
Expand All @@ -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"

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"

}`}
>
{Clicked && <TiTick className="text-white text-lg" />}
Expand Down
26 changes: 17 additions & 9 deletions src/features/AddMember/v1/Component/MemberShip_Status.tsx
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",
Expand All @@ -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
Expand All @@ -25,7 +28,7 @@ const MemberShip_Status = () => {
id="Active"
value="Active"
checked={membershipStatus === "Active"}
onChange={() => setMembershipStatus("Active")}
onChange={() => setValue("membershipStatus", "Active", { shouldDirty: true })}
/>

<span
Expand All @@ -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

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.


{/* 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
Expand All @@ -60,7 +68,7 @@ const MemberShip_Status = () => {
value="Pending"
id="Pending"
checked={membershipStatus === "Pending"}
onChange={() => setMembershipStatus("Pending")}
onChange={() => setValue("membershipStatus", "Pending", { shouldDirty: true })}
/>

<span
Expand All @@ -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`}
Expand All @@ -93,7 +101,7 @@ const MemberShip_Status = () => {
id="Suspended"
value="Suspended"
checked={membershipStatus === "Suspended"}
onChange={() => setMembershipStatus("Suspended")}
onChange={() => setValue("membershipStatus", "Suspended", { shouldDirty: true })}
/>

<span
Expand Down
2 changes: 1 addition & 1 deletion src/features/AddMember/v1/Component/SkillChip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>

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>

);
};

Expand Down
33 changes: 24 additions & 9 deletions src/features/AddMember/v1/Page/AddMemberPage.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,37 @@
import { FormProvider } from "react-hook-form";
import AddMemberHeader from "../Component/AddMemberHeader";
import Administrative_MetaData from "../Component/Administrative_MetaData";
import Community_Involvement from "../Component/Community_Involment";
import PersonalInfoCard from "../Sections/PersonalInfoCard";
import ProfessionalDetails from "../Sections/ProfessionalDetails";
import { useAddMember } from "../hook/useAddMember";

const AddMemberPage = () => {
const methods = useAddMember();

const handleCreateMember = methods.handleSubmit((data) => {
try {
alert("Member created successfully!");
console.log("Add member submit", data);
} catch (error) {
console.error("Error creating member:", error);
}
});

return (
<div className="w-full flex flex-col cd-page">
<AddMemberHeader />
<div className="flex p-8 gap-8 w-full flex-col lg:flex-row items-start overflow-x-hidden">
<div className="w-full lg:w-[65%] h-full flex-col">
<PersonalInfoCard />
<ProfessionalDetails />
<Community_Involvement />
<FormProvider {...methods}>
<div className="w-full flex flex-col cd-page">
<AddMemberHeader onCreate={handleCreateMember} onDiscard={() => methods.reset()} />
<div className="flex p-8 gap-8 w-full flex-col lg:flex-row items-start overflow-x-hidden">
<div className="w-full lg:w-[65%] h-full flex-col">
<PersonalInfoCard />
<ProfessionalDetails />
<Community_Involvement />
</div>
<Administrative_MetaData />
</div>
<Administrative_MetaData />
</div>
</div>
</FormProvider>
);
};

Expand Down
Loading
Loading