Skip to content

Commit

Permalink
Merge pull request #1191 from navikt/mote-varighet
Browse files Browse the repository at this point in the history
Mote varighet
  • Loading branch information
johatr authored Sep 14, 2023
2 parents 1312937 + d6f98a5 commit 1ca9b9a
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 21 deletions.
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.78",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^14.4.3",
"@types/moment-duration-format": "^2.2.3",
"@types/node": "^18.11.9",
"@types/react": "^17.0.45",
Expand Down
53 changes: 40 additions & 13 deletions src/moduler/aktivitet/aktivitet-forms/mote/MoteAktivitetForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AktivitetStatus, Kanal } from '../../../../datatypes/aktivitetTypes';
import { MoteAktivitet, VeilarbAktivitetType } from '../../../../datatypes/internAktivitetTypes';
import { coerceToUndefined } from '../../../../felles-komponenter/skjema/datovelger/common';
import ControlledDatePicker from '../../../../felles-komponenter/skjema/datovelger/ControlledDatePicker';
import { beregnFraTil, beregnKlokkeslettVarighet, formatterVarighet } from '../../aktivitet-util';
import { beregnFraTil, beregnKlokkeslettVarighet } from '../../aktivitet-util';
import AktivitetFormHeader from '../AktivitetFormHeader';
import CustomErrorSummary from '../CustomErrorSummary';
import { dateOrUndefined } from '../ijobb/AktivitetIjobbForm';
Expand All @@ -23,8 +23,7 @@ const schema = z.object({
invalid_type_error: 'Ikke en gyldig dato',
}),
klokkeslett: z.string().min(1, 'Du må fylle ut klokkeslett'),

varighet: z.string().min(1, 'Du må fylle ut varighet'),
varighet: z.number({ invalid_type_error: 'Du må velge varighet' }), // Blir NaN på default value
kanal: z.nativeEnum(Kanal, {
errorMap: (issue) => {
switch (issue.code) {
Expand Down Expand Up @@ -63,7 +62,7 @@ const MoteAktivitetForm = (props: Props) => {
tittel: aktivitet?.tittel,
klokkeslett: moteTid?.klokkeslett,
// Keep field as string since input natively returns string
varighet: formatterVarighet(moteTid?.varighet),
varighet: moteTid?.varighet,
kanal: aktivitet?.kanal,
adresse: aktivitet?.adresse,
beskrivelse: aktivitet?.beskrivelse,
Expand Down Expand Up @@ -91,6 +90,26 @@ const MoteAktivitetForm = (props: Props) => {
const beskrivelseValue = watch('beskrivelse'); // for <Textarea /> character-count to work
const forberedelserValue = watch('forberedelser'); // for <Textarea /> character-count to work

const varighet = [
{ minutter: 15, tekst: '15 minutter' },
{ minutter: 30, tekst: '30 minutter' },
{ minutter: 45, tekst: '45 minutter' },
{ minutter: 60, tekst: '1 time' },
{ minutter: 90, tekst: '1 time, 30 minutter' },
{ minutter: 120, tekst: '2 timer' },
{ minutter: 150, tekst: '2 timer, 30 minutter' },
{ minutter: 180, tekst: '3 timer' },
{ minutter: 210, tekst: '3 timer, 30 minutter' },
{ minutter: 240, tekst: '4 timer' },
{ minutter: 270, tekst: '4 timer, 30 minutter' },
{ minutter: 300, tekst: '5 timer' },
{ minutter: 330, tekst: '5 timer, 30 minutter' },
{ minutter: 360, tekst: '6 timer' },
{ minutter: 390, tekst: '6 timer, 30 minutter' },
{ minutter: 420, tekst: '7 timer' },
{ minutter: 450, tekst: '7 timer, 30 minutter' },
];

return (
<form
autoComplete="off"
Expand All @@ -102,7 +121,7 @@ const MoteAktivitetForm = (props: Props) => {
status: AktivitetStatus.PLANLAGT,
avtalt: false,
// dato: selectedDay!!.toString(),
})
}),
)}
>
<FormProvider {...formHandlers}>
Expand All @@ -124,18 +143,26 @@ const MoteAktivitetForm = (props: Props) => {
<TextField
label="Klokkeslett (obligatorisk)"
{...register('klokkeslett')}
type={'time' as any}
step="300"
type="time"
error={errors.klokkeslett && errors.klokkeslett.message}
/>
<TextField
<Select
label="Varighet (obligatorisk)"
{...register('varighet')}
type={'time' as any}
step="900"
{...register('varighet', { valueAsNumber: true })}
error={errors.varighet && errors.varighet.message}
/>
<Select label="Møteform (obligatorisk)" {...register('kanal')} error={errors.kanal && errors.kanal.message}>
>
<option value="">Velg varighet</option>
{varighet.map((item) => (
<option value={item.minutter} key={item.minutter}>
{item.tekst}
</option>
))}
</Select>
<Select
label="Møteform (obligatorisk)"
{...register('kanal')}
error={errors.kanal && errors.kanal.message}
>
<option value="">Velg møteform</option>
<option value={Kanal.OPPMOTE}>Oppmøte</option>
<option value={Kanal.TELEFON}>Telefonmøte</option>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { configureStore } from '@reduxjs/toolkit';
import { RenderResult, fireEvent, getByRole, render, screen } from '@testing-library/react';
import { RenderResult, fireEvent, render, screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { addDays, addMinutes, subYears } from 'date-fns';
import React from 'react';
import { Provider as ReduxProvider } from 'react-redux';

import { MOTE_TYPE } from '../../../../constant';
import reducer from '../../../../reducer';
import MoteAktivitetForm from './MoteAktivitetForm';
import { expect } from 'vitest';
import { Kanal } from '../../../../datatypes/aktivitetTypes';

const initialState: any = {
data: {
Expand All @@ -22,10 +25,32 @@ function mountWithIntl(node: any): RenderResult {
return render(<ReduxProvider store={store}>{node}</ReduxProvider>);
}

const fillForm = () => {
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Tema for møtet (obligatorisk)'), {
target: { value: 'Møte med NAV' },
});
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Dato (obligatorisk)'), {
target: { value: '21.09.2023' },
});
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Klokkeslett (obligatorisk)'), {
target: { value: '08:00' },
});
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Møteform (obligatorisk)'), {
target: { value: Kanal.TELEFON },
});
fireEvent.change(
screen.getByLabelText<HTMLInputElement>('Møtested eller annen praktisk informasjon (obligatorisk)'),
{ target: { value: 'Kontor' } },
);
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Hensikt med møtet (obligatorisk)'), {
target: { value: 'Møte med NAV' },
});
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Forberedelser til møtet (valgfri)'));
};
describe('MoteAktivitetForm', () => {
it.skip('Skal vise error summary når man submitter uten å oppgi påkrevde verdier', async () => {
const { queryByText, getByText, getByRole } = mountWithIntl(
<MoteAktivitetForm onSubmit={() => Promise.resolve()} isDirtyRef={dirtyRef} />
<MoteAktivitetForm onSubmit={() => Promise.resolve()} isDirtyRef={dirtyRef} />,
);
expect(queryByText('For å gå videre må du rette opp følgende')).toBeNull();

Expand Down Expand Up @@ -56,7 +81,7 @@ describe('MoteAktivitetForm', () => {
isDirtyRef={dirtyRef}
aktivitet={aktivitet as any}
/>
</ReduxProvider>
</ReduxProvider>,
);

fireEvent.click(screen.getByText('Lagre'));
Expand All @@ -76,7 +101,7 @@ describe('MoteAktivitetForm', () => {
onSubmit={() => new Promise(() => null)}
isDirtyRef={dirtyRef}
aktivitet={aktivitet as any}
/>
/>,
);

fireEvent.click(screen.getByText('Lagre'));
Expand Down Expand Up @@ -108,6 +133,61 @@ describe('MoteAktivitetForm', () => {
screen.getByDisplayValue('Dette er en beskrivelse');
});

it.skip('Skal validere form', async () => {
const mock = vi.fn();
mountWithIntl(<MoteAktivitetForm onSubmit={mock} isDirtyRef={dirtyRef} />);

fillForm();
fireEvent.change(screen.getByLabelText<HTMLInputElement>('Varighet (obligatorisk)'), {
target: { value: '30' },
});
await act(async () => {
fireEvent.click(screen.getByText('Lagre'));
});

expect(mock).toHaveBeenCalledWith({
adresse: 'Kontor',
avtalt: false,
beskrivelse: 'Møte med NAV',
dato: new Date('2023-09-20T22:00:00.000Z'),
forberedelser: '',
fraDato: '2023-09-21T06:00:00.000Z',
kanal: 'TELEFON',
klokkeslett: '08:00',
status: 'PLANLAGT',
tilDato: '2023-09-21T06:30:00.000Z',
tittel: 'Møte med NAV',
varighet: 30,
});
});

it.skip('Skal selekte riktig varighet', async () => {
const mock = vi.fn();
mountWithIntl(<MoteAktivitetForm onSubmit={mock} isDirtyRef={dirtyRef} />);

fillForm();
await userEvent.selectOptions(screen.getByLabelText('Varighet (obligatorisk)'), '2 timer, 30 minutter');

await act(async () => {
fireEvent.click(screen.getByText('Lagre'));
});

expect(mock).toHaveBeenCalledWith({
adresse: 'Kontor',
avtalt: false,
beskrivelse: 'Møte med NAV',
dato: new Date('2023-09-20T22:00:00.000Z'),
forberedelser: '',
fraDato: '2023-09-21T06:00:00.000Z',
kanal: 'TELEFON',
klokkeslett: '08:00',
status: 'PLANLAGT',
tilDato: '2023-09-21T08:30:00.000Z',
tittel: 'Møte med NAV',
varighet: 150,
});
});

it('Skal være disablede felter ved endring av aktivitet', () => {
const aktivitet = {
tittel: 'Dette er en test',
Expand All @@ -126,7 +206,8 @@ describe('MoteAktivitetForm', () => {
expect(screen.getByLabelText<HTMLInputElement>('Varighet (obligatorisk)').disabled).not.toBeTruthy();
expect(screen.getByLabelText<HTMLInputElement>('Møteform (obligatorisk)').disabled).not.toBeTruthy();
expect(
screen.getByLabelText<HTMLInputElement>('Møtested eller annen praktisk informasjon (obligatorisk)').disabled
screen.getByLabelText<HTMLInputElement>('Møtested eller annen praktisk informasjon (obligatorisk)')
.disabled,
).not.toBeTruthy();
expect(screen.getByLabelText<HTMLInputElement>('Hensikt med møtet (obligatorisk)').disabled).toBeTruthy();
expect(screen.getByLabelText<HTMLInputElement>('Forberedelser til møtet (valgfri)').disabled).toBeTruthy();
Expand Down
13 changes: 10 additions & 3 deletions src/moduler/aktivitet/aktivitet-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ export function beregnFraTil(data: MoteTid): FraTil {
if (dato && klokkeslett && validKlokkeslett(klokkeslett) && varighet !== undefined && varighet !== null) {
const { hour, minute } = toHourAndMinutes(klokkeslett);
const fraDato = setMinutes(setHours(startOfDay(toDate(dato)), hour), minute);
const { hour: varighetHours, minute: varighetMinutes } = toHourAndMinutes(varighet);
const tilDato = addMinutes(fraDato, varighetHours * 60 + varighetMinutes);
const tilDato = addMinutes(fraDato, varighet);
return {
fraDato: fraDato.toISOString(),
tilDato: tilDato.toISOString(),
Expand All @@ -176,7 +175,15 @@ export function formatterVarighet(varighet?: string | number): string | undefine
if (!varighet) return undefined;
if (typeof varighet === 'number' || !isNaN(parseInt(varighet))) {
const { hour, minute } = toHourAndMinutes(varighet);
return `${prefixMed0(hour.toString())}:${prefixMed0(minute.toString())}`;
if (hour > 0) {
if (minute > 0) {
return `${hour.toString()} ${hour === 1 ? 'time' : 'timer'}, ${prefixMed0(minute.toString())} minutter`;
} else {
return `${hour.toString()} ${hour === 1 ? 'time' : 'timer'}`;
}
} else {
return `${prefixMed0(minute.toString())} minutter`;
}
} else {
// Assuming this is correctly formatted "HH:ss"
return varighet;
Expand Down

0 comments on commit 1ca9b9a

Please sign in to comment.