From 8427dc4f13f7a4ef9d03f985ecddb967d9d1bc2f Mon Sep 17 00:00:00 2001 From: Eirik Dahlen Date: Mon, 18 Nov 2024 21:23:41 +0100 Subject: [PATCH] IS-2795: Add endpoint and modal for search --- src/api/types/personoversiktTypes.ts | 1 + src/api/types/sokDTO.ts | 4 + src/components/NewOversiktTable.tsx | 14 +- src/components/sokperson/SokPerson.tsx | 139 +++++++++++++++++ .../sokperson/SokPersonResultat.tsx | 76 +++++++++ src/components/toolbar/ToolbarWrapper.tsx | 18 ++- src/data/personoversiktHooks.ts | 20 ++- src/mocks/data/personoversiktEnhetMock.ts | 28 ++++ src/mocks/handlers.ts | 6 +- .../personoversikt/mockPersonoversikt.ts | 16 ++ src/utils/dateUtils.ts | 23 +++ src/utils/hendelseColumnUtils.ts | 9 ++ src/utils/stringUtil.ts | 8 + test/components/SokPersonTest.tsx | 147 ++++++++++++++++++ 14 files changed, 489 insertions(+), 20 deletions(-) create mode 100644 src/api/types/sokDTO.ts create mode 100644 src/components/sokperson/SokPerson.tsx create mode 100644 src/components/sokperson/SokPersonResultat.tsx create mode 100644 test/components/SokPersonTest.tsx diff --git a/src/api/types/personoversiktTypes.ts b/src/api/types/personoversiktTypes.ts index 26cfa171..bbdbb9cd 100644 --- a/src/api/types/personoversiktTypes.ts +++ b/src/api/types/personoversiktTypes.ts @@ -42,6 +42,7 @@ export interface PersonOversiktStatusDTO extends PersonOversiktUbehandletStatusDTO { fnr: string; navn: string; + fodselsdato: Date; enhet: string; veilederIdent: string | null; motestatus: MoteStatusType | undefined; diff --git a/src/api/types/sokDTO.ts b/src/api/types/sokDTO.ts new file mode 100644 index 00000000..e14faf2a --- /dev/null +++ b/src/api/types/sokDTO.ts @@ -0,0 +1,4 @@ +export interface SokDTO { + initials: string; + birthdate: Date; +} diff --git a/src/components/NewOversiktTable.tsx b/src/components/NewOversiktTable.tsx index 5b35e9a6..44249c93 100644 --- a/src/components/NewOversiktTable.tsx +++ b/src/components/NewOversiktTable.tsx @@ -3,25 +3,19 @@ import { Checkbox, Table } from '@navikt/ds-react'; import { VeilederColumn } from '@/components/VeilederColumn'; import { PersonData } from '@/api/types/personregisterTypes'; import { PersonRadVirksomhetColumn } from '@/components/PersonRadVirksomhetColumn'; -import { OppfolgingstilfelleDTO } from '@/api/types/personoversiktTypes'; import { FristDataCell } from '@/components/FristDataCell'; import { Sorting, SortingKey, useSorting } from '@/hooks/useSorting'; import { LinkSyfomodiaperson } from '@/components/LinkSyfomodiaperson'; import { toLastnameFirstnameFormat } from '@/utils/stringUtil'; -import { getHendelser } from '@/utils/hendelseColumnUtils'; +import { + getHendelser, + getVarighetOppfolgingstilfelle, +} from '@/utils/hendelseColumnUtils'; import { useTabType } from '@/context/tab/TabTypeContext'; import { OverviewTabType } from '@/konstanter'; import * as Amplitude from '@/utils/amplitude'; import { EventType } from '@/utils/amplitude'; -function getVarighetOppfolgingstilfelle( - oppfolgingstilfelle: OppfolgingstilfelleDTO | undefined -): string { - return oppfolgingstilfelle - ? `${oppfolgingstilfelle.varighetUker} uker` - : 'Ukjent'; -} - interface Props { personListe: [string, PersonData][]; selectedRows: string[]; diff --git a/src/components/sokperson/SokPerson.tsx b/src/components/sokperson/SokPerson.tsx new file mode 100644 index 00000000..48c7a91f --- /dev/null +++ b/src/components/sokperson/SokPerson.tsx @@ -0,0 +1,139 @@ +import React, { useState } from 'react'; +import { + Alert, + BodyShort, + Box, + Button, + Heading, + HStack, + Modal, + TextField, + VStack, +} from '@navikt/ds-react'; +import { useSokPerson } from '@/data/personoversiktHooks'; +import { SokDTO } from '@/api/types/sokDTO'; +import SokPersonResultat from '@/components/sokperson/SokPersonResultat'; +import { MagnifyingGlassIcon } from '@navikt/aksel-icons'; +import { isNumeric, removePunctuation } from '@/utils/stringUtil'; +import { parseDateString } from '@/utils/dateUtils'; + +const texts = { + buttonText: 'Søk etter sykmeldt', + header: 'Søk etter sykmeldt', + info: + 'Her kan du søke opp sykmeldte personer basert på initialer og fødselsdato.', + validation: { + initials: 'Vennligst angi gyldige initialer', + birthdate: 'Vennligst angi en gyldig fødselsdato', + }, + error: 'Noe gikk galt under søket. Vennligst prøv igjen.', +}; + +export default function SokPerson() { + const [isModalOpen, setIsModalOpen] = useState(false); + const [nameInitials, setNameInitials] = useState(''); + const [birthdate, setBirthdate] = useState(''); + const { + mutate, + data: searchResults, + isLoading, + isError, + isSuccess, + } = useSokPerson(); + const [isFormError, setIsFormError] = useState(false); + + const parseBirthdate = (birthdate: string): Date | null => { + const cleanedDateStr = removePunctuation(birthdate); + + if (cleanedDateStr.length < 6 || !isNumeric(cleanedDateStr)) { + return null; + } else { + return parseDateString(cleanedDateStr); + } + }; + + const validInitials = (initials: string): boolean => { + return initials.length <= 3 && initials.length > 1; + }; + + const handleSubmit = () => { + const parsedBirthdate = parseBirthdate(birthdate); + if (validInitials(nameInitials) && !!parsedBirthdate) { + const requestDTO: SokDTO = { + initials: nameInitials.toLowerCase(), + birthdate: parsedBirthdate, + }; + mutate(requestDTO); + } else { + setIsFormError(true); + } + }; + + return ( + + + setIsModalOpen(false)} + > + + + {texts.header} + + + + + {texts.info} + + setNameInitials(e.target.value)} + error={ + isFormError && !validInitials(nameInitials) + ? texts.validation.initials + : undefined + } + /> + setBirthdate(e.target.value)} + error={ + isFormError && parseBirthdate(birthdate) === null + ? texts.validation.birthdate + : undefined + } + /> + + + {searchResults && isSuccess && ( + + )} + {isError && ( + + {texts.error} + + )} + + + + + ); +} diff --git a/src/components/sokperson/SokPersonResultat.tsx b/src/components/sokperson/SokPersonResultat.tsx new file mode 100644 index 00000000..8fcb380c --- /dev/null +++ b/src/components/sokperson/SokPersonResultat.tsx @@ -0,0 +1,76 @@ +import React, { ReactElement } from 'react'; +import { useSorting } from '@/hooks/useSorting'; +import { PersonOversiktStatusDTO } from '@/api/types/personoversiktTypes'; +import { BodyShort, Box, Table } from '@navikt/ds-react'; +import { LinkSyfomodiaperson } from '@/components/LinkSyfomodiaperson'; +import { toLastnameFirstnameFormat } from '@/utils/stringUtil'; +import { toPersonData } from '@/utils/toPersondata'; + +const texts = { + noResults: { + first: 'Fant ingen sykmeldte personer for søkeparameterne.', + second: + 'Det kan hende personen ikke er sykmeldt eller at du ikke har tilgang å se personen.', + }, +}; + +interface Props { + sokeresultater: PersonOversiktStatusDTO[]; +} + +export default function SokPersonResultat({ + sokeresultater, +}: Props): ReactElement { + const { columns: allColumns } = useSorting(); + const columns = allColumns.filter( + (column) => column.sortKey === 'NAME' || column.sortKey === 'FNR' + ); + + const personer = Object.entries(toPersonData(sokeresultater, [])); + + return personer.length === 0 ? ( + + {texts.noResults.first} + {texts.noResults.second} + + ) : ( + + + + {columns.map((col, index) => ( + + {col.sortingText} + + ))} + + + + + {personer.map(([fnr, persondata], index) => ( + + + {persondata.navn.length > 0 && ( + + )} + + + {persondata.navn.length > 0 ? ( + fnr + ) : ( + + )} + + + ))} + +
+ ); +} diff --git a/src/components/toolbar/ToolbarWrapper.tsx b/src/components/toolbar/ToolbarWrapper.tsx index e6d9819a..dbb7304e 100644 --- a/src/components/toolbar/ToolbarWrapper.tsx +++ b/src/components/toolbar/ToolbarWrapper.tsx @@ -2,6 +2,7 @@ import React, { ReactElement, useState } from 'react'; import Toolbar from './Toolbar'; import { Label } from '@navikt/ds-react'; import { PAGINATED_NUMBER_OF_ITEMS } from '@/components/toolbar/PaginationContainer'; +import SokPerson from '@/components/sokperson/SokPerson'; export interface ToolbarWrapperProps { alleMarkert: boolean; @@ -38,15 +39,18 @@ const ToolbarWrapper = (props: ToolbarWrapperProps): ReactElement => { return ( <> -
- - {props.markertePersoner.length > 0 && ( +
+
- )} + {props.markertePersoner.length > 0 && ( + + )} +
+
diff --git a/src/data/personoversiktHooks.ts b/src/data/personoversiktHooks.ts index a86740c1..e1900da2 100644 --- a/src/data/personoversiktHooks.ts +++ b/src/data/personoversiktHooks.ts @@ -1,9 +1,9 @@ -import { useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import { PersonOversiktStatusDTO, PersonOversiktUbehandletStatusDTO, } from '@/api/types/personoversiktTypes'; -import { get } from '@/api/axios'; +import { get, post } from '@/api/axios'; import { useAktivEnhet } from '@/context/aktivEnhet/AktivEnhetContext'; import { useNotifications } from '@/context/notification/NotificationContext'; import { FetchPersonoversiktFailed } from '@/context/notification/Notifications'; @@ -12,6 +12,7 @@ import { useAsyncError } from '@/data/useAsyncError'; import { minutesToMillis } from '@/utils/timeUtils'; import { useMemo } from 'react'; import { PERSONOVERSIKT_ROOT } from '@/apiConstants'; +import { SokDTO } from '@/api/types/sokDTO'; const isUbehandlet = (ubehandletStatus: PersonOversiktUbehandletStatusDTO) => { return Object.values(ubehandletStatus).some((value) => value); @@ -88,3 +89,18 @@ export const usePersonoversiktQuery = () => { ), }; }; + +export const useSokPerson = () => { + const path = `${PERSONOVERSIKT_ROOT}/search`; + const postSok = (sokDTO: SokDTO) => + post(path, sokDTO); + + const mutation = useMutation({ + mutationFn: postSok, + }); + + return { + ...mutation, + data: mutation.data || [], + }; +}; diff --git a/src/mocks/data/personoversiktEnhetMock.ts b/src/mocks/data/personoversiktEnhetMock.ts index 77cd067a..0c676ed0 100644 --- a/src/mocks/data/personoversiktEnhetMock.ts +++ b/src/mocks/data/personoversiktEnhetMock.ts @@ -30,6 +30,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '01999911111', navn: 'Korrupt Heis', + fodselsdato: new Date('1990-10-10'), enhet: '0316', veilederIdent: null, oppfolgingsplanLPSBistandUbehandlet: true, @@ -46,6 +47,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999922222', navn: 'Korrupt Bordsen', + fodselsdato: new Date('1990-10-10'), enhet: '0316', veilederIdent: null, motebehovUbehandlet: true, @@ -66,6 +68,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999922220', navn: 'Ola Forhåndsvarselsen', + fodselsdato: new Date('1990-10-10'), enhet: '0316', veilederIdent: null, motebehovUbehandlet: true, @@ -87,6 +90,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999921210', navn: 'Per Arbeidsuforvarselsen', + fodselsdato: new Date('1990-10-10'), enhet: '0316', veilederIdent: null, oppfolgingsplanLPSBistandUbehandlet: null, @@ -102,6 +106,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999911120', navn: 'Hans Huskelappen', + fodselsdato: new Date('1990-10-10'), enhet: '0316', veilederIdent: null, motebehovUbehandlet: true, @@ -112,6 +117,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999911125', navn: 'Frist Fristersen', + fodselsdato: new Date('1990-10-10'), enhet: '0316', veilederIdent: null, motebehovUbehandlet: true, @@ -132,6 +138,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '18049911120', navn: 'Bent Behandlerbistandsen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: null, motebehovUbehandlet: true, @@ -143,6 +150,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '59999933333', navn: '', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z101010', motebehovUbehandlet: true, @@ -185,6 +193,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999944444', navn: 'Stol Bordsen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', motebehovUbehandlet: true, @@ -223,6 +232,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '18999955555', navn: 'Bord Stolesen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z999999', motebehovUbehandlet: true, @@ -258,6 +268,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966666', navn: 'Gulv Heisen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'M987654', motestatus: MoteStatusType.NYTT_TID_STED, @@ -287,6 +298,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999955556', navn: 'Skjerm Visen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: null, motebehovUbehandlet: true, @@ -313,6 +325,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966667', navn: 'Stol Sengestad', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'M987654', dialogmotekandidat: true, @@ -334,6 +347,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966668', navn: 'Bord Plantesen', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'M987654', dialogmotekandidat: true, @@ -364,6 +378,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966669', navn: 'Lun Gange', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Wienerbrød', oppfolgingsplanLPSBistandUbehandlet: true, @@ -389,6 +404,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966670', navn: 'Vissen Plass', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Wienerbrød', motestatus: undefined, @@ -409,6 +425,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966671', navn: 'Mør Benk', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z999991', oppfolgingsplanLPSBistandUbehandlet: true, @@ -434,6 +451,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966672', navn: 'Grønn Due', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z999991', oppfolgingsplanLPSBistandUbehandlet: true, @@ -445,6 +463,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966672', navn: 'Kandidat Arbeidsuforheten Uten Varslesen', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z999991', oppfolgingsplanLPSBistandUbehandlet: null, @@ -459,6 +478,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966673', navn: 'Kandidat Endringsen', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: MoteStatusType.NYTT_TID_STED, @@ -479,6 +499,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966674', navn: 'Kandidat Innkaltsen', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: MoteStatusType.INNKALT, @@ -503,6 +524,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966675', navn: 'Kandidat Avlystsen', + fodselsdato: new Date('1990-01-01'), enhet: '0316', veilederIdent: 'Z101010', dialogmotekandidat: true, @@ -533,6 +555,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966676', navn: 'Kandidat Kandidatsen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', dialogmotekandidat: true, @@ -571,6 +594,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966677', navn: 'Ikke Viseson', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: MoteStatusType.FERDIGSTILT, @@ -591,6 +615,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966678', navn: 'Ikke Visesen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: undefined, @@ -611,6 +636,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99999966678', navn: 'Ikke Viseby', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: undefined, @@ -631,6 +657,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99998966679', navn: 'Frisk T. Arbeidsformidlesen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: undefined, @@ -647,6 +674,7 @@ export const personoversiktEnhetMock: PersonOversiktStatusDTO[] = [ ...behandletPerson, fnr: '99918965679', navn: 'Manglende Medvirksen', + fodselsdato: new Date('2000-01-01'), enhet: '0316', veilederIdent: 'Z101010', motestatus: undefined, diff --git a/src/mocks/handlers.ts b/src/mocks/handlers.ts index d5cef4da..960f5078 100644 --- a/src/mocks/handlers.ts +++ b/src/mocks/handlers.ts @@ -4,7 +4,10 @@ import { mockUnleash } from '@/mocks/mockUnleash'; import { mockSyfoveileder } from '@/mocks/syfoveileder/mockSyfoveileder'; import { mockSyfoperson } from '@/mocks/syfoperson/mockSyfoperson'; import { mockPersontildeling } from '@/mocks/persontildeling/mockPersontildeling'; -import { mockPersonoversikt } from '@/mocks/personoversikt/mockPersonoversikt'; +import { + mockPersonoversikt, + mockSokPerson, +} from '@/mocks/personoversikt/mockPersonoversikt'; import { mockModiacontextholder } from '@/mocks/modiacontextholder/mockModiacontextholder'; import { mockFlexjar } from '@/mocks/flexjar/mockFlexjar'; import { mockEreg } from '@/mocks/ereg/mockEreg'; @@ -22,6 +25,7 @@ const handlers: HttpHandler[] = [ mockSyfoperson(generatedPersons), mockPersontildeling, mockPersonoversikt(generatedPersons), + mockSokPerson(), ...mockModiacontextholder, ]; diff --git a/src/mocks/personoversikt/mockPersonoversikt.ts b/src/mocks/personoversikt/mockPersonoversikt.ts index f47988b5..9de0f2ec 100644 --- a/src/mocks/personoversikt/mockPersonoversikt.ts +++ b/src/mocks/personoversikt/mockPersonoversikt.ts @@ -5,6 +5,7 @@ import { MockPerson, } from '../mockUtils'; import { http, HttpResponse } from 'msw'; +import { SokDTO } from '@/api/types/sokDTO'; const personoversiktEnhet = (generatedPersons: MockPerson[]) => [ ...personoversiktEnhetMock, @@ -15,3 +16,18 @@ export const mockPersonoversikt = (generatedPersons: MockPerson[]) => http.get(`${PERSONOVERSIKT_ROOT}/enhet/:id`, () => HttpResponse.json(personoversiktEnhet(generatedPersons)) ); + +export function mockSokPerson() { + return http.post(`${PERSONOVERSIKT_ROOT}/search`, async ({ request }) => { + const requestBody = (await request.json()) as SokDTO; + // Lokalt viser vi resultater på likhet ved første forbokstav ELLER dato, for enkelhetens skyld + const results = personoversiktEnhetMock.filter( + (person) => + person.navn.toLowerCase().substring(0, 1) === + requestBody.initials.toLowerCase().substring(0, 1) || + person.fodselsdato.getTime() === + new Date(requestBody.birthdate).getTime() + ); + return HttpResponse.json(results); + }); +} diff --git a/src/utils/dateUtils.ts b/src/utils/dateUtils.ts index 6d223fb9..024dff15 100644 --- a/src/utils/dateUtils.ts +++ b/src/utils/dateUtils.ts @@ -64,3 +64,26 @@ export const getWeeksBetween = (date1: Date, date2: Date): number => { export const addWeeks = (date: Date, numberOfWeeks: number): Date => { return dayjs(date).add(numberOfWeeks, 'weeks').toDate(); }; + +export function parseDateString(dateString: string): Date | null { + const day = dateString.slice(0, 2); + const month = dateString.slice(2, 4); + let year = dateString.slice(4); + const today = new Date(); + + if (year.length === 2) { + const todayYear = today.getFullYear().toString().substring(2, 4); + year = + parseInt(year, 10) < parseInt(todayYear, 10) ? `20${year}` : `19${year}`; + } + + const date = new Date(`${year}-${month}-${day}`); + if ( + date.getMonth() + 1 !== parseInt(month, 10) || + date.getDate() !== parseInt(day, 10) + ) { + return null; + } else { + return date; + } +} diff --git a/src/utils/hendelseColumnUtils.ts b/src/utils/hendelseColumnUtils.ts index 095a4931..8567f086 100644 --- a/src/utils/hendelseColumnUtils.ts +++ b/src/utils/hendelseColumnUtils.ts @@ -2,6 +2,7 @@ import { AktivitetskravStatus, OnskerOppfolging, Oppfolgingsgrunn, + OppfolgingstilfelleDTO, SenOppfolgingKandidatDTO, } from '@/api/types/personoversiktTypes'; import { PersonData } from '@/api/types/personregisterTypes'; @@ -156,3 +157,11 @@ export function getHendelser(personData: PersonData): string[] { return hendelser; } + +export function getVarighetOppfolgingstilfelle( + oppfolgingstilfelle: OppfolgingstilfelleDTO | undefined +): string { + return oppfolgingstilfelle + ? `${oppfolgingstilfelle.varighetUker} uker` + : 'Ukjent'; +} diff --git a/src/utils/stringUtil.ts b/src/utils/stringUtil.ts index 5aa3c5be..0b96c685 100644 --- a/src/utils/stringUtil.ts +++ b/src/utils/stringUtil.ts @@ -17,3 +17,11 @@ export const toLastnameFirstnameFormat = (navn: string): string => { return nameList.map(capitalizeHyphenatedWords).join(' '); }; + +export function isNumeric(str: string): boolean { + return /^\d+$/.test(str); +} + +export function removePunctuation(str: string): string { + return str.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, ''); +} diff --git a/test/components/SokPersonTest.tsx b/test/components/SokPersonTest.tsx new file mode 100644 index 00000000..45233988 --- /dev/null +++ b/test/components/SokPersonTest.tsx @@ -0,0 +1,147 @@ +import React from 'react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { NotificationProvider } from '@/context/notification/NotificationContext'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { AktivEnhetProvider } from '@/context/aktivEnhet/AktivEnhetContext'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { testQueryClient } from '../testQueryClient'; +import SokPerson from '@/components/sokperson/SokPerson'; +import userEvent from '@testing-library/user-event'; +import { SokDTO } from '@/api/types/sokDTO'; +import { parseDateString } from '@/utils/dateUtils'; +import { mockServer } from '../setup'; +import { mockSokPerson } from '@/mocks/personoversikt/mockPersonoversikt'; + +let queryClient: QueryClient; + +const renderSokPerson = () => + render( + + + + + + + + ); + +describe('SokPerson', () => { + beforeEach(() => { + queryClient = testQueryClient(); + mockServer.use(mockSokPerson()); + }); + + it('should render SokPerson with fields', async () => { + renderSokPerson(); + + const modalButton = screen.getByRole('button', { + name: 'Søk etter sykmeldt', + }); + expect(modalButton).to.exist; + + await userEvent.click(modalButton); + + expect(screen.getByRole('dialog', { name: 'Søk etter sykmeldt' })).to.exist; + expect(screen.getByRole('heading', { name: 'Søk etter sykmeldt' })).to + .exist; + expect( + screen.getByText( + 'Her kan du søke opp sykmeldte personer basert på initialer og fødselsdato.' + ) + ).to.exist; + expect(screen.getByRole('textbox', { name: 'Initialer' })).to.exist; + expect(screen.getByRole('textbox', { name: 'Fødselsdato' })).to.exist; + expect(screen.getByRole('button', { name: 'Søk' })).to.exist; + }); + + it('should render validation errors for fields', async () => { + renderSokPerson(); + + await userEvent.click( + screen.getByRole('button', { + name: 'Søk etter sykmeldt', + }) + ); + + await userEvent.click(screen.getByRole('button', { name: 'Søk' })); + + expect(screen.getByText('Vennligst angi gyldige initialer')).to.exist; + expect(screen.getByText('Vennligst angi en gyldig fødselsdato')).to.exist; + }); + + it('should send correct parameters', async () => { + renderSokPerson(); + + await userEvent.click( + screen.getByRole('button', { + name: 'Søk etter sykmeldt', + }) + ); + + const initialsInput = screen.getByRole('textbox', { name: 'Initialer' }); + const birthdateInput = screen.getByRole('textbox', { name: 'Fødselsdato' }); + + const initialsValue = 'kk'; + const birthdateValue = '101010'; + + fireEvent.change(initialsInput, { + target: { value: initialsValue }, + }); + + fireEvent.change(birthdateInput, { + target: { value: birthdateValue }, + }); + + await userEvent.click(screen.getByRole('button', { name: 'Søk' })); + + await waitFor(() => { + const sokMutation = queryClient.getMutationCache().getAll()[0]; + const birthdate = parseDateString(birthdateValue); + if (birthdate) { + const expectedSokDTO: SokDTO = { + initials: initialsValue, + birthdate: birthdate, + }; + if (!sokMutation) { + throw new Error('Mutation not found'); + } + expect(sokMutation.state.variables).to.deep.equal(expectedSokDTO); + } else { + throw new Error('Invalid birthdate'); + } + }); + }); + + it('should show correct results', async () => { + renderSokPerson(); + + await userEvent.click( + screen.getByRole('button', { + name: 'Søk etter sykmeldt', + }) + ); + + const initialsInput = screen.getByRole('textbox', { name: 'Initialer' }); + const birthdateInput = screen.getByRole('textbox', { name: 'Fødselsdato' }); + + const initialsValue = 'kh'; + const birthdateValue = '101010'; + + fireEvent.change(initialsInput, { + target: { value: initialsValue }, + }); + + fireEvent.change(birthdateInput, { + target: { value: birthdateValue }, + }); + + await userEvent.click(screen.getByRole('button', { name: 'Søk' })); + + expect(await screen.findByText('Navn')).to.exist; + expect(await screen.findByText('Fødselsnummer')).to.exist; + expect(await screen.findByText('Heis, Korrupt')).to.exist; + expect(await screen.findByText('Bordsen, Korrupt')).to.exist; + expect(await screen.findByText('01999911111')).to.exist; + expect(await screen.findByText('99999922222')).to.exist; + }); +});