diff --git a/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentApplicantAdminPage.tsx b/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentApplicantAdminPage.tsx index 07b7abd8f..1585bb699 100644 --- a/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentApplicantAdminPage.tsx +++ b/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentApplicantAdminPage.tsx @@ -1,5 +1,5 @@ +import { useMutation, useQuery } from '@tanstack/react-query'; import classNames from 'classnames'; -import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate, useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; @@ -7,7 +7,7 @@ import { BackButton, Button, Link, SamfundetLogoSpinner } from '~/Components'; import { Table } from '~/Components/Table'; import { Text } from '~/Components/Text/Text'; import { getRecruitmentApplicationsForRecruiter, withdrawRecruitmentApplicationRecruiter } from '~/api'; -import type { RecruitmentApplicationDto, RecruitmentUserDto } from '~/dto'; +import type { InterviewDto } from '~/dto'; import { STATUS } from '~/http_status_codes'; import { KEY } from '~/i18n/constants'; import { reverse } from '~/named-urls'; @@ -15,50 +15,39 @@ import { ROUTES } from '~/routes'; import { dbT } from '~/utils'; import { AdminPage } from '../AdminPageLayout'; import styles from './RecruitmentApplicantAdminPage.module.scss'; +import { RecruitmentInterviewNotesForm } from './RecruitmentInterviewNotesForm'; export function RecruitmentApplicantAdminPage() { const { t } = useTranslation(); const navigate = useNavigate(); - const [recruitmentApplication, setRecruitmentApplication] = useState(); - const [otherRecruitmentApplication, setOtherRecruitmentApplication] = useState([]); - const [applicant, setApplicant] = useState(); - - const [loading, setLoading] = useState(true); - const { applicationID } = useParams(); + const { data, isLoading, error } = useQuery({ + queryKey: ['recruitmentapplicationpage', applicationID], + queryFn: () => getRecruitmentApplicationsForRecruiter(applicationID as string), + }); - useEffect(() => { - getRecruitmentApplicationsForRecruiter(applicationID as string) - .then((res) => { - setRecruitmentApplication(res.data.application); - setApplicant(res.data.user); - setOtherRecruitmentApplication(res.data.other_applications); - setLoading(false); - }) - .catch((data) => { - if (data.request.status === STATUS.HTTP_404_NOT_FOUND) { - navigate(ROUTES.frontend.not_found, { replace: true }); - } - toast.error(t(KEY.common_something_went_wrong)); - }); - }, [applicationID, t, navigate]); - - const adminWithdraw = () => { - if (recruitmentApplication) { - if (window.confirm(t(KEY.recruitment_confirm_withdraw_application))) { - withdrawRecruitmentApplicationRecruiter(recruitmentApplication.id) - .then((response) => { - setRecruitmentApplication(response.data); - toast.success(t(KEY.common_update_successful)); - }) - .catch(() => { - toast.error(t(KEY.common_something_went_wrong)); - }); - } + if (error) { + if (data?.request.status === STATUS.HTTP_404_NOT_FOUND) { + navigate(ROUTES.frontend.not_found, { replace: true }); } - }; + toast.error(t(KEY.common_something_went_wrong)); + } + + const recruitmentApplication = data?.data.application; + const applicant = data?.data.user; + const otherRecruitmentApplications = data?.data.other_applications; + const interviewNotes = recruitmentApplication?.interview?.notes; + + const adminWithdraw = useMutation({ + mutationFn: (id: string) => { + return withdrawRecruitmentApplicationRecruiter(id); + }, + onSuccess: () => { + toast.success(t(KEY.common_update_successful)); + }, + }); - if (loading) { + if (isLoading) { return (
@@ -66,6 +55,10 @@ export function RecruitmentApplicantAdminPage() { ); } + const initialData: Partial = { + notes: interviewNotes || '', + }; + return (
@@ -97,11 +90,22 @@ export function RecruitmentApplicantAdminPage() { {t(KEY.recruitment_withdrawn)} ) : ( - )}
+
+ +
+
{t(KEY.recruitment_all_applications)} @@ -114,57 +118,61 @@ export function RecruitmentApplicantAdminPage() { t(KEY.recruitment_recruiter_status), t(KEY.recruitment_interview_time), ]} - data={otherRecruitmentApplication.map((element) => { - return { - cells: [ - { - sortable: true, - content: ( - - {element.applicant_priority} - - ), - }, - { - content: ( - - {dbT(element.recruitment_position, 'name')} - - ), - }, - { - content: ( - - {dbT(element.recruitment_position.gang, 'name')} - - ), - }, - element.recruiter_priority ? element.recruiter_priority : t(KEY.common_not_set), - element.interview_time ? element.interview_time : t(KEY.common_not_set), - ], - }; - })} + data={ + otherRecruitmentApplications + ? otherRecruitmentApplications.map((element) => { + return { + cells: [ + { + sortable: true, + content: ( + + {element.applicant_priority} + + ), + }, + { + content: ( + + {dbT(element.recruitment_position, 'name')} + + ), + }, + { + content: ( + + {dbT(element.recruitment_position.gang, 'name')} + + ), + }, + element.recruiter_priority ? element.recruiter_priority : t(KEY.common_not_set), + element.interview_time ? element.interview_time : t(KEY.common_not_set), + ], + }; + }) + : [] + } />
diff --git a/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentInterviewNotesForm.tsx b/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentInterviewNotesForm.tsx new file mode 100644 index 000000000..39b9de9d4 --- /dev/null +++ b/frontend/src/PagesAdmin/RecruitmentApplicantAdminPage/RecruitmentInterviewNotesForm.tsx @@ -0,0 +1,58 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { z } from 'zod'; +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, Textarea } from '~/Components'; +import { KEY } from '~/i18n/constants'; + +const recruitmentNotesSchema = z.object({ + notes: z.string(), +}); + +type RecruitmentInterviewNotesFormType = z.infer; + +interface RecruitmentInterviewNotesFormProps { + initialData: Partial; +} + +export function RecruitmentInterviewNotesForm({ initialData }: RecruitmentInterviewNotesFormProps) { + const { t } = useTranslation(); + + const form = useForm({ + resolver: zodResolver(recruitmentNotesSchema), + defaultValues: initialData, + }); + + function handleUpdateNotes(value: string) { + // TODO: Update notes using a put request + console.log(value); + } + + return ( +
+ +
+ ( + + {t(KEY.recruitment_interview_notes)} + +