From 84c6cea4b9935d02f0ea04decd42d6fe19bc9ac7 Mon Sep 17 00:00:00 2001 From: Hallvard Andreas Stark <hallvard@scel.to> Date: Wed, 19 Mar 2025 11:07:59 +0100 Subject: [PATCH 1/5] =?UTF-8?q?P=C3=A5begynt=20aksjonspunkt=20Bort=20med?= =?UTF-8?q?=20bruk=20av=20tailwind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prosess/ung-beregning/ArbeidOgInntekt.tsx | 236 ++++++++++++++---- .../src/prosess/ung-beregning/BarnPanel.tsx | 38 +++ .../ung-beregning/DagsatsOgUtbetaling.tsx | 21 +- .../src/prosess/ung-beregning/DataSection.tsx | 39 +-- .../prosess/ung-beregning/UngBarnFakta.tsx | 47 ---- .../ung-beregning/UngBeregning.stories.tsx | 5 +- .../prosess/ung-beregning/UngBeregning.tsx | 15 +- .../ung-beregning/UngBeregningIndex.tsx | 7 +- .../ung-beregning/arbeidOgInntekt.module.css | 24 ++ .../arbeidOgInntekt.module.d.css.ts | 10 + .../src/prosess/ung-beregning/barn.module.css | 7 + .../ung-beregning/barn.module.d.css.ts | 6 + .../dagsatsOgUtbetaling.module.css | 17 ++ .../dagsatsOgUtbetaling.module.d.css.ts | 8 + .../ung-beregning/dataSection.module.css | 14 ++ .../ung-beregning/dataSection.module.d.css.ts | 7 + 16 files changed, 369 insertions(+), 132 deletions(-) create mode 100644 packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx delete mode 100644 packages/v2/gui/src/prosess/ung-beregning/UngBarnFakta.tsx create mode 100644 packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.css create mode 100644 packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.d.css.ts create mode 100644 packages/v2/gui/src/prosess/ung-beregning/barn.module.css create mode 100644 packages/v2/gui/src/prosess/ung-beregning/barn.module.d.css.ts create mode 100644 packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.css create mode 100644 packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.d.css.ts create mode 100644 packages/v2/gui/src/prosess/ung-beregning/dataSection.module.css create mode 100644 packages/v2/gui/src/prosess/ung-beregning/dataSection.module.d.css.ts diff --git a/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx b/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx index 648d49b1dd..edd9386e3d 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx @@ -1,5 +1,9 @@ -import { CheckmarkCircleFillIcon } from '@navikt/aksel-icons'; -import { HStack, Table } from '@navikt/ds-react'; +import { CheckmarkCircleFillIcon, ExclamationmarkTriangleFillIcon, PersonIcon } from '@navikt/aksel-icons'; +import { Bleed, BodyLong, Box, Button, Heading, HStack, Table, VStack } from '@navikt/ds-react'; +import { Form, InputField, RadioGroupPanel, TextAreaField } from '@navikt/ft-form-hooks'; +import { minLength, required } from '@navikt/ft-form-validators'; +import { useForm } from 'react-hook-form'; +import styles from './arbeidOgInntekt.module.css'; const dummyData = [ { @@ -9,51 +13,187 @@ const dummyData = [ rapportertDeltager: '0 kr', rapportertInntekt: '0 kr', }, + { + status: 'Avvik', + arbeidsforhold: 'Bedrift 2 AS', + periode: `${new Date().toLocaleDateString('no')} - ${new Date().toLocaleDateString('no')}`, + rapportertDeltager: '0 kr', + rapportertInntekt: '0 kr', + }, ]; -export const ArbeidOgInntekt = () => ( - <div className="rounded-lg border border-[#CFD3D8] flex border-solid mt-7 "> - <Table> - <Table.Header> - <Table.Row> - <Table.HeaderCell scope="col" className="pl-4"> - Status - </Table.HeaderCell> - <Table.HeaderCell scope="col">Arbeidsforhold</Table.HeaderCell> - <Table.HeaderCell scope="col">Periode</Table.HeaderCell> - <Table.HeaderCell scope="col" align="right"> - Rapportert av deltager - </Table.HeaderCell> - <Table.HeaderCell scope="col" align="right"> - Rapportert i A-inntekt - </Table.HeaderCell> - <Table.HeaderCell /> - </Table.Row> - </Table.Header> - <Table.Body> - {dummyData.map((data, index) => { - const isLastRow = index === dummyData.length - 1; - return ( - <Table.ExpandableRow - key={index} - content="Innhold" - togglePlacement="right" - className={isLastRow ? '[&>td]:border-none' : ''} - > - <Table.DataCell className="pl-2"> - <HStack gap="2"> - <CheckmarkCircleFillIcon fontSize={24} style={{ color: 'var(--a-surface-success)' }} /> - {data.status} - </HStack> - </Table.DataCell> - <Table.DataCell>{data.arbeidsforhold}</Table.DataCell> - <Table.DataCell>{data.periode}</Table.DataCell> - <Table.DataCell align="right">{data.rapportertDeltager}</Table.DataCell> - <Table.DataCell align="right">{data.rapportertInntekt}</Table.DataCell> - </Table.ExpandableRow> - ); - })} - </Table.Body> - </Table> - </div> -); +type Formvalues = { + inntektArbeid: string; + inntektYtelse: string; + inntektRadio: 'deltager' | 'a-inntekt' | 'fastsett-belop' | ''; + begrunnelse: string; +}; + +interface ArbeidOgInntektProps { + submitCallback: (data: unknown) => void; +} + +export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { + const formMethods = useForm<Formvalues>({ + defaultValues: { + inntektArbeid: '', + inntektYtelse: '', + inntektRadio: '', + begrunnelse: '', + }, + }); + const inntektRadio = formMethods.watch('inntektRadio'); + + const onSubmit = (values: Formvalues) => { + let payload; + if (values.inntektRadio === 'fastsett-belop') { + payload = { + inntektArbeid: values.inntektArbeid, + inntektYtelse: values.inntektYtelse, + begrunnelse: values.begrunnelse, + }; + } else { + payload = { + inntektRadio: values.inntektRadio, + begrunnelse: values.begrunnelse, + }; + } + submitCallback(payload); + }; + + const getAksjonspunkt = () => ( + <Bleed marginBlock="4 0"> + <Box + marginInline="2 0" + padding="6" + background="surface-subtle" + borderColor="border-warning" + borderWidth="0 0 0 4" + borderRadius="0 medium medium 0" + > + <VStack gap="6"> + <HStack gap="2" wrap={false}> + <PersonIcon title="Deltager" fontSize="1.5rem" className={styles.personIcon} /> + <VStack gap="2"> + <Heading size="xsmall" as="h3"> + Beskrivelse fra deltaker for avvik i perioden 01.02.2025 - 28.02.2025 + </Heading> + <Box maxWidth="75ch"> + <BodyLong size="small"> + Jeg fikk forskuttert litt lønn av arbeidsgiver denne måneden fordi jeg har hatt økonomiske + utfordringer, så jeg rapporterte bare det jeg egentlig skulle fått utbetalt. Det var ikke meningen å + oppgi feil, bare å holde det riktig for denne måneden! + </BodyLong> + </Box> + </VStack> + </HStack> + <Box borderColor="border-default" borderWidth="0 0 1 0" /> + <VStack gap="2"> + <RadioGroupPanel + name="inntektRadio" + label="Hvilken inntekt skal benyttes?" + validate={[required]} + radios={[ + { value: 'deltager', label: 'Rapportert inntekt fra deltager' }, + { value: 'a-inntekt', label: 'Rapportert inntekt fra A-inntekt' }, + { value: 'fastsett-belop', label: 'Fastsett beløp' }, + ]} + /> + {inntektRadio === 'fastsett-belop' && ( + <VStack gap="4"> + <InputField + name="inntektArbeid" + label="Inntekt fra arbeid" + type="text" + validate={[required]} + htmlSize={7} + size="small" + /> + <InputField + name="inntektYtelse" + label="Inntekt fra ytelse" + type="text" + validate={[required]} + htmlSize={7} + size="small" + /> + </VStack> + )} + </VStack> + <Box maxWidth="70ch"> + <TextAreaField + name="begrunnelse" + label="Begrunnelse" + validate={[required, minLength(3)]} + maxLength={1500} + /> + </Box> + <HStack gap="2"> + <Button size="small" variant="primary" type="submit"> + Bekreft og fortsett + </Button> + <Button size="small" variant="secondary"> + Avbryt + </Button> + </HStack> + </VStack> + </Box> + </Bleed> + ); + + return ( + <Form<Formvalues> formMethods={formMethods} onSubmit={onSubmit}> + <Box marginBlock="7 0" borderRadius="large" borderWidth="1" borderColor="border-divider"> + <Table> + <Table.Header> + <Table.Row> + <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> + Status + </Table.HeaderCell> + <Table.HeaderCell scope="col">Arbeidsforhold</Table.HeaderCell> + <Table.HeaderCell scope="col">Periode</Table.HeaderCell> + <Table.HeaderCell scope="col" align="right"> + Rapportert av deltager + </Table.HeaderCell> + <Table.HeaderCell scope="col" align="right"> + Rapportert i A-inntekt + </Table.HeaderCell> + <Table.HeaderCell /> + </Table.Row> + </Table.Header> + <Table.Body> + {dummyData.map((data, index) => { + const isLastRow = index === dummyData.length - 1; + const hasAvvik = data.status === 'Avvik'; + return ( + <Table.ExpandableRow + key={index} + content={hasAvvik ? getAksjonspunkt() : null} + togglePlacement="right" + className={isLastRow ? styles.lastRow : ''} + expandOnRowClick + expansionDisabled={!hasAvvik} + > + <Table.DataCell className={styles.firstDataCell}> + <HStack gap="2"> + {hasAvvik ? ( + <ExclamationmarkTriangleFillIcon fontSize="1.5rem" className={styles.exclamationmarkIcon} /> + ) : ( + <CheckmarkCircleFillIcon fontSize={24} className={styles.checkmarkIcon} /> + )} + {data.status} + </HStack> + </Table.DataCell> + <Table.DataCell>{data.arbeidsforhold}</Table.DataCell> + <Table.DataCell>{data.periode}</Table.DataCell> + <Table.DataCell align="right">{data.rapportertDeltager}</Table.DataCell> + <Table.DataCell align="right">{data.rapportertInntekt}</Table.DataCell> + </Table.ExpandableRow> + ); + })} + </Table.Body> + </Table> + </Box> + </Form> + ); +}; diff --git a/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx b/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx new file mode 100644 index 0000000000..bc5622675f --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx @@ -0,0 +1,38 @@ +import { Box, Table } from '@navikt/ds-react'; +import styles from './barn.module.css'; +import type { Barn } from './types/Barn'; + +interface Props { + barn: Barn[]; +} + +export const BarnPanel = ({ barn }: Props) => { + const harBarnMedDødsdato = barn.some(b => !!b.dødsdato); + return ( + <Box marginBlock="4 0" borderRadius="large" borderWidth="1" borderColor="border-divider"> + <Table> + <Table.Header> + <Table.Row> + <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> + Navn + </Table.HeaderCell> + <Table.HeaderCell scope="col">Fødselsdato</Table.HeaderCell> + {harBarnMedDødsdato && <Table.HeaderCell scope="col">Dødsdato</Table.HeaderCell>} + </Table.Row> + </Table.Header> + <Table.Body> + {barn.map(({ navn, fødselsdato, dødsdato }, index) => { + const isLastRow = index === barn.length - 1; + return ( + <Table.Row key={navn} className={isLastRow ? styles.lastRow : ''}> + <Table.DataCell className={styles.firstHeaderCell}>{navn}</Table.DataCell> + <Table.DataCell>{fødselsdato}</Table.DataCell> + {harBarnMedDødsdato && <Table.DataCell>{dødsdato}</Table.DataCell>} + </Table.Row> + ); + })} + </Table.Body> + </Table> + </Box> + ); +}; diff --git a/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx b/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx index e01aa33016..fbff4246bc 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx @@ -3,8 +3,9 @@ import { type UngdomsytelseSatsPeriodeDto, } from '@k9-sak-web/backend/ungsak/generated'; import { formatPeriod } from '@k9-sak-web/lib/dateUtils/dateUtils.js'; -import { Heading, Table, Tooltip, VStack } from '@navikt/ds-react'; +import { Box, Heading, Table, Tooltip, VStack } from '@navikt/ds-react'; import { DataSection } from './DataSection'; +import styles from './dagsatsOgUtbetaling.module.css'; const formatCurrencyWithKr = (value: number) => { const formattedValue = Number(value).toLocaleString('nb-NO').replace(/,|\s/g, ' '); @@ -39,7 +40,7 @@ const formatSats = (satstype: UngdomsytelseSatsPeriodeDtoSatsType) => { ); } return ( - <div className="flex items-center gap-2"> + <div className={styles.sats}> {satstype} {icon && <Tooltip content="Hjelpetekst om satser her">{icon}</Tooltip>} </div> ); @@ -50,17 +51,16 @@ interface DagsatsOgUtbetalingProps { } export const DagsatsOgUtbetaling = ({ satser }: DagsatsOgUtbetalingProps) => ( - <div className="mt-5"> + <div className={styles.dagsatsSection}> <VStack gap="4"> <DataSection /> - <div> <Heading size="xsmall">Beregning av dagsats</Heading> - <div className="rounded-lg border border-[#CFD3D8] flex border-solid mt-3 "> + <Box marginBlock="4 0" borderRadius="large" borderWidth="1" borderColor="border-divider"> <Table> <Table.Header> <Table.Row> - <Table.HeaderCell scope="col" className="pl-4"> + <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> Periode </Table.HeaderCell> <Table.HeaderCell scope="col">Sats</Table.HeaderCell> @@ -83,9 +83,12 @@ export const DagsatsOgUtbetaling = ({ satser }: DagsatsOgUtbetalingProps) => ( key={`${fom}_${tom}`} content="Innhold" togglePlacement="right" - className={isLastRow ? '[&>td]:border-none' : ''} + className={isLastRow ? styles.lastRow : ''} + expandOnRowClick > - <Table.DataCell className="pl-4">{fom && tom && formatPeriod(fom, tom)}</Table.DataCell> + <Table.DataCell className={styles.firstHeaderCell}> + {fom && tom && formatPeriod(fom, tom)} + </Table.DataCell> <Table.DataCell>{formatSats(satsType)}</Table.DataCell> <Table.DataCell>{grunnbeløp && formatCurrencyWithKr(grunnbeløp)}</Table.DataCell> <Table.DataCell>{dagsats && formatCurrencyNoKr(dagsats)} kr</Table.DataCell> @@ -102,7 +105,7 @@ export const DagsatsOgUtbetaling = ({ satser }: DagsatsOgUtbetalingProps) => ( })} </Table.Body> </Table> - </div> + </Box> </div> </VStack> </div> diff --git a/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx b/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx index bd161f5b1b..ac8cbb7b4c 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx @@ -7,9 +7,10 @@ import { } from '@navikt/aksel-icons'; import { Bleed, BodyShort, Box, Button, HelpText, HGrid, HStack, Label, ProgressBar, VStack } from '@navikt/ds-react'; import { useState } from 'react'; +import styles from './dataSection.module.css'; const DataBox = ({ children, maxHeight }: { children: React.ReactNode; maxHeight?: string }) => ( - <div className="rounded-lg bg-[#EEF6FC] px-4 pt-5 pb-4 mb-4" style={{ maxHeight }}> + <div className={styles.dataBox} style={{ maxHeight }}> <VStack gap="4">{children}</VStack> </div> ); @@ -41,7 +42,7 @@ const BeregningDetails = ({ {barnetillegg * barnetilleggDager} kr </BodyShort> </HStack> - <div className="h-[1px] bg-[#C0D6E4]" /> + <Box borderColor="border-subtle" borderWidth="0 0 1 0" /> <HStack justify="space-between"> <BodyShort size="small">Rapportert inntekt</BodyShort> <BodyShort size="small" weight="semibold"> @@ -56,12 +57,12 @@ const BeregningDetails = ({ {reduksjonBeløp} kr </BodyShort> </HStack> - <div className="h-[1px] bg-[#C0D6E4]" /> + <Box borderColor="border-subtle" borderWidth="0 0 1 0" /> <HStack justify="space-between"> - <BodyShort weight="semibold" size="small" className="text-[#156389]" as="p"> + <BodyShort weight="semibold" size="small" className={styles.utbetalingText} as="p"> Til utbetaling </BodyShort> - <BodyShort size="small" className="text-[#156389]" weight="semibold"> + <BodyShort size="small" className={styles.utbetalingText} weight="semibold"> {tilUtbetaling} kr </BodyShort> </HStack> @@ -73,7 +74,7 @@ export const DataSection = () => { return ( <HGrid gap="5" columns={3}> <DataBox maxHeight="190px"> - <HStack gap="2" className="ml-0.5"> + <HStack gap="2" marginInline="05 0"> <InformationSquareIcon color="#417DA0" fontSize="1.5rem" /> <Label as="p">Nøkkelinformasjon</Label> </HStack> @@ -87,7 +88,7 @@ export const DataSection = () => { </HStack> </DataBox> <DataBox maxHeight="190px"> - <HStack gap="2" className="ml-0.5"> + <HStack gap="2" marginInline="05 0"> <CalendarIcon color="#417DA0" fontSize="1.5rem" /> <Label as="p">Dager i ungdomsprogram</Label> </HStack> @@ -96,19 +97,19 @@ export const DataSection = () => { <HelpText title="Forklaringstekst">Forklaring om dager utbetalt her</HelpText> </HStack> <div> - <HStack justify="space-between"> - <BodyShort className="mb-2" size="small" id="progress-bar-label-medium"> - 0 av 260 - </BodyShort> - <BodyShort className="mb-2" size="small"> - 260 dager igjen - </BodyShort> - </HStack> + <Box marginBlock="0 2"> + <HStack justify="space-between"> + <BodyShort size="small" id="progress-bar-label-medium"> + 0 av 260 + </BodyShort> + <BodyShort size="small">260 dager igjen</BodyShort> + </HStack> + </Box> <ProgressBar value={0} valueMax={260} size="medium" aria-labelledby="progress-bar-label-medium" /> </div> </DataBox> <DataBox> - <HStack gap="2" className="ml-0.5"> + <HStack gap="2" marginInline="05 0"> <SackKronerIcon color="#417DA0" fontSize="1.5rem" /> <Label as="p">Siste utbetaling</Label> </HStack> @@ -117,7 +118,7 @@ export const DataSection = () => { {new Date().toLocaleDateString('nb-NO', { day: 'numeric', month: 'long' })} til kontonummer xxx </BodyShort> <Bleed marginInline="4" asChild> - <div className="h-[1px] bg-[#C0D6E4]" /> + <Box borderColor="border-subtle" borderWidth="0 0 1 0" /> </Bleed> <Bleed marginInline="3" marginBlock="2 1" asChild> <Button @@ -126,7 +127,7 @@ export const DataSection = () => { icon={isUtregningExpanded ? <ChevronUpIcon fontSize="1.5rem" /> : <ChevronDownIcon fontSize="1.5rem" />} iconPosition="right" onClick={() => setIsUtregningExpanded(!isUtregningExpanded)} - className="justify-between" + className={styles.expandButton} > {isUtregningExpanded ? 'Skjul utregning' : 'Vis utregning'} </Button> @@ -134,7 +135,7 @@ export const DataSection = () => { {isUtregningExpanded && ( <> <Bleed marginBlock="2 0" asChild> - <div className="h-[1px] bg-[#C0D6E4]" /> + <Box borderColor="border-subtle" borderWidth="0 0 1 0" /> </Bleed> <Box> <BeregningDetails diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBarnFakta.tsx b/packages/v2/gui/src/prosess/ung-beregning/UngBarnFakta.tsx deleted file mode 100644 index 462ca4c541..0000000000 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBarnFakta.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Alert, Table } from '@navikt/ds-react'; -import type { Barn } from './types/Barn'; - -interface Props { - barn: Barn[]; -} - -const UngBarnFakta = ({ barn }: Props) => { - const harBarnMedDødsdato = barn.some(b => !!b.dødsdato); - return ( - <div className="flex mt-4"> - {barn.length === 0 ? ( - <Alert variant="info" size="small"> - Deltaker har ingen registrerte barn i folkeregisteret. - </Alert> - ) : ( - <div className="rounded-lg border border-[#CFD3D8] flex border-solid"> - <Table> - <Table.Header> - <Table.Row> - <Table.HeaderCell scope="col" className="pl-4"> - Navn - </Table.HeaderCell> - <Table.HeaderCell scope="col">Fødselsdato</Table.HeaderCell> - {harBarnMedDødsdato && <Table.HeaderCell scope="col">Dødsdato</Table.HeaderCell>} - </Table.Row> - </Table.Header> - <Table.Body> - {barn.map(({ navn, fødselsdato, dødsdato }, index) => { - const isLastRow = index === barn.length - 1; - return ( - <Table.Row key={navn} className={isLastRow ? '[&>td]:border-none' : ''}> - <Table.DataCell className="pl-4">{navn}</Table.DataCell> - <Table.DataCell>{fødselsdato}</Table.DataCell> - {harBarnMedDødsdato && <Table.DataCell>{dødsdato}</Table.DataCell>} - </Table.Row> - ); - })} - </Table.Body> - </Table> - </div> - )} - </div> - ); -}; - -export default UngBarnFakta; diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.stories.tsx b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.stories.tsx index 087c935823..791e1ece1b 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.stories.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react'; +import { asyncAction } from '../../storybook/asyncAction'; import { FakeUngBeregningBackendApi } from '../../storybook/mocks/FakeUngBeregningBackendApi'; import UngBeregning from './UngBeregning'; @@ -11,4 +12,6 @@ export default meta; type Story = StoryObj<typeof meta>; -export const DefaultStory: Story = { args: { behandling: { uuid: '123' }, api, barn: [] } }; +export const DefaultStory: Story = { + args: { behandling: { uuid: '123' }, api, barn: [], submitCallback: asyncAction('Løs aksjonspunkt') }, +}; diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx index 0a9ad94d81..83adebf2b9 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx @@ -2,8 +2,8 @@ import { type UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/gen import { Alert, Box, Heading, Loader, Tabs } from '@navikt/ds-react'; import { useQuery } from '@tanstack/react-query'; import { ArbeidOgInntekt } from './ArbeidOgInntekt'; +import { BarnPanel } from './BarnPanel'; import { DagsatsOgUtbetaling } from './DagsatsOgUtbetaling'; -import UngBarnFakta from './UngBarnFakta'; import type { UngBeregningBackendApiType } from './UngBeregningBackendApiType'; import type { Barn } from './types/Barn'; @@ -12,12 +12,13 @@ interface Props { api: UngBeregningBackendApiType; barn: Barn[]; inntekt?: unknown[]; + submitCallback: (data: unknown) => void; } const sortSatser = (data: UngdomsytelseSatsPeriodeDto[]) => data?.toSorted((a, b) => new Date(a.fom).getTime() - new Date(b.fom).getTime()).toReversed(); -const UngBeregning = ({ api, behandling, barn, inntekt }: Props) => { +const UngBeregning = ({ api, behandling, barn, inntekt, submitCallback }: Props) => { const { data: satser, isLoading: satserIsLoading, @@ -42,25 +43,27 @@ const UngBeregning = ({ api, behandling, barn, inntekt }: Props) => { return ( <Box paddingInline="4 8" paddingBlock="2"> - <div className="min-h-svh"> + <Box minHeight="100svh"> <Heading size="medium" level="1" spacing> Sats og beregning </Heading> <Tabs defaultValue="dagsats"> <Tabs.List> {harInntekt && <Tabs.Tab value="arbeid" label="Arbeid og inntekt" />} + {/* <Tabs.Tab value="arbeid" label="Arbeid og inntekt" /> */} {harBarn && <Tabs.Tab value="barn" label="Registrerte barn" />} {(harInntekt || harBarn) && <Tabs.Tab value="dagsats" label="Dagsats og utbetaling" />} + {/* <Tabs.Tab value="dagsats" label="Dagsats og utbetaling" /> */} </Tabs.List> <Tabs.Panel value="arbeid"> - <ArbeidOgInntekt /> + <ArbeidOgInntekt submitCallback={submitCallback} /> </Tabs.Panel> <Tabs.Panel value="dagsats">{satserSuccess && <DagsatsOgUtbetaling satser={satser} />}</Tabs.Panel> <Tabs.Panel value="barn"> - <UngBarnFakta barn={barn} /> + <BarnPanel barn={barn} /> </Tabs.Panel> </Tabs> - </div> + </Box> </Box> ); }; diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregningIndex.tsx b/packages/v2/gui/src/prosess/ung-beregning/UngBeregningIndex.tsx index 4589f4a380..95cffc3e30 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregningIndex.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregningIndex.tsx @@ -8,12 +8,15 @@ import type { Barn } from './types/Barn'; interface Props { behandling: BehandlingDto; barn: Barn[]; + submitCallback: (data: unknown) => void; } -const UngBeregningIndex = ({ barn, behandling }: Props) => { +const UngBeregningIndex = ({ barn, behandling, submitCallback }: Props) => { const ungSakClient = useContext(UngSakClientContext); const ungBeregningBackendClient = new UngBeregningBackendClient(ungSakClient); - return <UngBeregning behandling={behandling} api={ungBeregningBackendClient} barn={barn} />; + return ( + <UngBeregning behandling={behandling} api={ungBeregningBackendClient} barn={barn} submitCallback={submitCallback} /> + ); }; export default UngBeregningIndex; diff --git a/packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.css b/packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.css new file mode 100644 index 0000000000..a2699ad10c --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.css @@ -0,0 +1,24 @@ +.firstHeaderCell { + padding-left: var(--a-spacing-4); +} + +.firstDataCell { + padding-left: var(--a-spacing-2); +} + +.lastRow > td { + border-bottom: none; +} + +.exclamationmarkIcon { + color: var(--a-icon-warning); + font-size: var(--a-font-size-heading-medium); +} + +.checkmarkIcon { + color: var(--a-surface-success); +} + +.personIcon { + flex-shrink: 0; +} diff --git a/packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.d.css.ts b/packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.d.css.ts new file mode 100644 index 0000000000..ccc0e454ff --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/arbeidOgInntekt.module.d.css.ts @@ -0,0 +1,10 @@ +declare const styles: { + readonly "checkmarkIcon": string; + readonly "exclamationmarkIcon": string; + readonly "firstDataCell": string; + readonly "firstHeaderCell": string; + readonly "lastRow": string; + readonly "personIcon": string; +}; +export = styles; + diff --git a/packages/v2/gui/src/prosess/ung-beregning/barn.module.css b/packages/v2/gui/src/prosess/ung-beregning/barn.module.css new file mode 100644 index 0000000000..21466b4be0 --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/barn.module.css @@ -0,0 +1,7 @@ +.lastRow > td { + border-bottom: none; +} + +.firstHeaderCell { + padding-left: var(--a-spacing-4); +} diff --git a/packages/v2/gui/src/prosess/ung-beregning/barn.module.d.css.ts b/packages/v2/gui/src/prosess/ung-beregning/barn.module.d.css.ts new file mode 100644 index 0000000000..336c92b0c0 --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/barn.module.d.css.ts @@ -0,0 +1,6 @@ +declare const styles: { + readonly "firstHeaderCell": string; + readonly "lastRow": string; +}; +export = styles; + diff --git a/packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.css b/packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.css new file mode 100644 index 0000000000..39a33a9de2 --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.css @@ -0,0 +1,17 @@ +.sats { + display: flex; + align-items: center; + gap: var(--a-spacing-2); +} + +.dagsatsSection { + margin-top: var(--a-spacing-5); +} + +.firstHeaderCell { + padding-left: var(--a-spacing-4); +} + +.lastRow > td { + border-bottom: none; +} diff --git a/packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.d.css.ts b/packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.d.css.ts new file mode 100644 index 0000000000..31164d614b --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/dagsatsOgUtbetaling.module.d.css.ts @@ -0,0 +1,8 @@ +declare const styles: { + readonly "dagsatsSection": string; + readonly "firstHeaderCell": string; + readonly "lastRow": string; + readonly "sats": string; +}; +export = styles; + diff --git a/packages/v2/gui/src/prosess/ung-beregning/dataSection.module.css b/packages/v2/gui/src/prosess/ung-beregning/dataSection.module.css new file mode 100644 index 0000000000..03877d62e6 --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/dataSection.module.css @@ -0,0 +1,14 @@ +.dataBox { + border-radius: 0.5rem; + background-color: #eef6fc; + padding: 1.25rem 1rem 1rem; + margin-bottom: 1rem; +} + +.utbetalingText { + color: #156389; +} + +.expandButton { + justify-content: space-between; +} diff --git a/packages/v2/gui/src/prosess/ung-beregning/dataSection.module.d.css.ts b/packages/v2/gui/src/prosess/ung-beregning/dataSection.module.d.css.ts new file mode 100644 index 0000000000..b848f721fd --- /dev/null +++ b/packages/v2/gui/src/prosess/ung-beregning/dataSection.module.d.css.ts @@ -0,0 +1,7 @@ +declare const styles: { + readonly "dataBox": string; + readonly "expandButton": string; + readonly "utbetalingText": string; +}; +export = styles; + From cc9f1ed7b33bc17a85585e2bdc7986501f6716fc Mon Sep 17 00:00:00 2001 From: Hallvard Andreas Stark <hallvard@scel.to> Date: Thu, 20 Mar 2025 14:38:29 +0100 Subject: [PATCH 2/5] Bruker nytt endepunkt for data til arbeid og inntekt --- packages/v2/backend/package.json | 2 +- .../prosess/ung-beregning/ArbeidOgInntekt.tsx | 112 +++++++++--------- .../prosess/ung-beregning/UngBeregning.tsx | 14 ++- .../UngBeregningBackendApiType.ts | 3 +- .../UngBeregningBackendClient.ts | 10 +- .../src/shared/periodLabel/PeriodLabel.tsx | 35 ++++++ packages/v2/gui/src/utils/formatters.ts | 5 + yarn.lock | 10 +- 8 files changed, 124 insertions(+), 67 deletions(-) create mode 100644 packages/v2/gui/src/shared/periodLabel/PeriodLabel.tsx diff --git a/packages/v2/backend/package.json b/packages/v2/backend/package.json index a3ce062d8c..78180b6fd8 100644 --- a/packages/v2/backend/package.json +++ b/packages/v2/backend/package.json @@ -22,7 +22,7 @@ "dependencies": { "@navikt/k9-klage-typescript-client": "2.0.20250218125133", "@navikt/k9-sak-typescript-client": "2.0.20250306092710", - "@navikt/ung-sak-typescript-client": "0.2.20250221104339" + "@navikt/ung-sak-typescript-client": "0.2.20250320091618" }, "devDependencies": { "@tanstack/eslint-plugin-query": "^5.68.0" diff --git a/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx b/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx index edd9386e3d..d98d83f4eb 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx @@ -1,43 +1,39 @@ +import { + KontrollerInntektPeriodeDtoStatus, + KontrollerInntektPeriodeDtoValg, + type KontrollerInntektDto, + type RapportertInntektDto, +} from '@k9-sak-web/backend/ungsak/generated'; import { CheckmarkCircleFillIcon, ExclamationmarkTriangleFillIcon, PersonIcon } from '@navikt/aksel-icons'; import { Bleed, BodyLong, Box, Button, Heading, HStack, Table, VStack } from '@navikt/ds-react'; import { Form, InputField, RadioGroupPanel, TextAreaField } from '@navikt/ft-form-hooks'; import { minLength, required } from '@navikt/ft-form-validators'; import { useForm } from 'react-hook-form'; +import PeriodLabel from '../../shared/periodLabel/PeriodLabel'; +import { formatCurrencyWithKr } from '../../utils/formatters'; import styles from './arbeidOgInntekt.module.css'; -const dummyData = [ - { - status: 'Ingen avvik', - arbeidsforhold: 'Bedrift AS', - periode: `${new Date().toLocaleDateString('no')} - ${new Date().toLocaleDateString('no')}`, - rapportertDeltager: '0 kr', - rapportertInntekt: '0 kr', - }, - { - status: 'Avvik', - arbeidsforhold: 'Bedrift 2 AS', - periode: `${new Date().toLocaleDateString('no')} - ${new Date().toLocaleDateString('no')}`, - rapportertDeltager: '0 kr', - rapportertInntekt: '0 kr', - }, -]; +const formaterInntekt = (inntekt: RapportertInntektDto) => { + return formatCurrencyWithKr((inntekt.arbeidsinntekt ?? 0) + (inntekt.ytelse ?? 0)); +}; type Formvalues = { - inntektArbeid: string; - inntektYtelse: string; - inntektRadio: 'deltager' | 'a-inntekt' | 'fastsett-belop' | ''; + fastsattArbeidsinntekt: string; + fastsattYtelse: string; + inntektRadio: KontrollerInntektPeriodeDtoValg | ''; begrunnelse: string; }; interface ArbeidOgInntektProps { submitCallback: (data: unknown) => void; + inntektKontrollperioder: KontrollerInntektDto['kontrollperioder']; } -export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { +export const ArbeidOgInntekt = ({ submitCallback, inntektKontrollperioder }: ArbeidOgInntektProps) => { const formMethods = useForm<Formvalues>({ defaultValues: { - inntektArbeid: '', - inntektYtelse: '', + fastsattArbeidsinntekt: '', + fastsattYtelse: '', inntektRadio: '', begrunnelse: '', }, @@ -45,19 +41,14 @@ export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { const inntektRadio = formMethods.watch('inntektRadio'); const onSubmit = (values: Formvalues) => { - let payload; - if (values.inntektRadio === 'fastsett-belop') { - payload = { - inntektArbeid: values.inntektArbeid, - inntektYtelse: values.inntektYtelse, - begrunnelse: values.begrunnelse, - }; - } else { - payload = { - inntektRadio: values.inntektRadio, - begrunnelse: values.begrunnelse, - }; - } + const payload = { + inntektRadio: values.inntektRadio, + begrunnelse: values.begrunnelse, + ...(values.inntektRadio === KontrollerInntektPeriodeDtoValg.MANUELT_FASTSATT && { + fastsattArbeidsinntekt: values.fastsattArbeidsinntekt, + fastsattYtelse: values.fastsattYtelse, + }), + }; submitCallback(payload); }; @@ -94,15 +85,21 @@ export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { label="Hvilken inntekt skal benyttes?" validate={[required]} radios={[ - { value: 'deltager', label: 'Rapportert inntekt fra deltager' }, - { value: 'a-inntekt', label: 'Rapportert inntekt fra A-inntekt' }, - { value: 'fastsett-belop', label: 'Fastsett beløp' }, + { + value: KontrollerInntektPeriodeDtoValg.BRUK_BRUKERS_INNTEKT, + label: 'Rapportert inntekt fra deltager', + }, + { + value: KontrollerInntektPeriodeDtoValg.BRUK_REGISTER_INNTEKT, + label: 'Rapportert inntekt fra A-inntekt', + }, + { value: KontrollerInntektPeriodeDtoValg.MANUELT_FASTSATT, label: 'Fastsett beløp' }, ]} /> - {inntektRadio === 'fastsett-belop' && ( + {inntektRadio === KontrollerInntektPeriodeDtoValg.MANUELT_FASTSATT && ( <VStack gap="4"> <InputField - name="inntektArbeid" + name="fastsattArbeidsinntekt" label="Inntekt fra arbeid" type="text" validate={[required]} @@ -110,7 +107,7 @@ export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { size="small" /> <InputField - name="inntektYtelse" + name="fastsattYtelse" label="Inntekt fra ytelse" type="text" validate={[required]} @@ -150,7 +147,6 @@ export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> Status </Table.HeaderCell> - <Table.HeaderCell scope="col">Arbeidsforhold</Table.HeaderCell> <Table.HeaderCell scope="col">Periode</Table.HeaderCell> <Table.HeaderCell scope="col" align="right"> Rapportert av deltager @@ -162,32 +158,40 @@ export const ArbeidOgInntekt = ({ submitCallback }: ArbeidOgInntektProps) => { </Table.Row> </Table.Header> <Table.Body> - {dummyData.map((data, index) => { - const isLastRow = index === dummyData.length - 1; - const hasAvvik = data.status === 'Avvik'; + {inntektKontrollperioder?.map((inntekt, index) => { + const isLastRow = index === inntektKontrollperioder.length - 1; + const harAksjonspunkt = inntekt.erTilVurdering; + const harAvvik = inntekt.status === KontrollerInntektPeriodeDtoStatus.AVVIK; return ( <Table.ExpandableRow - key={index} - content={hasAvvik ? getAksjonspunkt() : null} + key={`${inntekt.periode?.fom}_${inntekt.periode?.tom}`} + content={harAksjonspunkt ? getAksjonspunkt() : null} togglePlacement="right" className={isLastRow ? styles.lastRow : ''} expandOnRowClick - expansionDisabled={!hasAvvik} + expansionDisabled={!harAksjonspunkt} > <Table.DataCell className={styles.firstDataCell}> <HStack gap="2"> - {hasAvvik ? ( + {harAvvik ? ( <ExclamationmarkTriangleFillIcon fontSize="1.5rem" className={styles.exclamationmarkIcon} /> ) : ( <CheckmarkCircleFillIcon fontSize={24} className={styles.checkmarkIcon} /> )} - {data.status} + {inntekt.status} </HStack> </Table.DataCell> - <Table.DataCell>{data.arbeidsforhold}</Table.DataCell> - <Table.DataCell>{data.periode}</Table.DataCell> - <Table.DataCell align="right">{data.rapportertDeltager}</Table.DataCell> - <Table.DataCell align="right">{data.rapportertInntekt}</Table.DataCell> + <Table.DataCell> + {inntekt.periode && ( + <PeriodLabel dateStringFom={inntekt.periode?.fom} dateStringTom={inntekt.periode?.tom} /> + )} + </Table.DataCell> + <Table.DataCell align="right"> + {inntekt.rapporterteInntekter?.bruker && formaterInntekt(inntekt.rapporterteInntekter?.bruker)} + </Table.DataCell> + <Table.DataCell align="right"> + {inntekt.rapporterteInntekter?.register && formaterInntekt(inntekt.rapporterteInntekter?.register)} + </Table.DataCell> </Table.ExpandableRow> ); })} diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx index 83adebf2b9..fd86650f55 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx @@ -11,14 +11,13 @@ interface Props { behandling: { uuid: string }; api: UngBeregningBackendApiType; barn: Barn[]; - inntekt?: unknown[]; submitCallback: (data: unknown) => void; } const sortSatser = (data: UngdomsytelseSatsPeriodeDto[]) => data?.toSorted((a, b) => new Date(a.fom).getTime() - new Date(b.fom).getTime()).toReversed(); -const UngBeregning = ({ api, behandling, barn, inntekt, submitCallback }: Props) => { +const UngBeregning = ({ api, behandling, barn, submitCallback }: Props) => { const { data: satser, isLoading: satserIsLoading, @@ -30,7 +29,12 @@ const UngBeregning = ({ api, behandling, barn, inntekt, submitCallback }: Props) select: sortSatser, }); - if (satserIsLoading) { + const { data: inntekt, isLoading: kontrollInntektIsLoading } = useQuery({ + queryKey: ['kontrollInntekt', behandling.uuid], + queryFn: () => api.getKontrollerInntekt(behandling.uuid), + }); + + if (satserIsLoading || kontrollInntektIsLoading) { return <Loader size="large" />; } @@ -39,7 +43,7 @@ const UngBeregning = ({ api, behandling, barn, inntekt, submitCallback }: Props) } const harBarn = barn.length > 0; - const harInntekt = inntekt && inntekt.length > 0; + const harInntekt = inntekt?.kontrollperioder && inntekt.kontrollperioder.length > 0; return ( <Box paddingInline="4 8" paddingBlock="2"> @@ -56,7 +60,7 @@ const UngBeregning = ({ api, behandling, barn, inntekt, submitCallback }: Props) {/* <Tabs.Tab value="dagsats" label="Dagsats og utbetaling" /> */} </Tabs.List> <Tabs.Panel value="arbeid"> - <ArbeidOgInntekt submitCallback={submitCallback} /> + <ArbeidOgInntekt submitCallback={submitCallback} inntektKontrollperioder={inntekt?.kontrollperioder} /> </Tabs.Panel> <Tabs.Panel value="dagsats">{satserSuccess && <DagsatsOgUtbetaling satser={satser} />}</Tabs.Panel> <Tabs.Panel value="barn"> diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendApiType.ts b/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendApiType.ts index 7720167da9..f3f0c48f55 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendApiType.ts +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendApiType.ts @@ -1,5 +1,6 @@ -import type { UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/generated'; +import type { KontrollerInntektDto, UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/generated'; export type UngBeregningBackendApiType = { getSatser(behandlingUuid: string): Promise<UngdomsytelseSatsPeriodeDto[]>; + getKontrollerInntekt(behandlingUuid: string): Promise<KontrollerInntektDto>; }; diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendClient.ts b/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendClient.ts index 72477d1704..0d5e823ceb 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendClient.ts +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregningBackendClient.ts @@ -1,4 +1,8 @@ -import type { UngSakClient, UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/generated'; +import type { + KontrollerInntektDto, + UngSakClient, + UngdomsytelseSatsPeriodeDto, +} from '@k9-sak-web/backend/ungsak/generated'; export default class UngBeregningBackendClient { #ungsak: UngSakClient; @@ -10,4 +14,8 @@ export default class UngBeregningBackendClient { async getSatser(behandlingUuid: string): Promise<UngdomsytelseSatsPeriodeDto[]> { return this.#ungsak.ung.getUngdomsytelseInnvilgetSats(behandlingUuid); } + + async getKontrollerInntekt(behandlingUuid: string): Promise<KontrollerInntektDto> { + return this.#ungsak.kontroll.hentKontrollerInntekt(behandlingUuid); + } } diff --git a/packages/v2/gui/src/shared/periodLabel/PeriodLabel.tsx b/packages/v2/gui/src/shared/periodLabel/PeriodLabel.tsx new file mode 100644 index 0000000000..6a4400ca0f --- /dev/null +++ b/packages/v2/gui/src/shared/periodLabel/PeriodLabel.tsx @@ -0,0 +1,35 @@ +interface OwnProps { + dateStringFom: string; + dateStringTom?: string; + showTodayString?: boolean; +} + +const formatDate = (date: Date) => { + const options: Intl.DateTimeFormatOptions = { day: '2-digit', month: '2-digit', year: 'numeric' }; + return new Intl.DateTimeFormat('nb-NO', options).format(date); +}; + +/** + * PeriodLabel + * + * Presentasjonskomponent. Formaterer til og fra dato til en periode på formatet dd.mm.yyyy - dd.mm.yyyy. + * + * Eksempel: + * ```html + * <PeriodLabel dateStringFom="2017-08-25" dateStringTom="2017-08-31" /> + * ``` + */ +const PeriodLabel = ({ dateStringFom, dateStringTom, showTodayString = false }: OwnProps) => ( + <span> + {formatDate(new Date(dateStringFom))} + {dateStringTom && ( + <> + {' - '} + {formatDate(new Date(dateStringTom))} + </> + )} + {showTodayString && !dateStringTom && <span>d.d.</span>} + </span> +); + +export default PeriodLabel; diff --git a/packages/v2/gui/src/utils/formatters.ts b/packages/v2/gui/src/utils/formatters.ts index de98e8e33f..f9ac494c22 100644 --- a/packages/v2/gui/src/utils/formatters.ts +++ b/packages/v2/gui/src/utils/formatters.ts @@ -5,3 +5,8 @@ export const tilNOK = Intl.NumberFormat('no-NO', { style: 'currency', currency: export const stdDato = (input: dayjs.Dayjs | string | Date) => dayjs(input).format('YYYY-MM-DD'); export const visnDato = (input: dayjs.Dayjs | string | Date) => dayjs(input).format('DD.MM.YYYY'); + +export const formatCurrencyWithKr = (value: string | number) => { + const formattedValue = Number(value).toLocaleString('nb-NO').replace(/,|\s/g, ' '); + return `${formattedValue} kr`; +}; diff --git a/yarn.lock b/yarn.lock index 7639c8dd51..a75e644359 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3903,7 +3903,7 @@ __metadata: dependencies: "@navikt/k9-klage-typescript-client": "npm:2.0.20250218125133" "@navikt/k9-sak-typescript-client": "npm:2.0.20250306092710" - "@navikt/ung-sak-typescript-client": "npm:0.2.20250221104339" + "@navikt/ung-sak-typescript-client": "npm:0.2.20250320091618" "@tanstack/eslint-plugin-query": "npm:^5.68.0" languageName: unknown linkType: soft @@ -5334,10 +5334,10 @@ __metadata: languageName: node linkType: hard -"@navikt/ung-sak-typescript-client@npm:0.2.20250221104339": - version: 0.2.20250221104339 - resolution: "@navikt/ung-sak-typescript-client@npm:0.2.20250221104339::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fung-sak-typescript-client%2F0.2.20250221104339%2F6d5a1d86cf5f69b9fe82e90be8bab02d18f46cf3" - checksum: 10/c999af5284aa43d6a98ebf4582fa54407bb0ba88bb2ae08ba66708f2ff05d7ed20bb2b9bd0166215c384d8a8fe36544817e28685a6467dcd99588f8b48bc639e +"@navikt/ung-sak-typescript-client@npm:0.2.20250320091618": + version: 0.2.20250320091618 + resolution: "@navikt/ung-sak-typescript-client@npm:0.2.20250320091618::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fung-sak-typescript-client%2F0.2.20250320091618%2F3ddd9866a18f38e7d06a071382fa7afe544c65ee" + checksum: 10/4c8292ead715e468d45df11c10b9845663a3e5ad5fd2871b350b25ee44d0a58fc674958f7719cba141276ed374ae3b67e5a975370d3cfdd9865fc773a00b2cc7 languageName: node linkType: hard From 2e406d49a5ad7f3819b94d84b168702ff2adf7a1 Mon Sep 17 00:00:00 2001 From: Hallvard Andreas Stark <hallvard@scel.to> Date: Fri, 21 Mar 2025 11:01:04 +0100 Subject: [PATCH 3/5] Forbedret story Diverse styling --- .../prosess/ung-beregning/ArbeidOgInntekt.tsx | 37 +++++++++++---- .../prosess/ung-beregning/UngBeregning.tsx | 25 ++++++++-- .../mocks/FakeUngBeregningBackendApi.ts | 47 ++++++++++++++++++- 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx b/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx index d98d83f4eb..d22454c251 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/ArbeidOgInntekt.tsx @@ -5,7 +5,7 @@ import { type RapportertInntektDto, } from '@k9-sak-web/backend/ungsak/generated'; import { CheckmarkCircleFillIcon, ExclamationmarkTriangleFillIcon, PersonIcon } from '@navikt/aksel-icons'; -import { Bleed, BodyLong, Box, Button, Heading, HStack, Table, VStack } from '@navikt/ds-react'; +import { Bleed, BodyLong, BodyShort, Box, Button, Heading, HStack, Label, Table, VStack } from '@navikt/ds-react'; import { Form, InputField, RadioGroupPanel, TextAreaField } from '@navikt/ft-form-hooks'; import { minLength, required } from '@navikt/ft-form-validators'; import { useForm } from 'react-hook-form'; @@ -17,6 +17,13 @@ const formaterInntekt = (inntekt: RapportertInntektDto) => { return formatCurrencyWithKr((inntekt.arbeidsinntekt ?? 0) + (inntekt.ytelse ?? 0)); }; +const formaterStatus = (status?: KontrollerInntektPeriodeDtoStatus) => { + if (status === KontrollerInntektPeriodeDtoStatus.AVVIK) { + return 'Avvik'; + } + return 'Ingen avvik'; +}; + type Formvalues = { fastsattArbeidsinntekt: string; fastsattYtelse: string; @@ -145,14 +152,16 @@ export const ArbeidOgInntekt = ({ submitCallback, inntektKontrollperioder }: Arb <Table.Header> <Table.Row> <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> - Status + <Label size="small">Status</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Periode</Label> </Table.HeaderCell> - <Table.HeaderCell scope="col">Periode</Table.HeaderCell> <Table.HeaderCell scope="col" align="right"> - Rapportert av deltager + <Label size="small">Rapportert av deltager</Label> </Table.HeaderCell> <Table.HeaderCell scope="col" align="right"> - Rapportert i A-inntekt + <Label size="small">Rapportert i A-inntekt</Label> </Table.HeaderCell> <Table.HeaderCell /> </Table.Row> @@ -162,6 +171,7 @@ export const ArbeidOgInntekt = ({ submitCallback, inntektKontrollperioder }: Arb const isLastRow = index === inntektKontrollperioder.length - 1; const harAksjonspunkt = inntekt.erTilVurdering; const harAvvik = inntekt.status === KontrollerInntektPeriodeDtoStatus.AVVIK; + return ( <Table.ExpandableRow key={`${inntekt.periode?.fom}_${inntekt.periode?.tom}`} @@ -172,25 +182,32 @@ export const ArbeidOgInntekt = ({ submitCallback, inntektKontrollperioder }: Arb expansionDisabled={!harAksjonspunkt} > <Table.DataCell className={styles.firstDataCell}> - <HStack gap="2"> + <HStack gap="2" align="center"> {harAvvik ? ( <ExclamationmarkTriangleFillIcon fontSize="1.5rem" className={styles.exclamationmarkIcon} /> ) : ( <CheckmarkCircleFillIcon fontSize={24} className={styles.checkmarkIcon} /> )} - {inntekt.status} + <BodyShort size="small">{formaterStatus(inntekt.status)}</BodyShort> </HStack> </Table.DataCell> <Table.DataCell> {inntekt.periode && ( - <PeriodLabel dateStringFom={inntekt.periode?.fom} dateStringTom={inntekt.periode?.tom} /> + <BodyShort size="small"> + <PeriodLabel dateStringFom={inntekt.periode?.fom} dateStringTom={inntekt.periode?.tom} /> + </BodyShort> )} </Table.DataCell> <Table.DataCell align="right"> - {inntekt.rapporterteInntekter?.bruker && formaterInntekt(inntekt.rapporterteInntekter?.bruker)} + <BodyShort size="small"> + {inntekt.rapporterteInntekter?.bruker && formaterInntekt(inntekt.rapporterteInntekter?.bruker)} + </BodyShort> </Table.DataCell> <Table.DataCell align="right"> - {inntekt.rapporterteInntekter?.register && formaterInntekt(inntekt.rapporterteInntekter?.register)} + <BodyShort size="small"> + {inntekt.rapporterteInntekter?.register && + formaterInntekt(inntekt.rapporterteInntekter?.register)} + </BodyShort> </Table.DataCell> </Table.ExpandableRow> ); diff --git a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx index fd86650f55..e8708e9d75 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/UngBeregning.tsx @@ -1,4 +1,4 @@ -import { type UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/generated'; +import { type KontrollerInntektDto, type UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/generated'; import { Alert, Box, Heading, Loader, Tabs } from '@navikt/ds-react'; import { useQuery } from '@tanstack/react-query'; import { ArbeidOgInntekt } from './ArbeidOgInntekt'; @@ -17,6 +17,20 @@ interface Props { const sortSatser = (data: UngdomsytelseSatsPeriodeDto[]) => data?.toSorted((a, b) => new Date(a.fom).getTime() - new Date(b.fom).getTime()).toReversed(); +const sortInntekt = (data: KontrollerInntektDto): KontrollerInntektDto => { + const { kontrollperioder } = data; + return { + kontrollperioder: kontrollperioder + ?.toSorted((a, b) => { + if (!a.periode || !b.periode) { + return 0; + } + return new Date(a.periode.fom).getTime() - new Date(b.periode.fom).getTime(); + }) + .toReversed(), + }; +}; + const UngBeregning = ({ api, behandling, barn, submitCallback }: Props) => { const { data: satser, @@ -29,16 +43,21 @@ const UngBeregning = ({ api, behandling, barn, submitCallback }: Props) => { select: sortSatser, }); - const { data: inntekt, isLoading: kontrollInntektIsLoading } = useQuery({ + const { + data: inntekt, + isLoading: kontrollInntektIsLoading, + isError: kontrollInntektIsError, + } = useQuery({ queryKey: ['kontrollInntekt', behandling.uuid], queryFn: () => api.getKontrollerInntekt(behandling.uuid), + select: sortInntekt, }); if (satserIsLoading || kontrollInntektIsLoading) { return <Loader size="large" />; } - if (satserIsError) { + if (satserIsError || kontrollInntektIsError) { return <Alert variant="error">Noe gikk galt, vennligst prøv igjen senere</Alert>; } diff --git a/packages/v2/gui/src/storybook/mocks/FakeUngBeregningBackendApi.ts b/packages/v2/gui/src/storybook/mocks/FakeUngBeregningBackendApi.ts index 10f563973b..aa28a69727 100644 --- a/packages/v2/gui/src/storybook/mocks/FakeUngBeregningBackendApi.ts +++ b/packages/v2/gui/src/storybook/mocks/FakeUngBeregningBackendApi.ts @@ -1,4 +1,8 @@ -import type { UngdomsytelseSatsPeriodeDto } from '@k9-sak-web/backend/ungsak/generated'; +import { + KontrollerInntektPeriodeDtoStatus, + type KontrollerInntektDto, + type UngdomsytelseSatsPeriodeDto, +} from '@k9-sak-web/backend/ungsak/generated'; export class FakeUngBeregningBackendApi { async getSatser(): Promise<UngdomsytelseSatsPeriodeDto[]> { @@ -15,4 +19,45 @@ export class FakeUngBeregningBackendApi { }, ]; } + + async getKontrollerInntekt(): Promise<KontrollerInntektDto> { + return { + kontrollperioder: [ + { + erTilVurdering: false, + fastsattArbeidsinntekt: 123, + fastsattYtelse: 456, + periode: { fom: '2025-01-01', tom: '2025-01-31' }, + rapporterteInntekter: { + bruker: { + arbeidsinntekt: 123, + ytelse: 456, + }, + register: { + arbeidsinntekt: 123, + ytelse: 456, + }, + }, + status: KontrollerInntektPeriodeDtoStatus.INGEN_AVVIK, + }, + { + erTilVurdering: true, + fastsattArbeidsinntekt: 5000, + fastsattYtelse: 2500, + periode: { fom: '2025-02-01', tom: '2025-02-28' }, + rapporterteInntekter: { + bruker: { + arbeidsinntekt: 4800, + ytelse: 2600, + }, + register: { + arbeidsinntekt: 5200, + ytelse: 2400, + }, + }, + status: KontrollerInntektPeriodeDtoStatus.AVVIK, + }, + ], + }; + } } From 60b695de45361d2ef398c6b3443b3fcef5d9e890 Mon Sep 17 00:00:00 2001 From: Hallvard Andreas Stark <hallvard@scel.to> Date: Fri, 21 Mar 2025 11:55:37 +0100 Subject: [PATCH 4/5] Ztyling --- .../ung-beregning/DagsatsOgUtbetaling.tsx | 62 ++++++++++++++----- .../src/prosess/ung-beregning/DataSection.tsx | 6 +- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx b/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx index fbff4246bc..376bc1b3ac 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/DagsatsOgUtbetaling.tsx @@ -3,7 +3,7 @@ import { type UngdomsytelseSatsPeriodeDto, } from '@k9-sak-web/backend/ungsak/generated'; import { formatPeriod } from '@k9-sak-web/lib/dateUtils/dateUtils.js'; -import { Box, Heading, Table, Tooltip, VStack } from '@navikt/ds-react'; +import { BodyShort, Box, Heading, Label, Table, Tooltip, VStack } from '@navikt/ds-react'; import { DataSection } from './DataSection'; import styles from './dagsatsOgUtbetaling.module.css'; @@ -61,17 +61,35 @@ export const DagsatsOgUtbetaling = ({ satser }: DagsatsOgUtbetalingProps) => ( <Table.Header> <Table.Row> <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> - Periode + <Label size="small">Periode</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Sats</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Grunnbeløp</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Dagsats</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Antall barn</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Barnetillegg</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Rapportert inntekt</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Dager</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Utbetaling</Label> + </Table.HeaderCell> + <Table.HeaderCell scope="col"> + <Label size="small">Status</Label> </Table.HeaderCell> - <Table.HeaderCell scope="col">Sats</Table.HeaderCell> - <Table.HeaderCell scope="col">Grunnbeløp</Table.HeaderCell> - <Table.HeaderCell scope="col">Dagsats</Table.HeaderCell> - <Table.HeaderCell scope="col">Antall barn</Table.HeaderCell> - <Table.HeaderCell scope="col">Barnetillegg</Table.HeaderCell> - <Table.HeaderCell scope="col">Rapportert inntekt</Table.HeaderCell> - <Table.HeaderCell scope="col">Dager</Table.HeaderCell> - <Table.HeaderCell scope="col">Utbetaling</Table.HeaderCell> - <Table.HeaderCell scope="col">Status</Table.HeaderCell> <Table.HeaderCell /> </Table.Row> </Table.Header> @@ -87,14 +105,24 @@ export const DagsatsOgUtbetaling = ({ satser }: DagsatsOgUtbetalingProps) => ( expandOnRowClick > <Table.DataCell className={styles.firstHeaderCell}> - {fom && tom && formatPeriod(fom, tom)} + <BodyShort size="small">{fom && tom && formatPeriod(fom, tom)}</BodyShort> + </Table.DataCell> + <Table.DataCell> + <BodyShort size="small">{formatSats(satsType)}</BodyShort> + </Table.DataCell> + <Table.DataCell> + <BodyShort size="small">{grunnbeløp && formatCurrencyWithKr(grunnbeløp)}</BodyShort> + </Table.DataCell> + <Table.DataCell> + <BodyShort size="small">{dagsats && formatCurrencyNoKr(dagsats)} kr</BodyShort> + </Table.DataCell> + <Table.DataCell> + <BodyShort size="small">{antallBarn}</BodyShort> </Table.DataCell> - <Table.DataCell>{formatSats(satsType)}</Table.DataCell> - <Table.DataCell>{grunnbeløp && formatCurrencyWithKr(grunnbeløp)}</Table.DataCell> - <Table.DataCell>{dagsats && formatCurrencyNoKr(dagsats)} kr</Table.DataCell> - <Table.DataCell>{antallBarn}</Table.DataCell> <Table.DataCell> - {dagsatsBarnetillegg ? `${formatCurrencyNoKr(dagsatsBarnetillegg)} kr` : null} + <BodyShort size="small"> + {dagsatsBarnetillegg ? `${formatCurrencyNoKr(dagsatsBarnetillegg)} kr` : null} + </BodyShort> </Table.DataCell> <Table.DataCell /> <Table.DataCell /> diff --git a/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx b/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx index ac8cbb7b4c..f928a8ee63 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/DataSection.tsx @@ -92,8 +92,8 @@ export const DataSection = () => { <CalendarIcon color="#417DA0" fontSize="1.5rem" /> <Label as="p">Dager i ungdomsprogram</Label> </HStack> - <HStack gap="2"> - <BodyShort>Dager utbetalt</BodyShort> + <HStack gap="2" align="center"> + <BodyShort size="small">Dager utbetalt</BodyShort> <HelpText title="Forklaringstekst">Forklaring om dager utbetalt her</HelpText> </HStack> <div> @@ -113,7 +113,7 @@ export const DataSection = () => { <SackKronerIcon color="#417DA0" fontSize="1.5rem" /> <Label as="p">Siste utbetaling</Label> </HStack> - <BodyShort>0 kr</BodyShort> + <BodyShort size="small">0 kr</BodyShort> <BodyShort size="small"> {new Date().toLocaleDateString('nb-NO', { day: 'numeric', month: 'long' })} til kontonummer xxx </BodyShort> From ae700e67ae29843452dc7d8dfb1833cfea450e6d Mon Sep 17 00:00:00 2001 From: Hallvard Andreas Stark <hallvard@scel.to> Date: Fri, 21 Mar 2025 12:05:53 +0100 Subject: [PATCH 5/5] Ztyling --- .../src/prosess/ung-beregning/BarnPanel.tsx | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx b/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx index bc5622675f..073e85693f 100644 --- a/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx +++ b/packages/v2/gui/src/prosess/ung-beregning/BarnPanel.tsx @@ -1,4 +1,4 @@ -import { Box, Table } from '@navikt/ds-react'; +import { BodyShort, Box, Label, Table } from '@navikt/ds-react'; import styles from './barn.module.css'; import type { Barn } from './types/Barn'; @@ -14,10 +14,16 @@ export const BarnPanel = ({ barn }: Props) => { <Table.Header> <Table.Row> <Table.HeaderCell scope="col" className={styles.firstHeaderCell}> - Navn + <Label size="small">Navn</Label> </Table.HeaderCell> - <Table.HeaderCell scope="col">Fødselsdato</Table.HeaderCell> - {harBarnMedDødsdato && <Table.HeaderCell scope="col">Dødsdato</Table.HeaderCell>} + <Table.HeaderCell scope="col"> + <Label size="small">Fødselsdato</Label> + </Table.HeaderCell> + {harBarnMedDødsdato && ( + <Table.HeaderCell scope="col"> + <Label size="small">Dødsdato</Label> + </Table.HeaderCell> + )} </Table.Row> </Table.Header> <Table.Body> @@ -25,9 +31,17 @@ export const BarnPanel = ({ barn }: Props) => { const isLastRow = index === barn.length - 1; return ( <Table.Row key={navn} className={isLastRow ? styles.lastRow : ''}> - <Table.DataCell className={styles.firstHeaderCell}>{navn}</Table.DataCell> - <Table.DataCell>{fødselsdato}</Table.DataCell> - {harBarnMedDødsdato && <Table.DataCell>{dødsdato}</Table.DataCell>} + <Table.DataCell className={styles.firstHeaderCell}> + <BodyShort size="small">{navn}</BodyShort> + </Table.DataCell> + <Table.DataCell> + <BodyShort size="small">{fødselsdato}</BodyShort> + </Table.DataCell> + {harBarnMedDødsdato && ( + <Table.DataCell> + <BodyShort size="small">{dødsdato}</BodyShort> + </Table.DataCell> + )} </Table.Row> ); })}