Skip to content

Commit

Permalink
Merge branch 'main' into kontantstøttePerioder
Browse files Browse the repository at this point in the history
  • Loading branch information
throndi committed Jan 29, 2025
2 parents cee2cf8 + 262c88d commit 3b2d9c5
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { UttrekkArbeidssøkerSide } from './Komponenter/Uttrekk/UttrekkArbeidss
import { VelgPersonOgStønadstypeSide } from './Komponenter/Behandling/Førstegangsbehandling/VelgPersonOgStønadstypeSide';
import { OpprettFørstegangsbehandlingSide } from './Komponenter/Behandling/Førstegangsbehandling/OpprettFørstegangsbehandlingSide';
import { UlagretDataModal } from './Felles/Modal/UlagretDataModal';
import { VerktøySide } from './Komponenter/Verktøy/VerktøySide';

export const App: React.FC = () => {
const [innloggetSaksbehandler, settInnloggetSaksbehandler] = useState<ISaksbehandler>();
Expand Down Expand Up @@ -87,6 +88,7 @@ const AppRoutes: React.FC<{ innloggetSaksbehandler: ISaksbehandler }> = ({
<Route path="/admin/*" element={<AdminSide />} />
<Route path="/fagsak/:fagsakId" element={<FagsakTilFagsakPersonRedirect />} />
<Route path="/person/:fagsakPersonId/*" element={<PersonOversiktSide />} />
<Route path="/verktoy/*" element={<VerktøySide />} />
<Route path="/uttrekk/arbeidssoker" element={<UttrekkArbeidssøkerSide />} />
<Route
path={`/opprett-forstegangsbehandling`}
Expand Down
3 changes: 1 addition & 2 deletions src/frontend/App/context/toggles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export enum ToggleName {

// Release-toggles
konvertereDelmalblokkTilHtmlFelt = 'familie.ef.sak.konverter-delmalblokk-til-html-input',
visSamværskalkulator = 'familie.ef.sak.frontend-vis-samverskalkulator',
visMarkereGodkjenneVedtakOppgaveModal = 'familie.ef.sak.vis-markere-godkjenne-vedtak-oppgave-modal',

// Midlertidige toggles - kan fjernes etterhvert
}
249 changes: 249 additions & 0 deletions src/frontend/Felles/Kalkulator/SamværKalkulator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
import React, { ChangeEvent, useState } from 'react';
import {
BodyShort,
Checkbox,
CheckboxGroup,
Heading,
HStack,
Label,
Select,
VStack,
} from '@navikt/ds-react';
import styled from 'styled-components';
import { ABorderDivider, ASurfaceInfoSubtle } from '@navikt/ds-tokens/dist/tokens';

const Div = styled.div`
height: 1.25rem;
`;

const Filler = styled.div`
height: 1.5rem;
`;

const Flexbox = styled.div`
display: flex;
justify-self: center;
width: 2.5rem;
`;

const Valgmuligheter = styled(VStack)`
margin-right: 0.5rem;
`;

const StyledSelect = styled(Select)`
width: 10rem;
`;

const BeregningslengdeContainer = styled.div`
padding: 1rem 1.5rem 1.5rem 1.5rem;
background: ${ASurfaceInfoSubtle};
`;

const UkeContainer = styled(HStack)<{ $border: boolean }>`
border-right: ${(props) => props.$border && `2px solid ${ABorderDivider}`};
margin-bottom: 2rem;
`;

export const SamværKalkulator: React.FC = () => {
const [samværsandelerPerUke, settSamværsandelerPerUke] = useState<number[][]>(
initierSamværState(Beregningsperiode.TO_UKER)
);

const oppdaterSamværsandeler = (uke: number, dag: number, samvær: number) => {
settSamværsandelerPerUke((prevState) => [
...prevState.slice(0, uke),
[...prevState[uke].slice(0, dag), samvær, ...prevState[uke].slice(dag + 1)],
...prevState.slice(uke + 1),
]);
};

const oppdaterBeregningsperiode = (periode: Beregningsperiode) => {
const antallUkerForNåværendeBeregningsperiode = samværsandelerPerUke.length;
const antallUkerForNyBeregningsperiode = samværsperiodeTilAntallUker[periode];

if (antallUkerForNyBeregningsperiode > antallUkerForNåværendeBeregningsperiode) {
settSamværsandelerPerUke((prevState) => [
...prevState.slice(0, antallUkerForNåværendeBeregningsperiode),
...new Array(
antallUkerForNyBeregningsperiode - antallUkerForNåværendeBeregningsperiode
)
.fill(0)
.map((): number[] => new Array(7).fill(0)),
]);
} else {
settSamværsandelerPerUke((prevState) => [
...prevState.slice(0, antallUkerForNyBeregningsperiode),
]);
}
};

return (
<VStack gap="4">
<BeregningslengdeSelect oppdaterBeregningsperiode={oppdaterBeregningsperiode} />
<HStack gap="4">
{samværsandelerPerUke.map((ukeSamvær, index) => (
<Uke
key={index}
index={index}
ukeSamvær={ukeSamvær}
oppdaterSamværState={(dag: number, samvær: number) =>
oppdaterSamværsandeler(index, dag, samvær)
}
visValgmuligheter={index % 4 === 0}
/>
))}
</HStack>
<Oppsummering samværsandelerPerUke={samværsandelerPerUke} />
</VStack>
);
};

const Uke: React.FC<{
ukeSamvær: number[];
index: number;
oppdaterSamværState: (uke: number, samvær: number) => void;
visValgmuligheter: boolean;
}> = ({ ukeSamvær, index, oppdaterSamværState, visValgmuligheter }) => {
return (
<UkeContainer gap="1" $border={(index + 1) % 4 !== 0}>
{visValgmuligheter && (
<Valgmuligheter gap="6">
<Div />
{valgmuligheter.map((valgmulighet) => (
<Label key={valgmulighet.label}>{valgmulighet.label}</Label>
))}
</Valgmuligheter>
)}
{ukeSamvær.map((dagSamvær, index) => {
const ukedag = ukedager[index];

return (
<Ukedag
key={ukedag + index}
identifier={ukedag + index}
samvær={dagSamvær}
ukedag={ukedag}
oppdaterSamværState={(samvær: number) => oppdaterSamværState(index, samvær)}
/>
);
})}
</UkeContainer>
);
};

const Ukedag: React.FC<{
identifier: string;
samvær: number;
ukedag: string;
oppdaterSamværState: (samvær: number) => void;
}> = ({ samvær, ukedag, identifier, oppdaterSamværState }) => {
const oppdaterSamvær = (samvær: { id: number; value: number }[]) => {
const samværForUkedag = utledSamværForUkedag(samvær);
oppdaterSamværState(samværForUkedag);
};

const visningstekst = `${samvær}/8`;

return (
<VStack>
<CheckboxGroup legend={ukedag} onChange={oppdaterSamvær}>
{valgmuligheter.map((valgOption, index) => (
<Checkbox key={identifier + index} value={valgOption.value}>
{''}
</Checkbox>
))}
</CheckboxGroup>
<Flexbox>{samvær > 0 ? <BodyShort>{visningstekst}</BodyShort> : <Filler />}</Flexbox>
</VStack>
);
};

const BeregningslengdeSelect: React.FC<{
oppdaterBeregningsperiode: (periode: Beregningsperiode) => void;
}> = ({ oppdaterBeregningsperiode }) => (
<BeregningslengdeContainer>
<StyledSelect
label="Beregningslengde"
onChange={(event: ChangeEvent<HTMLSelectElement>) =>
oppdaterBeregningsperiode(event.target.value as Beregningsperiode)
}
>
{Object.values(Beregningsperiode).map((samværsperiode) => (
<option key={samværsperiode} value={samværsperiode}>
{samværsperiodeTilTekst[samværsperiode]}
</option>
))}
</StyledSelect>
</BeregningslengdeContainer>
);

const Oppsummering: React.FC<{ samværsandelerPerUke: number[][] }> = ({ samværsandelerPerUke }) => {
const summertSamvær = samværsandelerPerUke
.flatMap((andeler) => andeler)
.reduce((acc, andel) => acc + andel);

const maksimalSamværsandel = samværsandelerPerUke.length * 7 * 8;

const antallHeleDagerMedSamvær = Math.floor(summertSamvær / 8);

const rest = summertSamvær % 8;
const restSuffix = rest === 0 ? '' : '/8';

const prosentandel = summertSamvær / maksimalSamværsandel;

const visningstekstAntallDager = `${antallHeleDagerMedSamvær} dager og ${rest}${restSuffix} deler`;
const visningstekstProsentandel = `${Math.round(prosentandel * 1000) / 10}%`;

return (
<BeregningslengdeContainer>
<Heading size="medium">Total:</Heading>
<BodyShort size="large">{visningstekstAntallDager}</BodyShort>
<BodyShort size="large">{visningstekstProsentandel}</BodyShort>
</BeregningslengdeContainer>
);
};

const utledSamværForUkedag = (verdier: { id: number; value: number }[]): number => {
if (verdier.length === 0) {
return 0;
}
return verdier.map((verdi) => Number(verdi.value)).reduce((acc, verdi) => acc + verdi);
};

enum Beregningsperiode {
TO_UKER = 'TO_UKER',
FIRE_UKER = 'FIRE_UKER',
SEKS_UKER = 'SEKS_UKER',
ÅTTE_UKER = 'ÅTTE_UKER',
TOLV_UKER = 'TOLV_UKER',
}

const initierSamværState = (periode: Beregningsperiode): number[][] => {
const antallUker = samværsperiodeTilAntallUker[periode];
return new Array(antallUker).fill(0).map((): number[] => new Array(7).fill(0));
};

const samværsperiodeTilAntallUker: Record<Beregningsperiode, number> = {
TO_UKER: 2,
FIRE_UKER: 4,
SEKS_UKER: 6,
ÅTTE_UKER: 8,
TOLV_UKER: 12,
};

const samværsperiodeTilTekst: Record<Beregningsperiode, string> = {
TO_UKER: '2 uker',
FIRE_UKER: '4 uker',
SEKS_UKER: '6 uker',
ÅTTE_UKER: '8 uker',
TOLV_UKER: '12 uker',
};

const ukedager = ['Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør', 'Søn'];

const valgmuligheter = [
{ label: 'Morgen før bhg/skole (1/8)', value: { id: 1, value: 1 } },
{ label: 'Tiden i bhg/skole (2/8)', value: { id: 2, value: 2 } },
{ label: 'Ettermiddag etter bhg/skole (1/8)', value: { id: 3, value: 1 } },
{ label: 'Kveld/natt (4/8)', value: { id: 4, value: 4 } },
];
18 changes: 18 additions & 0 deletions src/frontend/Felles/PersonHeader/PersonHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { ABorderStrong } from '@navikt/ds-tokens/dist/tokens';
import Visittkort from './Visittkort';
import PersonTags from './PersonTags';
import BehandlingTags from './BehandlingTags';
import { Button, Dropdown, Link } from '@navikt/ds-react';
import { useToggles } from '../../App/context/TogglesContext';
import { ToggleName } from '../../App/context/toggles';

export const Container = styled(Sticky)`
display: flex;
Expand Down Expand Up @@ -52,6 +55,8 @@ const isBehandlingProps = (props: Props): props is BehandlingProps =>

export const PersonHeader: FC<Props> = (props) => {
const { erSaksbehandler } = useApp();
const { toggles } = useToggles();
const skalViseSamværskalkulator = toggles[ToggleName.visSamværskalkulator];

const {
personIdent,
Expand Down Expand Up @@ -93,6 +98,7 @@ export const PersonHeader: FC<Props> = (props) => {
vergemål={vergemål}
/>
</FlexContainer>

{harBehandling && (
<FlexContainer>
<BehandlingTags behandling={props.behandling} />
Expand All @@ -102,6 +108,18 @@ export const PersonHeader: FC<Props> = (props) => {
/>
</FlexContainer>
)}
{!harBehandling && skalViseSamværskalkulator && (
<Dropdown>
<Button as={Dropdown.Toggle}>Samværskalkulator</Button>
<Dropdown.Menu>
<Dropdown.Menu.List>
<Dropdown.Menu.List.Item as={Link} href="/verktoy/samver">
Samværskalkulator
</Dropdown.Menu.List.Item>
</Dropdown.Menu.List>
</Dropdown.Menu>
</Dropdown>
)}
</Container>
);
};
6 changes: 6 additions & 0 deletions src/frontend/Komponenter/Verktøy/SamværkalkulatorSide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { SamværKalkulator } from '../../Felles/Kalkulator/SamværKalkulator';

export const SamværkalkulatorSide: React.FC = () => {
return <SamværKalkulator />;
};
18 changes: 18 additions & 0 deletions src/frontend/Komponenter/Verktøy/VerktøySide.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import styled from 'styled-components';
import { Route, Routes } from 'react-router-dom';
import { SamværkalkulatorSide } from './SamværkalkulatorSide';

const Container = styled.div`
padding: 2rem;
`;

export const VerktøySide: React.FC = () => {
return (
<Container>
<Routes>
<Route path="samver" element={<SamværkalkulatorSide />} />
</Routes>
</Container>
);
};
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8294,9 +8294,9 @@ vite-node@2.1.8:
vite "^5.0.0"

vite@^5.0.0:
version "5.4.11"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.11.tgz#3b415cd4aed781a356c1de5a9ebafb837715f6e5"
integrity sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==
version "5.4.14"
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.14.tgz#ff8255edb02134df180dcfca1916c37a6abe8408"
integrity sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==
dependencies:
esbuild "^0.21.3"
postcss "^8.4.43"
Expand Down

0 comments on commit 3b2d9c5

Please sign in to comment.