'use client' import React, { useMemo, useState } from 'react' import { Controller, useForm } from 'react-hook-form' import { Box, Button, Checkbox, SimpleGrid, Stack, Text } from '@pikku/mantine/core' import type { DB } from '@heygermany/sdk' import { ApplicationCandidateData, CandidateDocumentTypes, LanguageCodes, ProfessionalRecognitionStatuses, } from '@heygermany/sdk' import { useI18n } from '@/context/i18n-provider' import { pikku } from '@/pikku/http' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { EnumSelect } from '@/components/common/EnumSelect' import { FileUpload } from '@/components/ui/FileUpload' import { useUploadCandidateFiles } from '@/hooks/useUploadCandidateFiles' import { useParams, useSearchParams } from '@/framework/navigation' import { CountrySearch } from '../form/CountrySearch' interface ApplicantProfileForm { nationality: string currentResidence: string professionalRecognitionStatus: DB.ProfessionalRecognitionStatus | null qualificationStatusGermany: DB.NurseRecognitionGermany | null recognitionLikelihood: DB.RecognitionLikelihood | null languagesSpoken: string[] } export const ApplicantProfile: React.FunctionComponent = () => { const params = useParams() const searchParams = useSearchParams() const candidateIdFromUrl = params.candidateId as string | undefined const candidateIdFromQuery = searchParams.get('candidateId') const candidateId = candidateIdFromUrl || candidateIdFromQuery || undefined // Fetch existing candidate data const { data: candidate } = useQuery({ queryKey: ['candidate', candidateId], queryFn: async () => { if (candidateId) { return await pikku().get('/candidate/:candidateId', { candidateId }) } return await pikku().get('/candidate') }, }) if (!candidate) { return null } return } const ApplicantProfileInner: React.FunctionComponent<{ candidate: ApplicationCandidateData }> = ({ candidate }) => { const t = useI18n() const queryClient = useQueryClient() const [isSaving, setIsSaving] = useState(false) // Update mutation const updateMutation = useMutation({ mutationFn: async (data: ApplicantProfileForm) => { if (!candidate?.candidateId) { throw new Error('Candidate ID not found') } setIsSaving(true) // Create a minimum delay promise (2 seconds) const minDelay = new Promise(resolve => setTimeout(resolve, 2000)) // Update candidate profile const updatePromise = pikku().patch(`/candidate/:candidateId`, { candidateId: candidate.candidateId, ...data, languagesSpoken: data.languagesSpoken as DB.LanguageCode[], }) // Wait for both the update and minimum delay await Promise.all([updatePromise, minDelay]) }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['candidate'] }) setIsSaving(false) // Show success notification or redirect }, onError: () => { setIsSaving(false) }, }) const { control, handleSubmit, trigger, formState: { errors } } = useForm({ defaultValues: { nationality: candidate.nationality || '', currentResidence: candidate.currentResidence || '', professionalRecognitionStatus: candidate.professionalRecognitionStatus || null, qualificationStatusGermany: candidate.qualificationStatusGermany || null, recognitionLikelihood: candidate.recognitionLikelihood || null, languagesSpoken: candidate.languagesSpoken || [], }, }) // File upload for CV (using WORK_EXPERIENCE document type) const { uploadFiles, deleteFile } = useUploadCandidateFiles( candidate.candidateId, CandidateDocumentTypes.WORK_EXPERIENCE, trigger ) // Available languages (sorted alphabetically, English first) const selectEnums = t.getEnumOptions(LanguageCodes, 'languagecode') const availableLanguages = useMemo(() => { // English first, then sort rest alphabetically by label const english = selectEnums.find(l => l.value === 'en')! const others = selectEnums.filter(l => l.value !== 'en').sort((a, b) => a.label.localeCompare(b.label)) return [english, ...others] }, [t, selectEnums]) return ( <> {t('jobs.profile.description')}
updateMutation.mutate(data))}> {/* Nationality */} ( )} /> {/* Current Residence */} ( )} /> {/* Professional Recognition Status */} ( )} /> {/* Languages Spoken */} {t('jobs.profile.languages.label')} ( {availableLanguages.map((lang) => ( ))} )} /> {/* CV Upload */} {t('jobs.profile.cv.label')} {t('jobs.profile.cv.description')} ({ id: file.documentId, fileName: file.fileName })) || []} uploadFiles={uploadFiles} deleteFile={deleteFile} /> {/* Submit Button */}
) } export default ApplicantProfile