'use client'; import { Container, Title, Text, TextInput, ActionIcon, Group, Button, Badge, Select } from '@pikku/mantine/core'; import { DataTable, type DataTableSortStatus } from 'mantine-datatable'; import { useDebouncedValue } from '@mantine/hooks'; import { IconSearch, IconX } from '@tabler/icons-react'; import sortBy from 'lodash/sortBy'; import dayjs from 'dayjs'; import { useGetBackOfficeCandidates } from '@/hooks/backoffice/useGetBackOfficeCandidates'; import { useI18n } from '@/context/i18n-provider'; import { useEffect, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { pikku } from '@/pikku/http'; import { CountriesMap } from '@heygermany/sdk'; import { CountrySearch } from '@/components/jobs/form/CountrySearch'; import { LanguageLevelSelectComponent, NurseRecognitionGermanySelectComponent, ApplicantStatusSelectComponent } from '@/components/backoffice/DocumentFieldFactory'; export default function BackOfficeCandidates() { const { isLoading, data: candidates } = useGetBackOfficeCandidates() const t = useI18n(); const notAvailable = t('common.na'); // Fetch countries map const { data: countriesMap = {} } = useQuery({ queryKey: ['countries', t.locale], queryFn: async (): Promise => { return await pikku().get('/countries', { locale: t.locale }) }, staleTime: 60 * 60 * 1000, // 1 hour }); // Filter states const [nameQuery, setNameQuery] = useState(''); const [debouncedNameQuery] = useDebouncedValue(nameQuery, 200); const [countryFilter, setCountryFilter] = useState(''); const [germanLevelFilter, setGermanLevelFilter] = useState(null); const [recognitionStatusFilter, setRecognitionStatusFilter] = useState(null); const [statusFilter, setStatusFilter] = useState(null); const [reuploadedAfterInvalidFilter, setReuploadedAfterInvalidFilter] = useState(null); // Sort state const [sortStatus, setSortStatus] = useState>({ columnAccessor: 'createdAt', direction: 'desc', }); // Records state const [records, setRecords] = useState([]); const hasReuploadedAfterInvalid = (candidate: any) => { if (!candidate.reuploadedAt || !candidate.invalidatedAt) { return false; } return new Date(candidate.reuploadedAt).getTime() > new Date(candidate.invalidatedAt).getTime(); }; // Apply filters useEffect(() => { if (!candidates?.data) { setRecords([]); return; } const filtered = candidates.data.filter((candidate: any) => { // Name filter if (debouncedNameQuery !== '' && !candidate.name?.toLowerCase().includes(debouncedNameQuery.trim().toLowerCase())) { return false; } // Country filter if (countryFilter && candidate.countryEducation !== countryFilter) { return false; } // German level filter if (germanLevelFilter && candidate.languageSelfAssessmentLevel !== germanLevelFilter) { return false; } // Recognition status filter if (recognitionStatusFilter && candidate.qualificationStatusGermany !== recognitionStatusFilter) { return false; } // Status filter if (statusFilter && candidate.status !== statusFilter) { return false; } if (reuploadedAfterInvalidFilter === 'yes' && !hasReuploadedAfterInvalid(candidate)) { return false; } if (reuploadedAfterInvalidFilter === 'no' && hasReuploadedAfterInvalid(candidate)) { return false; } return true; }); setRecords(filtered); }, [candidates?.data, debouncedNameQuery, countryFilter, germanLevelFilter, recognitionStatusFilter, statusFilter, reuploadedAfterInvalidFilter]); // Apply sorting useEffect(() => { if (records.length === 0) return; let sortedData = [...records]; if (sortStatus.columnAccessor === 'createdAt') { sortedData = sortBy(sortedData, (item) => item.createdAt ? new Date(item.createdAt).getTime() : 0); } else if (sortStatus.columnAccessor === 'fullName') { sortedData = sortBy(sortedData, (item) => item.name || ''); } else if (sortStatus.columnAccessor === 'countryEducation') { sortedData = sortBy(sortedData, (item) => item.countryEducation || ''); } else if (sortStatus.columnAccessor === 'germanLevel') { sortedData = sortBy(sortedData, (item) => item.languageSelfAssessmentLevel || ''); } else if (sortStatus.columnAccessor === 'recognitionStatus') { sortedData = sortBy(sortedData, (item) => item.qualificationStatusGermany || ''); } else if (sortStatus.columnAccessor === 'status') { sortedData = sortBy(sortedData, (item) => item.status || ''); } setRecords(sortStatus.direction === 'desc' ? sortedData.reverse() : sortedData); }, [sortStatus]); const clearFilters = () => { setNameQuery(''); setCountryFilter(''); setGermanLevelFilter(null); setRecognitionStatusFilter(null); setStatusFilter(null); setReuploadedAfterInvalidFilter(null); }; const hasActiveFilters = nameQuery !== '' || countryFilter !== '' || germanLevelFilter !== null || recognitionStatusFilter !== null || statusFilter !== null || reuploadedAfterInvalidFilter !== null; return ( {t('backoffice.candidates.title')} {t('backoffice.candidates.description')} {hasActiveFilters ? t('backoffice.candidates.count.filtered', { filtered: records.length, total: candidates?.total || 0, }) : t('backoffice.candidates.count.total', { total: candidates?.total || 0, })} {hasActiveFilters && ( )} window.open(`/backoffice/candidate/${record.candidateId}`, '_blank', 'noopener,noreferrer') } columns={[ { accessor: 'fullName', title: t('backoffice.candidates.columns.fullname'), sortable: true, render: (candidate) => candidate.name, filter: ( } rightSection={ setNameQuery('')}> } value={nameQuery} onChange={(e) => setNameQuery(e.currentTarget.value)} /> ), filtering: nameQuery !== '', }, { accessor: 'countryEducation', title: t('backoffice.candidates.columns.countryofeducation'), sortable: true, render: (candidate) => candidate.countryEducation ? (countriesMap[candidate.countryEducation] || candidate.countryEducation) : notAvailable, filter: ( ), filtering: countryFilter !== '', }, { accessor: 'germanLevel', title: t('backoffice.candidates.columns.germanlevel'), sortable: true, render: (candidate) => candidate.languageSelfAssessmentLevel ? t(`enums.languagelevel.${candidate.languageSelfAssessmentLevel.toLowerCase()}` as any) : notAvailable, filter: ( ), filtering: germanLevelFilter !== null, }, { accessor: 'recognitionStatus', title: t('backoffice.candidates.columns.recognitionstatus'), sortable: true, render: (candidate) => candidate.qualificationStatusGermany ? t(`enums.nurserecognitiongermany.${candidate.qualificationStatusGermany.toLowerCase()}` as any) : notAvailable, filter: ( ), filtering: recognitionStatusFilter !== null, }, { accessor: 'createdAt', title: t('backoffice.candidates.columns.creationdate'), sortable: true, render: (candidate) => dayjs(candidate.createdAt).format('YYYY-MM-DD') }, { accessor: 'status', title: t('backoffice.candidates.columns.status'), sortable: true, render: (candidate) => candidate.status ? t(`enums.applicantstatus.${candidate.status.toLowerCase()}` as any) : notAvailable, filter: ( ), filtering: statusFilter !== null, }, { accessor: 'reuploadedAfterInvalid', title: t('backoffice.candidates.columns.reuploaded'), render: (candidate) => hasReuploadedAfterInvalid(candidate) ? {t('backoffice.candidates.reuploaded.badge')} : {t('common.no')}, filter: (