From 377b1126839356129128ca1b58eab59b5607d331 Mon Sep 17 00:00:00 2001 From: siva-mirrapalli <sivamirrappalli@gmail.com> Date: Thu, 13 Mar 2025 12:26:16 +0530 Subject: [PATCH] job description full view and profile details full view --- frontend/src/app/(panel)/jds/page.tsx | 11 +- frontend/src/app/(panel)/profiles/page.tsx | 11 +- .../src/app/interviews/[interviewId]/page.tsx | 2 +- frontend/src/app/interviews/page.tsx | 1 + frontend/src/lib/components/LandingPage.tsx | 2 +- frontend/src/lib/components/ProfileCard.tsx | 10 +- .../src/lib/components/ProfilesLayout.tsx | 16 ++- .../job-description/JobDescriptionCard.tsx | 9 +- .../job-description/JobDescriptionLayout.tsx | 19 +++- .../JobDescriptionUploadSheet.tsx | 103 +++++++++--------- .../components/resume/ProfileUploadSheet.tsx | 48 ++++---- frontend/src/lib/components/shared/Card.tsx | 9 +- .../src/lib/components/shared/SideBar.tsx | 21 ++-- .../utils/contexts/JobDescriptionProvider.tsx | 56 ++++++++++ .../utils/contexts/ProfileViewProvider.tsx | 54 +++++++++ 15 files changed, 267 insertions(+), 105 deletions(-) create mode 100644 frontend/src/lib/utils/contexts/JobDescriptionProvider.tsx create mode 100644 frontend/src/lib/utils/contexts/ProfileViewProvider.tsx diff --git a/frontend/src/app/(panel)/jds/page.tsx b/frontend/src/app/(panel)/jds/page.tsx index bba1967..205e6d5 100644 --- a/frontend/src/app/(panel)/jds/page.tsx +++ b/frontend/src/app/(panel)/jds/page.tsx @@ -3,6 +3,7 @@ import { Metadata } from "next"; import { DashboardHeader } from "@/lib/components/DashboardHeader"; import { JobDescriptionLayout } from "@/lib/components/job-description/JobDescriptionLayout"; import { JobDescriptionUploadSheet } from "@/lib/components/job-description/JobDescriptionUploadSheet"; +import { JobDescriptionProvider } from "@/lib/utils/contexts/JobDescriptionProvider"; export const metadata: Metadata = { title: "job description", @@ -11,10 +12,12 @@ export const metadata: Metadata = { const Jobs: React.FC = () => { return ( <React.Fragment> - <DashboardHeader> - <JobDescriptionUploadSheet /> - </DashboardHeader> - <JobDescriptionLayout /> + <JobDescriptionProvider> + <DashboardHeader> + <JobDescriptionUploadSheet /> + </DashboardHeader> + <JobDescriptionLayout /> + </JobDescriptionProvider> </React.Fragment> ); }; diff --git a/frontend/src/app/(panel)/profiles/page.tsx b/frontend/src/app/(panel)/profiles/page.tsx index a21faf4..f8193cb 100644 --- a/frontend/src/app/(panel)/profiles/page.tsx +++ b/frontend/src/app/(panel)/profiles/page.tsx @@ -3,6 +3,7 @@ import { Metadata } from "next"; import { DashboardHeader } from "@/lib/components/DashboardHeader"; import { ProfilesLayout } from "@/lib/components/ProfilesLayout"; import { ProfileUploadSheet } from "@/lib/components/resume/ProfileUploadSheet"; +import { ProfileViewProvider } from "@/lib/utils/contexts/ProfileViewProvider"; export const metadata: Metadata = { title: "profile", @@ -11,10 +12,12 @@ export const metadata: Metadata = { const Profiles: React.FC = () => { return ( <React.Fragment> - <DashboardHeader> - <ProfileUploadSheet /> - </DashboardHeader> - <ProfilesLayout /> + <ProfileViewProvider> + <DashboardHeader> + <ProfileUploadSheet /> + </DashboardHeader> + <ProfilesLayout /> + </ProfileViewProvider> </React.Fragment> ); }; diff --git a/frontend/src/app/interviews/[interviewId]/page.tsx b/frontend/src/app/interviews/[interviewId]/page.tsx index 9f7d2f7..98bf287 100644 --- a/frontend/src/app/interviews/[interviewId]/page.tsx +++ b/frontend/src/app/interviews/[interviewId]/page.tsx @@ -1,4 +1,4 @@ -import LandingPage from "@/lib/components/LandingPage"; +import { LandingPage } from "@/lib/components/LandingPage"; import { Metadata } from "next"; export const metadata: Metadata = { title: "interviews", diff --git a/frontend/src/app/interviews/page.tsx b/frontend/src/app/interviews/page.tsx index 49f3d1b..83871d1 100644 --- a/frontend/src/app/interviews/page.tsx +++ b/frontend/src/app/interviews/page.tsx @@ -20,6 +20,7 @@ const Interviews = () => { Logger.log("completed"); } }; + useEffect(() => { getInterviewsByLoggedInUser(); }, []); diff --git a/frontend/src/lib/components/LandingPage.tsx b/frontend/src/lib/components/LandingPage.tsx index bfc6d89..79a1675 100644 --- a/frontend/src/lib/components/LandingPage.tsx +++ b/frontend/src/lib/components/LandingPage.tsx @@ -29,7 +29,7 @@ import { Logger } from "@/services/logging"; export const nextBackend = APP_URL; -export default function LandingPage() { +export function LandingPage() { const [url, setUrl] = useState<string>(""); const [meetingToken, setMeetingToken] = useState<string>(""); const [daily, setDaily] = useState<DailyCall | null>(null); diff --git a/frontend/src/lib/components/ProfileCard.tsx b/frontend/src/lib/components/ProfileCard.tsx index 5a0c215..a325058 100644 --- a/frontend/src/lib/components/ProfileCard.tsx +++ b/frontend/src/lib/components/ProfileCard.tsx @@ -8,11 +8,19 @@ import { Avatar } from "./shared/Avatar"; type ProfileCardProps = { profile: Profile; + onCardClick?: () => void; }; -export const ProfileCard: React.FC<ProfileCardProps> = ({ profile }) => { +export const ProfileCard: React.FC<ProfileCardProps> = ({ + profile, + onCardClick, +}) => { return ( <AppCard + className="cursor-pointer" + onCardClick={() => { + onCardClick && onCardClick(); + }} headerContent={<ProfileHeader profile={profile} />} bodyContent={<ProfileBody profile={profile} />} footerContent={<ProfileFooter profile={profile} />} diff --git a/frontend/src/lib/components/ProfilesLayout.tsx b/frontend/src/lib/components/ProfilesLayout.tsx index d916d5e..ff39d1a 100644 --- a/frontend/src/lib/components/ProfilesLayout.tsx +++ b/frontend/src/lib/components/ProfilesLayout.tsx @@ -5,10 +5,12 @@ import { Profile } from "@/lib/types/Profile"; import { useNotifyDispatch } from "@/lib/utils/hooks/useNotifyDispatch"; import { fetchAllProfiles } from "@/services/profile-apis"; import { ProfileCard } from "./ProfileCard"; +import { useProfileView } from "../utils/contexts/ProfileViewProvider"; export const ProfilesLayout: React.FC = () => { const [profiles, setProfiles] = useState<Profile[]>([]); const { addLoader, removeLoader } = useNotifyDispatch(); + const { setIsCreate, setProfile, setIsOpen } = useProfileView(); const getProfiles = async () => { try { @@ -21,6 +23,12 @@ export const ProfilesLayout: React.FC = () => { } }; + const onCardClick = (profile: Profile) => { + setIsOpen(true); + setIsCreate(false); + setProfile(profile); + }; + useEffect(() => { getProfiles(); }, []); @@ -28,7 +36,13 @@ export const ProfilesLayout: React.FC = () => { <div className="w-full"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5"> {profiles.map((profile) => { - return <ProfileCard profile={profile} key={profile._id} />; + return ( + <ProfileCard + profile={profile} + key={profile._id} + onCardClick={() => onCardClick(profile)} + /> + ); })} </div> </div> diff --git a/frontend/src/lib/components/job-description/JobDescriptionCard.tsx b/frontend/src/lib/components/job-description/JobDescriptionCard.tsx index 5d17284..b730c12 100644 --- a/frontend/src/lib/components/job-description/JobDescriptionCard.tsx +++ b/frontend/src/lib/components/job-description/JobDescriptionCard.tsx @@ -11,6 +11,7 @@ type JobDescriptionCardProps = { openScheduleOptimizerPopup?: () => void; index?: number; showGreenDot?: boolean; + onCardClick?: () => void; }; const getComparisionDate = (description: JobDescription) => { @@ -35,9 +36,12 @@ export const JobDescriptionCard: React.FC<JobDescriptionCardProps> = ({ onMatchProfiles, openScheduleOptimizerPopup, index, + onCardClick, }) => { return ( <AppCard + className="cursor-pointer" + onCardClick={onCardClick} headerContent={ <JobHeader jobDescription={jobDescription} @@ -140,7 +144,10 @@ export const JobFooter: React.FC<JobDescriptionCardProps> = ({ </div> <div className="bg-[#E4EBFD] rounded-sm flex items-center justify-center text-[#5353EF] p-2 cursor-pointer text-[16px] font-[400]" - onClick={() => onMatchProfiles?.(jobDescription)} + onClick={(e) => { + e.stopPropagation(); + onMatchProfiles?.(jobDescription); + }} > Suggest Profiles </div> diff --git a/frontend/src/lib/components/job-description/JobDescriptionLayout.tsx b/frontend/src/lib/components/job-description/JobDescriptionLayout.tsx index dfbbb67..9c87707 100644 --- a/frontend/src/lib/components/job-description/JobDescriptionLayout.tsx +++ b/frontend/src/lib/components/job-description/JobDescriptionLayout.tsx @@ -11,6 +11,7 @@ import { Profile } from "@/lib/types/Profile"; import { AppDialog } from "../shared/AppDialog"; import * as Dialog from "@radix-ui/react-dialog"; import { CardContent } from "@/lib/components/ui/card"; +import { useJD } from "@/lib/utils/contexts/JobDescriptionProvider"; export const formatDate = (date: Date | string | undefined) => { if (!date) return "NA"; @@ -42,6 +43,7 @@ export const JobDescriptionLayout: React.FC = () => { const [scheduleOptimizerPopup, setScheduleOptimizerPopup] = useState<boolean>(false); const [sheetOpen, setSheetOpen] = useState(false); + const { setIsOpen, setJobDescription, setIsCreate } = useJD(); const onMatchProfiles = (job: JobDescription) => { console.log("listening"); @@ -82,6 +84,12 @@ export const JobDescriptionLayout: React.FC = () => { setIsLoading(false); }; + const onCardClick = (jd: JobDescription) => { + setIsOpen(true); + setJobDescription(jd); + setIsCreate(false); + }; + const schedulerData = selectedJD?.schedules; return ( <div className="w-full"> @@ -118,6 +126,7 @@ export const JobDescriptionLayout: React.FC = () => { {jds.map((jd, index) => { return ( <JobDescriptionCard + onCardClick={() => onCardClick(jd)} jobDescription={jd} key={jd._id} onMatchProfiles={() => onMatchProfiles(jd)} @@ -133,12 +142,10 @@ export const JobDescriptionLayout: React.FC = () => { <JobMatchingProfilesSheet title={selectedJD?.jobTitle || ""} open={sheetOpen} - onOpenChange={() => { - // if (!isLoading) { - // setSelectedJD(null); - // setSheetOpen(false); - // setIsLoading(false); - // } + onOpenChange={(open) => { + setSelectedJD(null); + setSheetOpen(open); + setIsLoading(false); }} profiles={profiles.sort((a, b) => (b?.score || 0) - (a?.score || 0))} setIsLoading={setIsLoading} diff --git a/frontend/src/lib/components/job-description/JobDescriptionUploadSheet.tsx b/frontend/src/lib/components/job-description/JobDescriptionUploadSheet.tsx index 66b1daf..c941303 100644 --- a/frontend/src/lib/components/job-description/JobDescriptionUploadSheet.tsx +++ b/frontend/src/lib/components/job-description/JobDescriptionUploadSheet.tsx @@ -22,6 +22,7 @@ import JobDescriptionPrompts from "./JobDescriptionPrompts"; import { toast } from "sonner"; import JobDescriptionsJson from "../../../../public/job-descriptions.json"; import Icon from "../shared/Icon"; +import { useJD } from "@/lib/utils/contexts/JobDescriptionProvider"; const jobDescriptionUploadSheetLocale: Record<string, string> = { aj: "Add Job", @@ -51,11 +52,7 @@ const jobSchema = yup.object().shape({ }); export const JobDescriptionUploadSheet = () => { - const [jobDescription, setJobDescription] = useState<JobDescription | null>( - null, - ); const [isLoading, setIsLoading] = useState(false); - const [isOpen, setIsOpen] = useState(false); const { register, reset, @@ -66,6 +63,14 @@ export const JobDescriptionUploadSheet = () => { resolver: yupResolver(jobSchema), }); const { addLoader, removeLoader } = useNotifyDispatch(); + const { + isOpen, + setIsOpen, + setJobDescription, + jobDescription, + isCreate, + setIsCreate, + } = useJD(); const onSubmit = async (data: FieldValues) => { try { @@ -116,6 +121,7 @@ export const JobDescriptionUploadSheet = () => { const onOpenChange = (open: boolean) => { setIsOpen(open); setJobDescription(null); + setIsCreate(true); reset(); }; @@ -146,14 +152,6 @@ export const JobDescriptionUploadSheet = () => { onOpenChange={onOpenChange} showCloseButton={false} trigger={ - // <button - // className="bg-[#5353EF] text-white rounded-sm px-4 py-2 overflow-y-auto h-full" - // onClick={() => { - // setIsOpen(true); - // }} - // > - // <span>{jobDescriptionUploadSheetLocale["aj"]}</span> - // </button> <button className="flex bg-[#5353EF] justify-between text-white rounded-sm px-[20px] py-[6px] w-[128px]" onClick={() => setIsOpen(true)} @@ -171,40 +169,45 @@ export const JobDescriptionUploadSheet = () => { > {isLoading && <CustomLoader loaderType={LoaderTypes.JD_LOADER} />} <div className="flex flex-col gap-3 h-full mt-4"> - <form onSubmit={handleSubmit(onSubmit)}> - <div key={field.name} className="flex flex-col outline-none h-[20%]"> - {field.label && ( - <label className="font-[600] text-[0.6rem] mb-1 text-[#404040]"> - {field.label} - </label> - )} - <div className="border border-[#E9E9E9]"> - <textarea - id={field.name} - className={`resize-none text-sm text-[#303030] h-[5rem] p-2 w-[100%] outline-none rounded-[4px] placeholder:text-sm placeholder:font-[400] placeholder:text-[#303030] ${ - errors[`${field.name}`] - ? "border-red-500" - : "border-[#E9E9E9]" - }`} - placeholder={field.placeholder} - {...register(field.name)} - /> - {errors[field.name] && ( - <span className="text-red-500 text-[0.75rem]"> - {errors[field.name]?.message as ReactNode} - </span> + {isCreate && ( + <form onSubmit={handleSubmit(onSubmit)}> + <div + key={field.name} + className="flex flex-col outline-none h-[20%]" + > + {field.label && ( + <label className="font-[600] text-[0.6rem] mb-1 text-[#404040]"> + {field.label} + </label> )} - <div className="flex flex-col sm:flex-row sm:justify-end gap-2 p-2"> - <button - className="bg-[#5353EF] text-white rounded-sm px-4 py-2" - type="submit" - > - <span>{actions.generate}</span> - </button> + <div className="border border-[#E9E9E9]"> + <textarea + id={field.name} + className={`resize-none text-sm text-[#303030] h-[5rem] p-2 w-[100%] outline-none rounded-[4px] placeholder:text-sm placeholder:font-[400] placeholder:text-[#303030] ${ + errors[`${field.name}`] + ? "border-red-500" + : "border-[#E9E9E9]" + }`} + placeholder={field.placeholder} + {...register(field.name)} + /> + {errors[field.name] && ( + <span className="text-red-500 text-[0.75rem]"> + {errors[field.name]?.message as ReactNode} + </span> + )} + <div className="flex flex-col sm:flex-row sm:justify-end gap-2 p-2"> + <button + className="bg-[#5353EF] text-white rounded-sm px-4 py-2" + type="submit" + > + <span>{actions.generate}</span> + </button> + </div> </div> </div> - </div> - </form> + </form> + )} {!jobDescription && ( <JobDescriptionPrompts @@ -218,7 +221,7 @@ export const JobDescriptionUploadSheet = () => { <span className="text-[#000000] font-[500] text-[1rem] mb-1 inline-block"> {jobDescriptionUploadSheetLocale["jd"]} </span> - <div className="max-h-[62vh] overflow-auto"> + <div className=" overflow-auto"> <div className="flex flex-col gap-[1rem] border border-[#E9E9E9] h-full rounded-sm p-4 overflow-y-auto"> {Object.entries(basicJobDetails).map(([key, value]) => { return ( @@ -260,11 +263,13 @@ export const JobDescriptionUploadSheet = () => { })} </div> </div> - <CustomSheetFooter - className="" - onSave={onSaveJobDescription} - onCancel={() => onCancel()} - /> + {isCreate && ( + <CustomSheetFooter + className="" + onSave={onSaveJobDescription} + onCancel={() => onCancel()} + /> + )} </> )} </div> diff --git a/frontend/src/lib/components/resume/ProfileUploadSheet.tsx b/frontend/src/lib/components/resume/ProfileUploadSheet.tsx index 61add41..26ecdd8 100644 --- a/frontend/src/lib/components/resume/ProfileUploadSheet.tsx +++ b/frontend/src/lib/components/resume/ProfileUploadSheet.tsx @@ -26,6 +26,7 @@ import { useNotifyDispatch } from "@/lib/utils/hooks/useNotifyDispatch"; import CustomLoader, { LoaderTypes } from "../loaders/CustomLoader"; import { toast } from "sonner"; import Icon from "../shared/Icon"; +import { useProfileView } from "@/lib/utils/contexts/ProfileViewProvider"; const profileUploadSheetLocale = { ac: "Add Candidate", @@ -58,10 +59,10 @@ const profileSchema = yup.object().shape({ }); export const ProfileUploadSheet = () => { - const [profile, setProfile] = useState<Profile | null>(null); - const [isOpen, setIsOpen] = useState(false); const [isLoading, setIsLoading] = useState<boolean>(false); const { addLoader, removeLoader } = useNotifyDispatch(); + const { setIsCreate, isCreate, isOpen, setIsOpen, setProfile, profile } = + useProfileView(); const { register, handleSubmit, @@ -165,13 +166,10 @@ export const ProfileUploadSheet = () => { const onCancel = () => { setIsOpen(false); setProfile(null); + setIsCreate(true); reset(); }; - // const closeSheet = () => { - // setIsOpen(false); - // }; - useEffect(() => { if (!profile) return; console.log(profile?.basicDetails.dob); @@ -214,28 +212,30 @@ export const ProfileUploadSheet = () => { description="" className="overflow-y-scroll h-[100vh]" open={isOpen} - onOpenChange={setIsOpen} + onOpenChange={onCancel} > {isLoading && ( <CustomLoader loaderType={LoaderTypes.RESUME_PARSING_LOADER} /> )} <form onSubmit={handleSubmit(onSubmit)} className="mt-4"> - <label - htmlFor="file" - className="cursor-pointer border-2 border-dashed border-[#97CBFF] bg-[#F9FCFF] rounded-lg p-4 hover:#97CBFF/50 flex flex-col items-center gap-2 justify-center" - > - <Upload className="text-[#7A7A7A] h-4 w-4" /> - <span className="text-[#5353EF] text-[0.8rem] font-[400]"> - {profileUploadSheetLocale["uploadResume"]} - </span> - <input - id="file" - type="file" - accept=".pdf" - onChange={handleFileUpload} - className="hidden" - /> - </label> + {isCreate && ( + <label + htmlFor="file" + className="cursor-pointer border-2 border-dashed border-[#97CBFF] bg-[#F9FCFF] rounded-lg p-4 hover:#97CBFF/50 flex flex-col items-center gap-2 justify-center" + > + <Upload className="text-[#7A7A7A] h-4 w-4" /> + <span className="text-[#5353EF] text-[0.8rem] font-[400]"> + {profileUploadSheetLocale["uploadResume"]} + </span> + <input + id="file" + type="file" + accept=".pdf" + onChange={handleFileUpload} + className="hidden" + /> + </label> + )} {profile && ( <div className="py-2 flex flex-col gap-6"> <BasicProfile register={register} errors={errors} /> @@ -245,7 +245,7 @@ export const ProfileUploadSheet = () => { errors={errors} /> <AdditionalProfileInfo register={register} errors={errors} /> - <CustomSheetFooter onCancel={() => onCancel()} /> + {isCreate && <CustomSheetFooter onCancel={() => onCancel()} />} </div> )} </form> diff --git a/frontend/src/lib/components/shared/Card.tsx b/frontend/src/lib/components/shared/Card.tsx index 99b93db..5deb0fd 100644 --- a/frontend/src/lib/components/shared/Card.tsx +++ b/frontend/src/lib/components/shared/Card.tsx @@ -12,6 +12,7 @@ interface CardComponentProps { bodyContent: string | ReactNode | JSX.Element; footerContent: string | ReactNode | JSX.Element; className?: string; + onCardClick?: () => void; } export const AppCard = ({ @@ -19,9 +20,15 @@ export const AppCard = ({ bodyContent, footerContent, className, + onCardClick, }: CardComponentProps) => { return ( - <Card className={cn("overflow-hidden", className)}> + <Card + className={cn("overflow-hidden", className)} + onClick={() => { + onCardClick && onCardClick(); + }} + > {headerContent && ( <CardHeader className="p-0">{headerContent}</CardHeader> )} diff --git a/frontend/src/lib/components/shared/SideBar.tsx b/frontend/src/lib/components/shared/SideBar.tsx index 4e4c457..982396c 100644 --- a/frontend/src/lib/components/shared/SideBar.tsx +++ b/frontend/src/lib/components/shared/SideBar.tsx @@ -8,11 +8,12 @@ import { APP_URL } from "@/lib/constants/configs"; import Icon, { IconNames } from "./Icon"; import { Button } from "../ui/button"; import { Avatar } from "@/lib/components/shared/Avatar"; +import { Roles } from "@/lib/enums/Roles"; -export const taNavigationItems = [ - { name: "Profiles", href: "/profiles" }, - { name: "Jobs", href: "/jds" }, - { name: "Interviews", href: "/interviews" }, +export const taNavigationItems: SideBarItemProps[] = [ + { name: "profile", href: "/profiles" }, + { name: "job", href: "/jds" }, + { name: "interview", href: "/interviews" }, ]; interface SideBarItemProps { @@ -20,14 +21,10 @@ interface SideBarItemProps { href: string; } -export const sideBarItems: SideBarItemProps[] = [ - { name: "profile", href: "/profiles" }, - { name: "job", href: "/jds" }, +export const others: SideBarItemProps[] = [ { name: "interview", href: "/interviews" }, ]; -export const others = [{ name: "Interviews", href: "/interviews" }]; - export const Sidebar = () => { const pathname = usePathname(); const router = useRouter(); @@ -41,14 +38,14 @@ export const Sidebar = () => { console.log(userDetails); - // const filteredNavItems = - // userDetails?.role === Roles.TA ? taNavigationItems : others; + const filteredNavItems = + userDetails?.role === Roles.TA ? taNavigationItems : others; return ( <div className="fixed inset-y-0 left-0 w-[60px] bg-white flex flex-col justify-between bg-primary-high-contrast m-2.5 rounded-[0.6rem]"> <nav className="gap-8 p-4 flex flex-col items-center"> <Icon name="clientSideBar" width={40} height={40} className="mb-2" /> - {sideBarItems.map((item) => ( + {filteredNavItems.map((item) => ( <Link key={item.name} href={item.href} diff --git a/frontend/src/lib/utils/contexts/JobDescriptionProvider.tsx b/frontend/src/lib/utils/contexts/JobDescriptionProvider.tsx new file mode 100644 index 0000000..817dda6 --- /dev/null +++ b/frontend/src/lib/utils/contexts/JobDescriptionProvider.tsx @@ -0,0 +1,56 @@ +"use client"; +import { JobDescription } from "@/lib/types/JobDescription"; +import { + createContext, + Dispatch, + PropsWithChildren, + SetStateAction, + useContext, + useState, +} from "react"; + +const JobDescriptionContext = createContext({} as JobDescriptionContextType); + +interface JobDescriptionContextType { + jobDescription: JobDescription | null; + setJobDescription: Dispatch<SetStateAction<JobDescription | null>>; + isOpen: boolean; + setIsOpen: Dispatch<SetStateAction<boolean>>; + isCreate: boolean; + setIsCreate: Dispatch<SetStateAction<boolean>>; +} + +type JobDescriptionProviderProps = PropsWithChildren; + +export const JobDescriptionProvider: React.FC<JobDescriptionProviderProps> = ({ + children, +}) => { + const [jobDescription, setJobDescription] = useState<JobDescription | null>( + null, + ); + const [isOpen, setIsOpen] = useState(false); + const [isCreate, setIsCreate] = useState(true); + + return ( + <JobDescriptionContext.Provider + value={{ + jobDescription, + setJobDescription, + isOpen, + setIsOpen, + setIsCreate, + isCreate, + }} + > + {children} + </JobDescriptionContext.Provider> + ); +}; + +export const useJD = (): JobDescriptionContextType => { + const context = useContext(JobDescriptionContext); + if (!context) { + throw new Error("useJD must be used within a JobDescriptionProvider"); + } + return context; +}; diff --git a/frontend/src/lib/utils/contexts/ProfileViewProvider.tsx b/frontend/src/lib/utils/contexts/ProfileViewProvider.tsx new file mode 100644 index 0000000..4450651 --- /dev/null +++ b/frontend/src/lib/utils/contexts/ProfileViewProvider.tsx @@ -0,0 +1,54 @@ +"use client"; +import { Profile } from "@/lib/types/Profile"; +import { + createContext, + Dispatch, + PropsWithChildren, + SetStateAction, + useContext, + useState, +} from "react"; + +const ProfileViewContext = createContext({} as ProfileViewContextType); + +interface ProfileViewContextType { + profile: Profile | null; + setProfile: Dispatch<SetStateAction<Profile | null>>; + isOpen: boolean; + setIsOpen: Dispatch<SetStateAction<boolean>>; + isCreate: boolean; + setIsCreate: Dispatch<SetStateAction<boolean>>; +} + +type ProfileViewProviderProps = PropsWithChildren; + +export const ProfileViewProvider: React.FC<ProfileViewProviderProps> = ({ + children, +}) => { + const [profile, setProfile] = useState<Profile | null>(null); + const [isOpen, setIsOpen] = useState(false); + const [isCreate, setIsCreate] = useState(true); + + return ( + <ProfileViewContext.Provider + value={{ + profile, + setProfile, + isOpen, + setIsOpen, + setIsCreate, + isCreate, + }} + > + {children} + </ProfileViewContext.Provider> + ); +}; + +export const useProfileView = (): ProfileViewContextType => { + const context = useContext(ProfileViewContext); + if (!context) { + throw new Error("useProfileView must be used within a ProfileViewProvider"); + } + return context; +}; -- GitLab