diff --git a/.storybook/main.js b/.storybook/main.js
index 314821a26c..9995ece860 100644
--- a/.storybook/main.js
+++ b/.storybook/main.js
@@ -21,6 +21,7 @@ module.exports = {
// ref: https://medium.com/storybookjs/storybook-6-migration-guide-200346241bb5
// '@storybook/addon-essentials',
],
+ staticDirs: ['../public'],
// reactOptions: {
// fastRefresh: true,
@@ -75,6 +76,11 @@ module.exports = {
include: [PACKAGES_DIR],
exclude: [CSS_DIR],
},
+ {
+ test: /\.css$/,
+ use: ['postcss-loader'],
+ include: [CSS_DIR],
+ },
{
test: /\.less$/,
use: [
@@ -100,7 +106,7 @@ module.exports = {
},
},
],
- include: [CSS_DIR, NODE_MODULES],
+ include: [NODE_MODULES],
},
{
test: /\.(jp|pn|sv)g$/,
diff --git a/.storybook/preview.js b/.storybook/preview.js
index c41421b045..1c2006ddcb 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,12 +1,16 @@
-import React from 'react';
import '@formatjs/intl-datetimeformat/polyfill-force';
-import '@formatjs/intl-datetimeformat/locale-data/nb';
import '@formatjs/intl-numberformat/polyfill-force';
+import '@formatjs/intl-datetimeformat/locale-data/nb';
import '@formatjs/intl-numberformat/locale-data/nb';
+import { initialize, mswLoader } from 'msw-storybook-addon';
+import React from 'react';
+import '@navikt/ds-css';
import '@fpsak-frontend/assets/styles/global.css';
import '@navikt/ft-plattform-komponenter/dist/style.css';
-import '@navikt/ds-css';
+initialize({ onUnhandledRequest: 'bypass' });
+
+export const loaders = [mswLoader];
export const decorators = [
Story => (
diff --git a/@types/externals.d.ts b/@types/externals.d.ts
index de6f5bf6ce..a38d7e7dce 100644
--- a/@types/externals.d.ts
+++ b/@types/externals.d.ts
@@ -1,3 +1,4 @@
declare module '*.svg';
declare module '*.less';
declare module '*.css';
+declare module '*.module.css';
diff --git a/deploy/dev-fss-k9saksbehandling.yml b/deploy/dev-fss-k9saksbehandling.yml
index e233a31440..9b602b1f3b 100644
--- a/deploy/dev-fss-k9saksbehandling.yml
+++ b/deploy/dev-fss-k9saksbehandling.yml
@@ -115,3 +115,5 @@ spec:
value: "true"
- name: FAKTA_BEREGNING_REDESIGN
value: "true"
+ - name: NOTAT_I_SAK
+ value: "true"
diff --git a/deploy/prod-fss-k9saksbehandling.yml b/deploy/prod-fss-k9saksbehandling.yml
index 81ccc860cc..0a1595802a 100644
--- a/deploy/prod-fss-k9saksbehandling.yml
+++ b/deploy/prod-fss-k9saksbehandling.yml
@@ -115,3 +115,5 @@ spec:
value: "false"
- name: FAKTA_BEREGNING_REDESIGN
value: "false"
+ - name: NOTAT_I_SAK
+ value: "false"
diff --git a/feature-toggles.json b/feature-toggles.json
index da5bbce04f..cb2e1ae78a 100644
--- a/feature-toggles.json
+++ b/feature-toggles.json
@@ -74,5 +74,9 @@
{
"key": "FAKTA_BEREGNING_REDESIGN",
"value": "${FAKTA_BEREGNING_REDESIGN}"
+ },
+ {
+ "key": "NOTAT_I_SAK",
+ "value": "${NOTAT_I_SAK}"
}
]
diff --git a/package.json b/package.json
index 5b12f607e1..f2b98afa00 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"lint:fix": "eslint --fix --cache packages --ext .ts,.tsx,.js,.jsx",
"css:lint": "stylelint \"packages/**/*.css\"",
"dev": "yarn dev-env-variables cross-env NODE_ENV=development APP_URL_K9FORMIDLING=http://localhost:8060/rest/dummy webpack serve --config webpack/webpack.dev.ts",
- "dev-env-variables": "cross-env KLAGE_KABAL=true VARSELTEKST=true DOKUMENTDATA=true UNNTAKSBEHANDLING=true UTENLANDSOPPHOLD=true SOKNADPERIODESTRIPE=false TYPE_MEDISINSKE_OPPLYSNINGER_BREV=true LOS_MARKER_BEHANDLING=true LOS_MARKER_BEHANDLING_SUBMIT=true AKSJONSPUNKT_9014=true AKSJONSPUNKT_9015=true FRITEKST_REDIGERING=true FIX_SOKNADSFRIST_KALENDER_OG_READONLY=true INKLUDER_KALENDER_PILS=true FAKTA_BEREGNING_REDESIGN=true",
+ "dev-env-variables": "cross-env KLAGE_KABAL=true VARSELTEKST=true DOKUMENTDATA=true UNNTAKSBEHANDLING=true UTENLANDSOPPHOLD=true SOKNADPERIODESTRIPE=false TYPE_MEDISINSKE_OPPLYSNINGER_BREV=true LOS_MARKER_BEHANDLING=true LOS_MARKER_BEHANDLING_SUBMIT=true AKSJONSPUNKT_9014=true AKSJONSPUNKT_9015=true FRITEKST_REDIGERING=true FIX_SOKNADSFRIST_KALENDER_OG_READONLY=true INKLUDER_KALENDER_PILS=true FAKTA_BEREGNING_REDESIGN=true NOTAT_I_SAK=true",
"dev-lokal": "cross-env NODE_ENV=development APP_URL_SAK=http://k9-sak:8080 APP_URL_K9OPPDRAG=http://k9-oppdrag:8070 APP_URL_K9FORMIDLING_DD=http://k9-formidling-dokumentdata:8294 APP_URL_K9FORMIDLING=http://k9-formidling:8290 SPLITTET_SAMMENLINGNING_BEREGNING=true webpack serve --config webpack/webpack.dev.ts",
"dev-med-formidling": "cross-env NODE_ENV=development webpack serve --config webpack/webpack.dev.ts",
"build": "cross-env NODE_ENV=production SENTRY_RELEASE=$(git rev-parse --short HEAD) webpack --config webpack/webpack.prod.ts",
@@ -47,7 +47,7 @@
"@navikt/aksel-icons": "5.6.1",
"@navikt/ds-css": "5.6.1",
"@navikt/ds-react": "5.6.1",
- "@navikt/ds-tailwind": "^5.5.0",
+ "@navikt/ds-tailwind": "^5.6.1",
"@navikt/familie-endringslogg": "9.0.3",
"@navikt/ft-plattform-komponenter": "2.3.5",
"@popperjs/core": "2.11.8",
@@ -153,6 +153,7 @@
"lint-staged": "13.3.0",
"mini-css-extract-plugin": "2.7.6",
"msw": "1.3.1",
+ "msw-storybook-addon": "^1.8.0",
"postcss": "^8.4.30",
"prettier": "3.0.3",
"raf": "3.4.1",
diff --git a/packages/sak-app/package.json b/packages/sak-app/package.json
index eae8f47589..d2531a57bc 100644
--- a/packages/sak-app/package.json
+++ b/packages/sak-app/package.json
@@ -46,6 +46,7 @@
"@k9-sak-web/sak-infosider": "1.0.0",
"@k9-sak-web/sak-meldinger": "1.0.0",
"@k9-sak-web/sak-meny-marker-behandling": "1.0.0",
+ "@k9-sak-web/sak-notat": "1.0.0",
"@k9-sak-web/sak-soknadsperiodestripe": "1.0.0",
"@k9-sak-web/types": "1.0.0",
"@navikt/ds-react": "5.6.1",
diff --git a/packages/sak-app/src/app/AppIndex.tsx b/packages/sak-app/src/app/AppIndex.tsx
index d906246f5d..9a7f253324 100644
--- a/packages/sak-app/src/app/AppIndex.tsx
+++ b/packages/sak-app/src/app/AppIndex.tsx
@@ -22,7 +22,6 @@ import '@navikt/ft-form-hooks/dist/style.css';
import '@navikt/ft-plattform-komponenter/dist/style.css';
import '@navikt/ft-prosess-beregningsgrunnlag/dist/style.css';
import '@navikt/ft-ui-komponenter/dist/style.css';
-
import 'nav-datovelger/lib/styles/main.css';
import 'nav-frontend-alertstriper-style/dist/main.css';
import 'nav-frontend-chevron-style/dist/main.css';
diff --git a/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.spec.tsx b/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.spec.tsx
index cbc12e89be..0ba765f4bf 100644
--- a/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.spec.tsx
+++ b/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.spec.tsx
@@ -1,16 +1,17 @@
+import { screen } from '@testing-library/react';
import React from 'react';
-import sinon, { SinonStub } from 'sinon';
-import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
+import sinon, { SinonStub } from 'sinon';
-import { BehandlingAppKontekst, Fagsak } from '@k9-sak-web/types';
import behandlingStatus from '@fpsak-frontend/kodeverk/src/behandlingStatus';
import behandlingType from '@fpsak-frontend/kodeverk/src/behandlingType';
+import { BehandlingAppKontekst, Fagsak } from '@k9-sak-web/types';
-import { VergeBehandlingmenyValg } from '../behandling/behandlingRettigheterTsType';
+import { renderWithReactQueryClient } from '@fpsak-frontend/utils-test/src/test-utils';
import * as useTrackRouteParam from '../app/useTrackRouteParam';
+import { VergeBehandlingmenyValg } from '../behandling/behandlingRettigheterTsType';
+import { K9sakApiKeys, requestApi } from '../data/k9sakApi';
import BehandlingSupportIndex, { hentSynligePaneler, hentValgbarePaneler } from './BehandlingSupportIndex';
-import { requestApi, K9sakApiKeys } from '../data/k9sakApi';
describe('', () => {
const fagsak = {
@@ -66,15 +67,16 @@ describe('', () => {
requestApi.mock(K9sakApiKeys.HISTORY_TILBAKE, []);
requestApi.mock(K9sakApiKeys.HISTORY_KLAGE, []);
- render(
+ renderWithReactQueryClient(
-
+ ,
);
expect(screen.queryAllByTestId('TabMenyKnapp').length).toBe(3);
diff --git a/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.tsx b/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.tsx
index 1af83f6044..3763e22b6b 100644
--- a/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.tsx
+++ b/packages/sak-app/src/behandlingsupport/BehandlingSupportIndex.tsx
@@ -1,9 +1,18 @@
-import React, { useCallback, useMemo } from 'react';
-import { useNavigate } from 'react-router-dom';
-
import SupportMenySakIndex, { SupportTabs } from '@fpsak-frontend/sak-support-meny';
-import { ArbeidsgiverOpplysningerWrapper, BehandlingAppKontekst, Fagsak, Personopplysninger } from '@k9-sak-web/types';
-
+import { httpErrorHandler, useLocalStorage } from '@fpsak-frontend/utils';
+import { useRestApiErrorDispatcher } from '@k9-sak-web/rest-api-hooks';
+import {
+ ArbeidsgiverOpplysningerWrapper,
+ BehandlingAppKontekst,
+ Fagsak,
+ FeatureToggles,
+ NavAnsatt,
+ Personopplysninger,
+} from '@k9-sak-web/types';
+import axios from 'axios';
+import React, { useCallback, useMemo, useState } from 'react';
+import { useQuery } from 'react-query';
+import { useNavigate } from 'react-router-dom';
import { getSupportPanelLocationCreator } from '../app/paths';
import useTrackRouteParam from '../app/useTrackRouteParam';
import BehandlingRettigheter from '../behandling/behandlingRettigheterTsType';
@@ -11,15 +20,21 @@ import styles from './behandlingSupportIndex.module.css';
import DokumentIndex from './dokument/DokumentIndex';
import HistorikkIndex from './historikk/HistorikkIndex';
import MeldingIndex from './melding/MeldingIndex';
+import NotaterIndex from './notater/NotaterIndex';
import TotrinnskontrollIndex from './totrinnskontroll/TotrinnskontrollIndex';
-export const hentSynligePaneler = (behandlingRettigheter?: BehandlingRettigheter): string[] =>
+export const hentSynligePaneler = (
+ behandlingRettigheter?: BehandlingRettigheter,
+ featureToggles?: FeatureToggles,
+): string[] =>
Object.values(SupportTabs).filter(supportPanel => {
switch (supportPanel) {
case SupportTabs.TIL_BESLUTTER:
return behandlingRettigheter && behandlingRettigheter.behandlingTilGodkjenning;
case SupportTabs.FRA_BESLUTTER:
return behandlingRettigheter && behandlingRettigheter.behandlingFraBeslutter;
+ case SupportTabs.NOTATER:
+ return featureToggles?.NOTAT_I_SAK;
default:
return true;
}
@@ -45,6 +60,8 @@ interface OwnProps {
behandlingRettigheter?: BehandlingRettigheter;
personopplysninger?: Personopplysninger;
arbeidsgiverOpplysninger?: ArbeidsgiverOpplysningerWrapper;
+ navAnsatt: NavAnsatt;
+ featureToggles?: FeatureToggles;
}
/**
@@ -61,7 +78,39 @@ const BehandlingSupportIndex = ({
behandlingRettigheter,
personopplysninger,
arbeidsgiverOpplysninger,
+ navAnsatt,
+ featureToggles,
}: OwnProps) => {
+ const { addErrorMessage } = useRestApiErrorDispatcher();
+ const [antallUlesteNotater, setAntallUlesteNotater] = useState(0);
+ const [lesteNotater] = useLocalStorage('lesteNotater', []);
+
+ const getNotater = (signal: AbortSignal) => {
+ axios
+ .get(`/k9/sak/api/notat`, {
+ signal,
+ params: {
+ saksnummer: fagsak.saksnummer,
+ },
+ })
+ .then(response => {
+ const ulesteNotater = response.data.filter(
+ notat => lesteNotater.findIndex(lestNotatId => lestNotatId === notat.notatId) === -1,
+ );
+ setAntallUlesteNotater(ulesteNotater.length);
+ })
+ .catch(error => {
+ httpErrorHandler(error?.response?.status, addErrorMessage, error?.response?.headers?.location);
+ });
+ };
+ const notaterQueryKey = ['notater', fagsak?.saksnummer];
+ useQuery({
+ queryKey: notaterQueryKey,
+ queryFn: ({ signal }) => getNotater(signal),
+ enabled: featureToggles?.NOTAT_I_SAK && !!fagsak,
+ refetchOnWindowFocus: false,
+ });
+
const { selected: valgtSupportPanel, location } = useTrackRouteParam({
paramName: 'stotte',
isQueryParam: true,
@@ -74,7 +123,10 @@ const BehandlingSupportIndex = ({
const erPaVent = behandling ? behandling.behandlingPaaVent : false;
const erSendMeldingRelevant = fagsak && !erPaVent;
- const synligeSupportPaneler = useMemo(() => hentSynligePaneler(behandlingRettigheter), [behandlingRettigheter]);
+ const synligeSupportPaneler = useMemo(
+ () => hentSynligePaneler(behandlingRettigheter, featureToggles),
+ [behandlingRettigheter, featureToggles],
+ );
const valgbareSupportPaneler = useMemo(
() => hentValgbarePaneler(synligeSupportPaneler, erSendMeldingRelevant, behandlingRettigheter),
[synligeSupportPaneler, erSendMeldingRelevant, behandlingRettigheter],
@@ -102,6 +154,7 @@ const BehandlingSupportIndex = ({
valgbareTabs={valgbareSupportPaneler}
valgtIndex={synligeSupportPaneler.findIndex(p => p === aktivtSupportPanel)}
onClick={changeRouteCallback}
+ antallUlesteNotater={antallUlesteNotater}
/>
@@ -139,6 +192,15 @@ const BehandlingSupportIndex = ({
behandlingUuid={behandling?.uuid}
/>
)}
+ {aktivtSupportPanel === SupportTabs.NOTATER && featureToggles?.NOTAT_I_SAK && (
+
+ )}
>
);
diff --git a/packages/sak-app/src/behandlingsupport/notater/NotaterIndex.tsx b/packages/sak-app/src/behandlingsupport/notater/NotaterIndex.tsx
new file mode 100644
index 0000000000..40cb781337
--- /dev/null
+++ b/packages/sak-app/src/behandlingsupport/notater/NotaterIndex.tsx
@@ -0,0 +1,25 @@
+import { LoadingPanel, requireProps } from '@fpsak-frontend/shared-components';
+import Notater from '@k9-sak-web/sak-notat';
+import { FagsakPerson, NavAnsatt } from '@k9-sak-web/types';
+import React from 'react';
+
+interface OwnProps {
+ saksnummer: string;
+ behandlingId?: number;
+ behandlingVersjon?: number;
+ fagsakPerson?: FagsakPerson;
+ navAnsatt: NavAnsatt;
+}
+
+const EMPTY_ARRAY = [];
+
+/**
+ * NotaterIndex
+ *
+ * Container komponent. Har ansvar for å vise notater i saken.
+ */
+export const NotaterIndex = ({ saksnummer, navAnsatt }: OwnProps) => (
+
+);
+
+export default requireProps(['saksnummer'], )(NotaterIndex);
diff --git a/packages/sak-app/src/fagsak/FagsakIndex.spec.tsx b/packages/sak-app/src/fagsak/FagsakIndex.spec.tsx
index a9fd4b2947..2748cea00e 100644
--- a/packages/sak-app/src/fagsak/FagsakIndex.spec.tsx
+++ b/packages/sak-app/src/fagsak/FagsakIndex.spec.tsx
@@ -74,6 +74,7 @@ describe('', () => {
requestApi.mock(K9sakApiKeys.HENT_SAKSBEHANDLERE, {});
requestApi.mock(K9sakApiKeys.FEATURE_TOGGLE, []);
requestApi.mock(K9sakApiKeys.LOS_HENTE_MERKNAD, []);
+ requestApi.mock(K9sakApiKeys.NAV_ANSATT, {});
const wrapper = shallow();
diff --git a/packages/sak-app/src/fagsak/FagsakIndex.tsx b/packages/sak-app/src/fagsak/FagsakIndex.tsx
index 677a7b0934..ea4873ee42 100644
--- a/packages/sak-app/src/fagsak/FagsakIndex.tsx
+++ b/packages/sak-app/src/fagsak/FagsakIndex.tsx
@@ -19,6 +19,7 @@ import {
Kodeverk,
KodeverkMedNavn,
MerknadFraLos,
+ NavAnsatt,
Personopplysninger,
} from '@k9-sak-web/types';
import OvergangFraInfotrygd from '@k9-sak-web/types/src/overgangFraInfotrygd';
@@ -26,6 +27,7 @@ import RelatertFagsak from '@k9-sak-web/types/src/relatertFagsak';
import React, { useCallback, useMemo, useState } from 'react';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import { QueryClient, QueryClientProvider } from 'react-query';
import {
behandlingerRoutePath,
erBehandlingValgt,
@@ -60,6 +62,8 @@ const erOmsorgspenger = (fagsak: Fagsak) =>
fagsakYtelseType.OMSORGSPENGER_MIDLERTIDIG_ALENE,
].includes(fagsak?.sakstype?.kode);
+const queryClient = new QueryClient();
+
/**
* FagsakIndex
*
@@ -207,6 +211,8 @@ const FagsakIndex = () => {
},
);
+ const navAnsatt = restApiHooks.useGlobalStateRestApiData(K9sakApiKeys.NAV_ANSATT);
+
const erHastesak = merknaderFraLos && merknaderFraLos.merknadKoder?.includes(Merknadkode.HASTESAK);
if (!fagsak) {
@@ -273,15 +279,19 @@ const FagsakIndex = () => {
}
return (
-
+
+
+
);
}}
visittkortContent={() => {
diff --git a/packages/sak-notat/i18n/index.js b/packages/sak-notat/i18n/index.js
new file mode 100644
index 0000000000..5509d24218
--- /dev/null
+++ b/packages/sak-notat/i18n/index.js
@@ -0,0 +1,12 @@
+import {
+ intlWithMessages,
+ shallowWithIntl as globalShallowWithIntl,
+} from '@fpsak-frontend/utils-test/src/intl-enzyme-test-helper';
+
+import messages from './nb_NO.json';
+
+const shallowWithIntl = node => globalShallowWithIntl(node, messages);
+
+export const intlMock = intlWithMessages(messages);
+
+export default shallowWithIntl;
diff --git a/packages/sak-notat/i18n/nb_NO.json b/packages/sak-notat/i18n/nb_NO.json
new file mode 100644
index 0000000000..917d29864b
--- /dev/null
+++ b/packages/sak-notat/i18n/nb_NO.json
@@ -0,0 +1,16 @@
+{
+ "NotatISakIndex.VisNotatTilknyttetPleietrengende": "Vis notat i alle saker tilknyttet pleietrengende",
+ "NotatISakIndex.LeggTilNotatButton": "Legg til notat",
+ "NotatISakIndex.IngenNotaterAlert": "Ingen notater er publisert i saken",
+ "NotatISakIndex.NotaterISak": "Notater i sak",
+ "NotatISakIndex.VisSkjulteNotater": "Vis skjulte notater",
+ "NotatISakIndex.SkrivNyttNotat": "Skriv et nytt notat",
+ "NotatISakIndex.Gjelder": "Gjelder:",
+ "NotatISakIndex.Rediger": "Rediger",
+ "NotatISakIndex.SkjulNotat": "Skjul notat",
+ "NotatISakIndex.VisNotat": "Vis notat",
+ "NotatISakIndex.LagreEndringer": "Lagre endringer",
+ "NotatISakIndex.Avbryt": "Avbryt",
+ "NotatISakIndex.NoeGikkGaltHentingNotater": "Noe gikk galt ved henting av notater, vennligst prøv igjen senere",
+ "NotatISakIndex.NoeGikkGaltLagringNotater": "Noe gikk galt ved lagring av notater, vennligst prøv igjen senere"
+}
diff --git a/packages/sak-notat/index.ts b/packages/sak-notat/index.ts
new file mode 100644
index 0000000000..40b2dd2d8b
--- /dev/null
+++ b/packages/sak-notat/index.ts
@@ -0,0 +1 @@
+export { default } from './src/NotaterIndex';
diff --git a/packages/sak-notat/package.json b/packages/sak-notat/package.json
new file mode 100644
index 0000000000..c2362a0bbb
--- /dev/null
+++ b/packages/sak-notat/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "@k9-sak-web/sak-notat",
+ "version": "1.0.0",
+ "module": "index.jsx",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "@fpsak-frontend/utils": "1.0.0",
+ "@k9-sak-web/types": "1.0.0",
+ "@navikt/aksel-icons": "5.6.1",
+ "@navikt/ds-react": "5.6.1",
+ "@navikt/ft-form-hooks": "4.2.7",
+ "@navikt/ft-form-validators": "^2.1.3",
+ "date-fns": "2.30.0",
+ "react": "17.0.2",
+ "react-hook-form": "7.47.0",
+ "react-intl": "6.4.7"
+ }
+}
diff --git a/packages/sak-notat/src/Notater.tsx b/packages/sak-notat/src/Notater.tsx
new file mode 100644
index 0000000000..e0f304746a
--- /dev/null
+++ b/packages/sak-notat/src/Notater.tsx
@@ -0,0 +1,132 @@
+import { NavAnsatt } from '@k9-sak-web/types';
+import { Alert, Button, Heading, Loader, Switch } from '@navikt/ds-react';
+import { CheckboxField, Form, TextAreaField } from '@navikt/ft-form-hooks';
+import React, { useState } from 'react';
+import { UseFormReturn } from 'react-hook-form';
+import { FormattedMessage, RawIntlProvider, createIntl, createIntlCache } from 'react-intl';
+import messages from '../i18n/nb_NO.json';
+import ChatComponent from './components/ChatComponent';
+import { NotatResponse } from './types/NotatResponse';
+import styles from './notater.module.css';
+
+const cache = createIntlCache();
+
+const intl = createIntl(
+ {
+ locale: 'nb-NO',
+ messages,
+ },
+ cache,
+);
+
+export type Inputs = {
+ notatTekst: string;
+ visNotatIAlleSaker: boolean;
+};
+
+export interface skjulNotatMutationVariables {
+ skjul: boolean;
+ id: number;
+ saksnummer: string;
+ versjon: number;
+}
+
+interface NotaterProps {
+ fagsakId: string;
+ navAnsatt: NavAnsatt;
+ submitNotat: (data: Inputs, id?: number, fagsakIdFraRedigertNotat?: string, versjon?: number) => void;
+ submitSkjulNotat: ({ skjul, id, saksnummer, versjon }: skjulNotatMutationVariables) => void;
+ isLoading: boolean;
+ hasGetNotaterError: boolean;
+ notater: NotatResponse[];
+ postNotatMutationError: boolean;
+ formMethods: UseFormReturn;
+}
+
+const Notater: React.FunctionComponent = ({
+ fagsakId,
+ navAnsatt,
+ submitNotat,
+ isLoading,
+ hasGetNotaterError,
+ notater,
+ postNotatMutationError,
+ submitSkjulNotat,
+ formMethods,
+}) => {
+ const [visSkjulteNotater, setVisSkjulteNotater] = useState(false);
+
+ const toggleVisSkjulteNotater = () => {
+ setVisSkjulteNotater(current => !current);
+ };
+
+ const submit = (data: Inputs) => submitNotat(data);
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+ <>
+
+
+
+
+
+
+
+
+ {!hasGetNotaterError && notater?.length === 0 && (
+
+
+
+ )}
+ {hasGetNotaterError && (
+
+
+
+ )}
+ {postNotatMutationError && (
+
+
+
+ )}
+ {notater?.length > 0 && (
+
+ {notater
+ .filter(notat => visSkjulteNotater || !notat.skjult)
+ .map(notat => (
+ submitNotat(data.data, data.id, data.saksnummer, data.versjon)}
+ navAnsatt={navAnsatt}
+ skjulNotat={data => submitSkjulNotat(data)}
+ fagsakId={fagsakId}
+ />
+ ))}
+
+ )}
+
+ >
+ )}
+
+ );
+};
+export default Notater;
diff --git a/packages/sak-notat/src/NotaterIndex.tsx b/packages/sak-notat/src/NotaterIndex.tsx
new file mode 100644
index 0000000000..fb11c051ad
--- /dev/null
+++ b/packages/sak-notat/src/NotaterIndex.tsx
@@ -0,0 +1,125 @@
+import { useLocalStorage } from '@fpsak-frontend/utils';
+import { NavAnsatt } from '@k9-sak-web/types';
+import axios from 'axios';
+import React from 'react';
+import { useForm } from 'react-hook-form';
+import { useMutation, useQuery, useQueryClient } from 'react-query';
+import Notater, { Inputs, skjulNotatMutationVariables } from './Notater';
+import { NotatGjelderType } from './types/NotatGjelderType';
+import { NotatResponse } from './types/NotatResponse';
+
+interface NotaterIndexProps {
+ fagsakId: string;
+ navAnsatt: NavAnsatt;
+}
+
+interface postNotatMutationVariables {
+ data: Inputs;
+ id?: number;
+ fagsakIdFraRedigertNotat?: string;
+ versjon?: number;
+}
+
+const NotaterIndex: React.FC = ({ fagsakId, navAnsatt }) => {
+ const [lesteNotater, setLesteNotater] = useLocalStorage('lesteNotater', []);
+ const queryClient = useQueryClient();
+
+ const notaterQueryKey = ['notater', fagsakId];
+
+ const formMethods = useForm({
+ defaultValues: {
+ notatTekst: '',
+ visNotatIAlleSaker: false,
+ },
+ });
+
+ const getNotater = (signal: AbortSignal) =>
+ axios
+ .get(`/k9/sak/api/notat`, {
+ signal,
+ params: {
+ saksnummer: fagsakId,
+ },
+ })
+ .then(({ data }) => {
+ const sorterteNotater = [...data].sort(
+ (notatA, notatB) => +new Date(notatA.opprettetTidspunkt) - +new Date(notatB.opprettetTidspunkt),
+ );
+ setLesteNotater([
+ ...new Set([...lesteNotater, ...data.filter(notat => !notat.skjult).map(notat => notat.notatId)]),
+ ]);
+ return sorterteNotater;
+ });
+
+ const {
+ isLoading: getNotaterLoading,
+ isError: hasGetNotaterError,
+ data: notater,
+ } = useQuery({ queryKey: notaterQueryKey, queryFn: ({ signal }) => getNotater(signal), enabled: !!fagsakId });
+
+ const postNotat = (data: Inputs, id?: number, fagsakIdFraRedigertNotat?: string, versjon?: number) => {
+ let notatGjelderType;
+ if (!id) {
+ notatGjelderType = data.visNotatIAlleSaker ? NotatGjelderType.pleietrengende : NotatGjelderType.fagsak;
+ }
+ const postUrl = id ? '/k9/sak/api/notat/endre' : '/k9/sak/api/notat';
+ return axios.post(postUrl, {
+ notatTekst: data.notatTekst,
+ saksnummer: fagsakIdFraRedigertNotat || fagsakId,
+ notatGjelderType,
+ versjon: versjon || 0,
+ notatId: id,
+ });
+ };
+
+ const postNotatMutation = useMutation(
+ ({ data, id, fagsakIdFraRedigertNotat, versjon }: postNotatMutationVariables) =>
+ postNotat(data, id, fagsakIdFraRedigertNotat, versjon),
+ {
+ onSuccess: () => {
+ formMethods.reset();
+ queryClient.invalidateQueries({ queryKey: notaterQueryKey });
+ },
+ },
+ );
+
+ const skjulNotat = (skjul: boolean, id: number, saksnummer: string, versjon: number) =>
+ axios.post('/k9/sak/api/notat/skjul', {
+ notatId: id,
+ skjul,
+ saksnummer,
+ versjon,
+ });
+
+ const skjulNotatMutation = useMutation(
+ ({ skjul, id, saksnummer, versjon }: skjulNotatMutationVariables) => skjulNotat(skjul, id, saksnummer, versjon),
+ {
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: notaterQueryKey });
+ },
+ },
+ );
+
+ const isLoading = getNotaterLoading || postNotatMutation.isLoading;
+
+ const submitNotat = (data: Inputs, id?: number, fagsakIdFraRedigertNotat?: string, versjon?: number) =>
+ postNotatMutation.mutate({ data, id, fagsakIdFraRedigertNotat, versjon });
+
+ const submitSkjulNotat = (data: skjulNotatMutationVariables) => skjulNotatMutation.mutate(data);
+
+ return (
+
+ );
+};
+
+export default NotaterIndex;
diff --git a/packages/sak-notat/src/components/ChatComponent.tsx b/packages/sak-notat/src/components/ChatComponent.tsx
new file mode 100644
index 0000000000..746731d33a
--- /dev/null
+++ b/packages/sak-notat/src/components/ChatComponent.tsx
@@ -0,0 +1,178 @@
+import { NavAnsatt } from '@k9-sak-web/types';
+import { EyeSlashIcon, EyeWithPupilIcon, PencilIcon } from '@navikt/aksel-icons';
+import { BodyLong, Button, Chat, Label, Tag } from '@navikt/ds-react';
+import { Form, TextAreaField } from '@navikt/ft-form-hooks';
+import { maxLength, minLength, required } from '@navikt/ft-form-validators';
+import { format } from 'date-fns';
+import React, { useEffect, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { FormattedMessage } from 'react-intl';
+import { NotatResponse } from '../types/NotatResponse';
+import styles from './chatComponent.module.css';
+
+export enum ChatPosition {
+ Left = 'left',
+ Right = 'right',
+}
+
+type Inputs = {
+ notatTekst: string;
+ visNotatIAlleSaker: boolean;
+};
+
+interface ChatComponentProps {
+ notat: NotatResponse;
+ postNotat: ({
+ data,
+ id,
+ saksnummer,
+ versjon,
+ }: {
+ data: Inputs;
+ id: number;
+ saksnummer: string;
+ versjon: number;
+ }) => void;
+ navAnsatt: NavAnsatt;
+ skjulNotat: ({
+ skjul,
+ id,
+ saksnummer,
+ versjon,
+ }: {
+ skjul: boolean;
+ id: number;
+ saksnummer: string;
+ versjon: number;
+ }) => void;
+ fagsakId: string;
+}
+
+const ChatComponent: React.FunctionComponent = ({
+ notat,
+ postNotat,
+ navAnsatt,
+ skjulNotat,
+ fagsakId,
+}) => {
+ const {
+ endretAv,
+ endretTidspunkt,
+ gjelderType,
+ notatId,
+ notatTekst,
+ opprettetAv,
+ opprettetTidspunkt,
+ versjon,
+ skjult,
+ } = notat;
+ const erSistEndretAvGjeldendeBruker =
+ endretAv === navAnsatt.brukernavn || (!endretAv && opprettetAv === navAnsatt.brukernavn);
+ const position = erSistEndretAvGjeldendeBruker ? ChatPosition.Right : ChatPosition.Left;
+
+ const minLength3 = minLength(3);
+ const maxLength2000 = maxLength(1500);
+
+ const formMethods = useForm({
+ defaultValues: {
+ notatTekst,
+ },
+ shouldUnregister: true,
+ });
+ const { reset } = formMethods;
+ const [readOnly, setReadOnly] = useState(true);
+
+ useEffect(() => {
+ reset({
+ notatTekst,
+ });
+ }, [reset, notatTekst]);
+
+ const submit = (data: Inputs) => {
+ postNotat({ data, id: notatId, saksnummer: fagsakId, versjon });
+ };
+
+ const toggleReadOnly = () => {
+ setReadOnly(current => !current);
+ };
+
+ const toggleSkjulNotat = () => {
+ skjulNotat({ skjul: !skjult, id: notatId, saksnummer: fagsakId, versjon });
+ };
+
+ const name = erSistEndretAvGjeldendeBruker ? 'Deg' : endretAv || opprettetAv;
+ const timestamp = format(new Date(endretTidspunkt || opprettetTidspunkt), 'dd.MM.yyyy H:mm');
+
+ return (
+
+ );
+};
+export default ChatComponent;
diff --git a/packages/sak-notat/src/components/chatComponent.module.css b/packages/sak-notat/src/components/chatComponent.module.css
new file mode 100644
index 0000000000..27a6fb5fcc
--- /dev/null
+++ b/packages/sak-notat/src/components/chatComponent.module.css
@@ -0,0 +1,34 @@
+.nyttNotatTekst {
+ min-width: 31.25rem;
+}
+
+.nyttNotatKnappContainer {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+ margin-top: 0.75rem;
+}
+
+.notatContainer {
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ margin-top: 1.25rem;
+}
+
+.labelTagContainer {
+ align-items: baseline;
+ display: flex;
+}
+
+.redigerSkjulNotatKnappContainer {
+ display: flex;
+}
+
+:global(.navds-button).redigerSkjulKnapp {
+ margin-left: 0.625rem;
+}
+
+:global(.navds-tag).navnTag {
+ margin-left: 0.5rem;
+}
diff --git a/packages/sak-notat/src/notater.module.css b/packages/sak-notat/src/notater.module.css
new file mode 100644
index 0000000000..1c33cb7d6d
--- /dev/null
+++ b/packages/sak-notat/src/notater.module.css
@@ -0,0 +1,33 @@
+.loader {
+ display: flex;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.heading {
+ align-items: baseline;
+ display: flex;
+ justify-content: space-between;
+}
+
+.alert {
+ margin-top: 1.75rem;
+}
+
+.notater {
+ display: grid;
+ gap: 2.5rem;
+ margin-top: 1.25rem;
+}
+
+.nyttNotat {
+ margin-top: 2.25rem;
+}
+
+.visAlleNotater {
+ margin-top: 0.75rem;
+}
+
+:global(.navds-button).leggTilNotatKnapp {
+ margin-top: 1rem;
+}
diff --git a/packages/sak-notat/src/types/NotatGjelderType.ts b/packages/sak-notat/src/types/NotatGjelderType.ts
new file mode 100644
index 0000000000..66cd569555
--- /dev/null
+++ b/packages/sak-notat/src/types/NotatGjelderType.ts
@@ -0,0 +1,5 @@
+// eslint-disable-next-line import/prefer-default-export
+export enum NotatGjelderType {
+ fagsak = 'FAGSAK',
+ pleietrengende = 'PLEIETRENGENDE',
+}
diff --git a/packages/sak-notat/src/types/NotatResponse.ts b/packages/sak-notat/src/types/NotatResponse.ts
new file mode 100644
index 0000000000..56b5f43d3d
--- /dev/null
+++ b/packages/sak-notat/src/types/NotatResponse.ts
@@ -0,0 +1,14 @@
+import { NotatGjelderType } from './NotatGjelderType';
+
+export interface NotatResponse {
+ endretAv: string;
+ endretTidspunkt: null;
+ gjelderType: { kode: NotatGjelderType; navn: string };
+ notatId: number;
+ notatTekst: string;
+ opprettetAv: string;
+ opprettetTidspunkt: string;
+ sakstype?: string;
+ skjult: boolean;
+ versjon: number;
+}
diff --git a/packages/sak-support-meny/i18n/nb_NO.json b/packages/sak-support-meny/i18n/nb_NO.json
index 24e6c61670..d5e53261ac 100644
--- a/packages/sak-support-meny/i18n/nb_NO.json
+++ b/packages/sak-support-meny/i18n/nb_NO.json
@@ -3,5 +3,6 @@
"SupportMenySakIndex.FraBeslutter": "Fra beslutter",
"SupportMenySakIndex.Historikk": "Historikk",
"SupportMenySakIndex.Melding": "Send melding",
- "SupportMenySakIndex.Dokumenter": "Dokumenter"
+ "SupportMenySakIndex.Dokumenter": "Dokumenter",
+ "SupportMenySakIndex.Notater": "Notater"
}
diff --git a/packages/sak-support-meny/src/SupportMenySakIndex.spec.tsx b/packages/sak-support-meny/src/SupportMenySakIndex.spec.tsx
index ce43e52375..d6c27de256 100644
--- a/packages/sak-support-meny/src/SupportMenySakIndex.spec.tsx
+++ b/packages/sak-support-meny/src/SupportMenySakIndex.spec.tsx
@@ -13,6 +13,7 @@ describe('', () => {
valgbareTabs={[SupportTabs.HISTORIKK, SupportTabs.MELDINGER, SupportTabs.DOKUMENTER]}
valgtIndex={1}
onClick={() => undefined}
+ antallUlesteNotater={0}
/>,
);
@@ -37,6 +38,7 @@ describe('', () => {
tilgjengeligeTabs={[SupportTabs.HISTORIKK, SupportTabs.MELDINGER]}
valgbareTabs={[SupportTabs.HISTORIKK]}
onClick={() => undefined}
+ antallUlesteNotater={0}
/>,
);
diff --git a/packages/sak-support-meny/src/SupportMenySakIndex.tsx b/packages/sak-support-meny/src/SupportMenySakIndex.tsx
index ca87b51682..74c98eef9c 100644
--- a/packages/sak-support-meny/src/SupportMenySakIndex.tsx
+++ b/packages/sak-support-meny/src/SupportMenySakIndex.tsx
@@ -6,9 +6,11 @@ import { ReactComponent as SendMeldingSvg } from '@fpsak-frontend/assets/images/
import { ReactComponent as DokumenterSvg } from '@fpsak-frontend/assets/images/folder-big.svg';
import { ReactComponent as TilBeslutterSvg } from '@fpsak-frontend/assets/images/person-favorite-star-2.svg';
import { ReactComponent as HistorikkSvg } from '@fpsak-frontend/assets/images/synchronize-time.svg';
+import { PencilWritingFillIcon, PencilWritingIcon } from '@navikt/aksel-icons';
import TabMeny from './components/TabMeny';
import SupportTabs from './supportTabs';
+import styles from './supportMenySakIndex.module.css';
import messages from '../i18n/nb_NO.json';
@@ -50,9 +52,34 @@ const TABS = {
getSvg: (isActive, isDisabled, props) => ,
tooltipTextCode: 'SupportMenySakIndex.Dokumenter',
},
+ [SupportTabs.NOTATER]: {
+ getSvg: (isActive, isDisabled, props, antallUlesteNotater) => (
+
+ {antallUlesteNotater > 0 &&
{antallUlesteNotater}
}
+ {isActive ? (
+
+ ) : (
+
+ )}
+
+ ),
+
+ tooltipTextCode: 'SupportMenySakIndex.Notater',
+ },
};
-const lagTabs = (tilgjengeligeTabs: string[], valgbareTabs: string[], valgtIndex?: number) =>
+const lagTabs = (
+ tilgjengeligeTabs: string[],
+ valgbareTabs: string[],
+ antallUlesteNotater: number,
+ valgtIndex?: number,
+) =>
Object.keys(TABS)
.filter(key => tilgjengeligeTabs.includes(key))
.map((key, index) => ({
@@ -60,6 +87,7 @@ const lagTabs = (tilgjengeligeTabs: string[], valgbareTabs: string[], valgtIndex
tooltip: intl.formatMessage({ id: TABS[key].tooltipTextCode }),
isDisabled: !valgbareTabs.includes(key),
isActive: index === valgtIndex,
+ antallUlesteNotater,
}));
interface OwnProps {
@@ -67,12 +95,19 @@ interface OwnProps {
valgbareTabs: string[];
valgtIndex?: number;
onClick: (index: number) => void;
+ antallUlesteNotater: number;
}
-const SupportMenySakIndex = ({ tilgjengeligeTabs, valgbareTabs, valgtIndex, onClick }: OwnProps) => {
+const SupportMenySakIndex = ({
+ tilgjengeligeTabs,
+ valgbareTabs,
+ valgtIndex,
+ onClick,
+ antallUlesteNotater,
+}: OwnProps) => {
const tabs = useMemo(
- () => lagTabs(tilgjengeligeTabs, valgbareTabs, valgtIndex),
- [tilgjengeligeTabs, valgbareTabs, valgtIndex],
+ () => lagTabs(tilgjengeligeTabs, valgbareTabs, antallUlesteNotater, valgtIndex),
+ [tilgjengeligeTabs, valgbareTabs, valgtIndex, antallUlesteNotater],
);
return (
diff --git a/packages/sak-support-meny/src/components/TabMeny.spec.tsx b/packages/sak-support-meny/src/components/TabMeny.spec.tsx
index 2ab0cce6ea..847232dbcc 100644
--- a/packages/sak-support-meny/src/components/TabMeny.spec.tsx
+++ b/packages/sak-support-meny/src/components/TabMeny.spec.tsx
@@ -18,6 +18,7 @@ describe('', () => {
tooltip: 'Historikk',
isActive: true,
isDisabled: false,
+ antallUlesteNotater: 0,
},
{
getSvg: (isActive, isDisabled, props) => (
@@ -26,6 +27,7 @@ describe('', () => {
tooltip: 'Send melding',
isActive: false,
isDisabled: true,
+ antallUlesteNotater: 0,
},
];
@@ -64,6 +66,7 @@ describe('', () => {
tooltip: 'Historikk',
isActive: false,
isDisabled: false,
+ antallUlesteNotater: 0,
},
{
getSvg: (isActive, isDisabled, props) => (
@@ -72,6 +75,7 @@ describe('', () => {
tooltip: 'Send melding',
isActive: false,
isDisabled: false,
+ antallUlesteNotater: 0,
},
];
diff --git a/packages/sak-support-meny/src/components/TabMeny.tsx b/packages/sak-support-meny/src/components/TabMeny.tsx
index 27264cc4d6..ff96bedb9a 100644
--- a/packages/sak-support-meny/src/components/TabMeny.tsx
+++ b/packages/sak-support-meny/src/components/TabMeny.tsx
@@ -9,10 +9,11 @@ const classNames = classnames.bind(styles);
interface OwnProps {
tabs: {
- getSvg: (isActive: boolean, isDisabled: boolean, props) => React.ReactNode;
+ getSvg: (isActive: boolean, isDisabled: boolean, prop, antallUlesteNotater: number) => React.ReactNode;
tooltip: string;
isActive: boolean;
isDisabled: boolean;
+ antallUlesteNotater: number;
}[];
onClick: (index: number) => void;
}
@@ -47,11 +48,16 @@ const TabMeny = ({ tabs, onClick }: OwnProps) => {
tabRef.current[index] = el;
}}
>
- {tab.getSvg(tab.isActive, tab.isDisabled, {
- className: styles.tabImage,
- tabIndex: '-1',
- alt: tab.tooltip,
- })}
+ {tab.getSvg(
+ tab.isActive,
+ tab.isDisabled,
+ {
+ className: styles.tabImage,
+ tabIndex: '-1',
+ alt: tab.tooltip,
+ },
+ tab.antallUlesteNotater,
+ )}
))}
diff --git a/packages/sak-support-meny/src/supportMenySakIndex.module.css b/packages/sak-support-meny/src/supportMenySakIndex.module.css
new file mode 100644
index 0000000000..08540619d9
--- /dev/null
+++ b/packages/sak-support-meny/src/supportMenySakIndex.module.css
@@ -0,0 +1,25 @@
+.pencilSvgContainer {
+ position: relative;
+}
+
+.ulesteNotater {
+ position: absolute;
+ width: 1.25rem;
+ height: 1.25rem;
+ border-radius: 9999px;
+ background-color: #c30000;
+ left: calc(50% + 7px);
+ top: -0.4375rem;
+ color: white;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ font-weight: 600;
+}
+
+.pencilSvgFill {
+ margin-bottom: 0.5rem;
+}
+
+.pencilSvg {
+ margin-bottom: 0.5rem;
+}
diff --git a/packages/sak-support-meny/src/supportTabs.tsx b/packages/sak-support-meny/src/supportTabs.tsx
index 0ac573082b..344894689a 100644
--- a/packages/sak-support-meny/src/supportTabs.tsx
+++ b/packages/sak-support-meny/src/supportTabs.tsx
@@ -4,6 +4,7 @@ enum SupportTabs {
HISTORIKK = 'HISTORIKK',
MELDINGER = 'MELDINGER',
DOKUMENTER = 'DOKUMENTER',
+ NOTATER = 'NOTATER',
}
export default SupportTabs;
diff --git a/packages/storybook/stories/sak/NotatISakIndex.stories.tsx b/packages/storybook/stories/sak/NotatISakIndex.stories.tsx
new file mode 100644
index 0000000000..b82696d621
--- /dev/null
+++ b/packages/storybook/stories/sak/NotatISakIndex.stories.tsx
@@ -0,0 +1,109 @@
+import dayjs from 'dayjs';
+import { rest } from 'msw';
+import React from 'react';
+import NotatISakIndex from '@k9-sak-web/sak-notat';
+import { QueryClientProvider, QueryClient } from 'react-query';
+
+const queryClient = new QueryClient();
+
+export default {
+ title: 'sak/sak-notat',
+ component: NotatISakIndex,
+};
+
+export const VisNotatISakPanel = () => (
+
+
+
+
+
+);
+
+const notater = [
+ {
+ id: 1,
+ notatTekst: 'Saken er tidligere rettet opp i punsj på grunn av manglende funksjonalitet.',
+ gjelderType: 'FAGSAK',
+ versjon: 1,
+ opprettetAv: 'Saksbehandler Huldra',
+ opprettetTidspunkt: '01.01.22 14:00',
+ endretAv: undefined,
+ endretTidspunkt: undefined,
+ fagsakId: '1',
+ skjult: false,
+ },
+ {
+ id: 2,
+ notatTekst:
+ // eslint-disable-next-line max-len
+ 'Bruker venter på legeerklæring fra sykehus, men har fått beskjed om at sykehuslege er på ferie og det kan derfor ta litt tid før den kommer inn. Setter derfor fristen lenger frem i tid enn normalt.',
+ gjelderType: 'PLEIETRENGENDE',
+ versjon: 1,
+ opprettetAv: 'Saksbehandler Huldra',
+ opprettetTidspunkt: '01.01.22 14:00',
+ endretAv: undefined,
+ endretTidspunkt: undefined,
+ fagsakId: undefined,
+ aktørId: '123',
+ sakstype: 'PSB',
+ skjult: false,
+ },
+];
+
+VisNotatISakPanel.parameters = {
+ msw: {
+ handlers: [
+ rest.get('/k9/sak/api/notat', (req, res, ctx) => res(ctx.delay(250), ctx.json(notater))),
+ rest.post('/k9/sak/api/notat', async (req, res, ctx) => {
+ const nyttNotat = await req.json();
+ const redigertNotatIndex = notater.findIndex(notat => notat.id === nyttNotat.id);
+ if (redigertNotatIndex >= 0) {
+ notater[redigertNotatIndex] = {
+ ...notater[redigertNotatIndex],
+ notatTekst: nyttNotat.notatTekst,
+ versjon: notater[redigertNotatIndex].versjon + 1,
+ endretTidspunkt: dayjs().format('DD.MM.YYYY HH:mm'),
+ endretAv: nyttNotat.endretAv,
+ };
+ } else {
+ notater.push({
+ id: notater.length + 1,
+ notatTekst: nyttNotat.notatTekst,
+ gjelderType: nyttNotat.notatGjelderType,
+ fagsakId: nyttNotat.fagsakId,
+ opprettetAv: nyttNotat.opprettetAv,
+ opprettetTidspunkt: dayjs().format('DD.MM.YYYY HH:mm'),
+ endretAv: '',
+ endretTidspunkt: undefined,
+ aktørId: '123',
+ sakstype: 'PSB',
+ versjon: 1,
+ skjult: false,
+ });
+ }
+ return res(ctx.status(201));
+ }),
+ ],
+ },
+};
diff --git a/packages/storybook/stories/sak/SupportMenySakIndex.stories.tsx b/packages/storybook/stories/sak/SupportMenySakIndex.stories.tsx
index 866a8e5ed8..ce2931eb30 100644
--- a/packages/storybook/stories/sak/SupportMenySakIndex.stories.tsx
+++ b/packages/storybook/stories/sak/SupportMenySakIndex.stories.tsx
@@ -17,6 +17,7 @@ export const visMenyUtenBeslutterGodkjenningOgTilbakesending = () => {
valgbareTabs={[SupportTabs.HISTORIKK, SupportTabs.MELDINGER, SupportTabs.DOKUMENTER]}
valgtIndex={valgtPanelIndex}
onClick={setPanelIndex}
+ antallUlesteNotater={0}
/>
);
};
@@ -34,6 +35,7 @@ export const visMenyMedBeslutterGodkjenning = () => {
valgbareTabs={[SupportTabs.TIL_BESLUTTER, SupportTabs.HISTORIKK, SupportTabs.MELDINGER, SupportTabs.DOKUMENTER]}
valgtIndex={valgtPanelIndex}
onClick={setPanelIndex}
+ antallUlesteNotater={0}
/>
);
};
@@ -51,6 +53,7 @@ export const visMenyEtterTilbakesendingFraBeslutter = () => {
valgbareTabs={[SupportTabs.FRA_BESLUTTER, SupportTabs.HISTORIKK, SupportTabs.MELDINGER, SupportTabs.DOKUMENTER]}
valgtIndex={valgtPanelIndex}
onClick={setPanelIndex}
+ antallUlesteNotater={0}
/>
);
};
@@ -63,6 +66,7 @@ export const visSendMeldingSomIkkeValgbar = () => {
valgbareTabs={[SupportTabs.HISTORIKK, SupportTabs.DOKUMENTER]}
valgtIndex={valgtPanelIndex}
onClick={setPanelIndex}
+ antallUlesteNotater={0}
/>
);
};
diff --git a/packages/utils-test/src/test-utils.tsx b/packages/utils-test/src/test-utils.tsx
index 10a47ad22d..49c3c8c0f4 100644
--- a/packages/utils-test/src/test-utils.tsx
+++ b/packages/utils-test/src/test-utils.tsx
@@ -4,6 +4,7 @@ import { IntlProvider } from 'react-intl';
import { combineReducers, createStore } from 'redux';
import { Provider } from 'react-redux';
import { reducer } from 'redux-form';
+import { QueryClient, QueryClientProvider } from 'react-query';
// eslint-disable-next-line import/no-relative-packages
import defaultMessages from '../../../public/sprak/nb_NO.json';
// eslint-disable-next-line import/no-relative-packages
@@ -39,4 +40,23 @@ export function renderWithIntlAndReduxForm(ui: ReactElement, { locale, messages,
return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
}
+const createTestReactQueryClient = () =>
+ new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ },
+ },
+ });
+
+export function renderWithReactQueryClient(ui: React.ReactElement) {
+ const testQueryClient = createTestReactQueryClient();
+ const { rerender, ...result } = rtlRender({ui});
+ return {
+ ...result,
+ rerender: (rerenderUi: React.ReactElement) =>
+ rerender({rerenderUi}),
+ };
+}
+
export * from '@testing-library/react';
diff --git a/packages/utils/index.ts b/packages/utils/index.ts
index 2aba40825e..2b9ca4f511 100644
--- a/packages/utils/index.ts
+++ b/packages/utils/index.ts
@@ -122,3 +122,4 @@ export { joinNonNullStrings, safeJSONParse } from './src/stringUtils';
export type { Adresser } from './src/getAddresses';
export { default as mapVilkar } from './src/beregning/VilkarMapper';
export { default as transformBeregningValues } from './src/beregning/transformValuesBeregning';
+export { default as useLocalStorage } from './src/useLocalStorageHook';
diff --git a/packages/utils/src/useLocalStorageHook.ts b/packages/utils/src/useLocalStorageHook.ts
new file mode 100644
index 0000000000..d48eede453
--- /dev/null
+++ b/packages/utils/src/useLocalStorageHook.ts
@@ -0,0 +1,25 @@
+import { useState } from 'react';
+
+function useLocalStorage(key: string, initialValue: S): [S, (value: S) => void] {
+ const [storedValue, setStoredValue] = useState(() => {
+ try {
+ const item = window.localStorage.getItem(key);
+ return item !== null ? JSON.parse(item) : initialValue;
+ } catch (error) {
+ return initialValue;
+ }
+ });
+
+ const setValue = (value: S) => {
+ try {
+ setStoredValue(value);
+ window.localStorage.setItem(key, JSON.stringify(value));
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ return [storedValue, setValue];
+}
+
+export default useLocalStorage;
diff --git a/postcss.config.js b/postcss.config.js
index 2b2bed35af..6f83ac4ff5 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -3,5 +3,5 @@ const autoprefixer = require('autoprefixer');
const postcssImport = require('postcss-import');
module.exports = {
- plugins: [postcssImport, tailwindcss('./tailwind.config.js'), autoprefixer],
-};
+ plugins: [postcssImport, tailwindcss('./tailwind.config.js'), autoprefixer],
+};
\ No newline at end of file
diff --git a/public/client/index.html b/public/client/index.html
index cbbf0dd8b2..af3e4b4956 100644
--- a/public/client/index.html
+++ b/public/client/index.html
@@ -1,10 +1,11 @@
-
+
K9-SAK
+
diff --git a/public/mockServiceWorker.js b/public/mockServiceWorker.js
index 0f24d51586..4471d859f6 100644
--- a/public/mockServiceWorker.js
+++ b/public/mockServiceWorker.js
@@ -8,121 +8,121 @@
* - Please do NOT serve this file on production.
*/
-const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70'
-const activeClientIds = new Set()
+const INTEGRITY_CHECKSUM = '3d6b9f06410d179a7f7404d4bf4c3c70';
+const activeClientIds = new Set();
self.addEventListener('install', function () {
- self.skipWaiting()
-})
+ self.skipWaiting();
+});
self.addEventListener('activate', function (event) {
- event.waitUntil(self.clients.claim())
-})
+ event.waitUntil(self.clients.claim());
+});
self.addEventListener('message', async function (event) {
- const clientId = event.source.id
+ const clientId = event.source.id;
if (!clientId || !self.clients) {
- return
+ return;
}
- const client = await self.clients.get(clientId)
+ const client = await self.clients.get(clientId);
if (!client) {
- return
+ return;
}
const allClients = await self.clients.matchAll({
type: 'window',
- })
+ });
switch (event.data) {
case 'KEEPALIVE_REQUEST': {
sendToClient(client, {
type: 'KEEPALIVE_RESPONSE',
- })
- break
+ });
+ break;
}
case 'INTEGRITY_CHECK_REQUEST': {
sendToClient(client, {
type: 'INTEGRITY_CHECK_RESPONSE',
payload: INTEGRITY_CHECKSUM,
- })
- break
+ });
+ break;
}
case 'MOCK_ACTIVATE': {
- activeClientIds.add(clientId)
+ activeClientIds.add(clientId);
sendToClient(client, {
type: 'MOCKING_ENABLED',
payload: true,
- })
- break
+ });
+ break;
}
case 'MOCK_DEACTIVATE': {
- activeClientIds.delete(clientId)
- break
+ activeClientIds.delete(clientId);
+ break;
}
case 'CLIENT_CLOSED': {
- activeClientIds.delete(clientId)
+ activeClientIds.delete(clientId);
- const remainingClients = allClients.filter((client) => {
- return client.id !== clientId
- })
+ const remainingClients = allClients.filter(client => {
+ return client.id !== clientId;
+ });
// Unregister itself when there are no more clients
if (remainingClients.length === 0) {
- self.registration.unregister()
+ self.registration.unregister();
}
- break
+ break;
}
}
-})
+});
self.addEventListener('fetch', function (event) {
- const { request } = event
- const accept = request.headers.get('accept') || ''
+ const { request } = event;
+ const accept = request.headers.get('accept') || '';
// Bypass server-sent events.
if (accept.includes('text/event-stream')) {
- return
+ return;
}
// Bypass navigation requests.
if (request.mode === 'navigate') {
- return
+ return;
}
// Opening the DevTools triggers the "only-if-cached" request
// that cannot be handled by the worker. Bypass such requests.
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
- return
+ return;
}
// Bypass all requests when there are no active clients.
// Prevents the self-unregistered worked from handling requests
// after it's been deleted (still remains active until the next reload).
if (activeClientIds.size === 0) {
- return
+ return;
}
// Generate unique request ID.
- const requestId = Math.random().toString(16).slice(2)
+ const requestId = Math.random().toString(16).slice(2);
event.respondWith(
- handleRequest(event, requestId).catch((error) => {
+ handleRequest(event, requestId).catch(error => {
if (error.name === 'NetworkError') {
console.warn(
'[MSW] Successfully emulated a network error for the "%s %s" request.',
request.method,
request.url,
- )
- return
+ );
+ return;
}
// At this point, any exception indicates an issue with the original request/response.
@@ -132,21 +132,21 @@ self.addEventListener('fetch', function (event) {
request.method,
request.url,
`${error.name}: ${error.message}`,
- )
+ );
}),
- )
-})
+ );
+});
async function handleRequest(event, requestId) {
- const client = await resolveMainClient(event)
- const response = await getResponse(event, client, requestId)
+ const client = await resolveMainClient(event);
+ const response = await getResponse(event, client, requestId);
// Send back the response clone for the "response:*" life-cycle events.
// Ensure MSW is active and ready to handle the message, otherwise
// this message will pend indefinitely.
if (client && activeClientIds.has(client.id)) {
- ;(async function () {
- const clonedResponse = response.clone()
+ (async function () {
+ const clonedResponse = response.clone();
sendToClient(client, {
type: 'RESPONSE',
payload: {
@@ -155,16 +155,15 @@ async function handleRequest(event, requestId) {
ok: clonedResponse.ok,
status: clonedResponse.status,
statusText: clonedResponse.statusText,
- body:
- clonedResponse.body === null ? null : await clonedResponse.text(),
+ body: clonedResponse.body === null ? null : await clonedResponse.text(),
headers: Object.fromEntries(clonedResponse.headers.entries()),
redirected: clonedResponse.redirected,
},
- })
- })()
+ });
+ })();
}
- return response
+ return response;
}
// Resolve the main client for the given event.
@@ -172,49 +171,49 @@ async function handleRequest(event, requestId) {
// that registered the worker. It's with the latter the worker should
// communicate with during the response resolving phase.
async function resolveMainClient(event) {
- const client = await self.clients.get(event.clientId)
+ const client = await self.clients.get(event.clientId);
if (client?.frameType === 'top-level') {
- return client
+ return client;
}
const allClients = await self.clients.matchAll({
type: 'window',
- })
+ });
return allClients
- .filter((client) => {
+ .filter(client => {
// Get only those clients that are currently visible.
- return client.visibilityState === 'visible'
+ return client.visibilityState === 'visible';
})
- .find((client) => {
+ .find(client => {
// Find the client ID that's recorded in the
// set of clients that have registered the worker.
- return activeClientIds.has(client.id)
- })
+ return activeClientIds.has(client.id);
+ });
}
async function getResponse(event, client, requestId) {
- const { request } = event
- const clonedRequest = request.clone()
+ const { request } = event;
+ const clonedRequest = request.clone();
function passthrough() {
// Clone the request because it might've been already used
// (i.e. its body has been read and sent to the client).
- const headers = Object.fromEntries(clonedRequest.headers.entries())
+ const headers = Object.fromEntries(clonedRequest.headers.entries());
// Remove MSW-specific request headers so the bypassed requests
// comply with the server's CORS preflight check.
// Operate with the headers as an object because request "Headers"
// are immutable.
- delete headers['x-msw-bypass']
+ delete headers['x-msw-bypass'];
- return fetch(clonedRequest, { headers })
+ return fetch(clonedRequest, { headers });
}
// Bypass mocking when the client is not active.
if (!client) {
- return passthrough()
+ return passthrough();
}
// Bypass initial page load requests (i.e. static assets).
@@ -222,13 +221,13 @@ async function getResponse(event, client, requestId) {
// means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
// and is not ready to handle requests.
if (!activeClientIds.has(client.id)) {
- return passthrough()
+ return passthrough();
}
// Bypass requests with the explicit bypass header.
// Such requests can be issued by "ctx.fetch()".
if (request.headers.get('x-msw-bypass') === 'true') {
- return passthrough()
+ return passthrough();
}
// Notify the client that a request has been intercepted.
@@ -251,53 +250,53 @@ async function getResponse(event, client, requestId) {
bodyUsed: request.bodyUsed,
keepalive: request.keepalive,
},
- })
+ });
switch (clientMessage.type) {
case 'MOCK_RESPONSE': {
- return respondWithMock(clientMessage.data)
+ return respondWithMock(clientMessage.data);
}
case 'MOCK_NOT_FOUND': {
- return passthrough()
+ return passthrough();
}
case 'NETWORK_ERROR': {
- const { name, message } = clientMessage.data
- const networkError = new Error(message)
- networkError.name = name
+ const { name, message } = clientMessage.data;
+ const networkError = new Error(message);
+ networkError.name = name;
// Rejecting a "respondWith" promise emulates a network error.
- throw networkError
+ throw networkError;
}
}
- return passthrough()
+ return passthrough();
}
function sendToClient(client, message) {
return new Promise((resolve, reject) => {
- const channel = new MessageChannel()
+ const channel = new MessageChannel();
- channel.port1.onmessage = (event) => {
+ channel.port1.onmessage = event => {
if (event.data && event.data.error) {
- return reject(event.data.error)
+ return reject(event.data.error);
}
- resolve(event.data)
- }
+ resolve(event.data);
+ };
- client.postMessage(message, [channel.port2])
- })
+ client.postMessage(message, [channel.port2]);
+ });
}
function sleep(timeMs) {
- return new Promise((resolve) => {
- setTimeout(resolve, timeMs)
- })
+ return new Promise(resolve => {
+ setTimeout(resolve, timeMs);
+ });
}
async function respondWithMock(response) {
- await sleep(response.delay)
- return new Response(response.body, response)
+ await sleep(response.delay);
+ return new Response(response.body, response);
}
diff --git a/tailwind.config.js b/tailwind.config.js
index e88b75e221..864f9ddc19 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,13 +1,13 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- content: ['./packages/**/*.{js,jsx,ts,tsx}', './public/client/index.html'],
- // eslint-disable-next-line global-require
- presets: [require('@navikt/ds-tailwind')],
- theme: {
- extend: {},
- },
- corePlugins: {
- preflight: false,
- },
- plugins: [],
+ content: ['./packages/**/*.{js,jsx,ts,tsx}', './public/client/index.html'],
+ // eslint-disable-next-line global-require
+ presets: [require('@navikt/ds-tailwind')],
+ theme: {
+ extend: {},
+ },
+ corePlugins: {
+ preflight: false,
+ },
+ plugins: [],
};
diff --git a/webpack/mocks/feature-toggles.js b/webpack/mocks/feature-toggles.js
index a55ef69147..d5478f57dd 100644
--- a/webpack/mocks/feature-toggles.js
+++ b/webpack/mocks/feature-toggles.js
@@ -69,6 +69,10 @@ const featureToggles = [
key: 'FAKTA_BEREGNING_REDESIGN',
value: process.env.FAKTA_BEREGNING_REDESIGN,
},
+ {
+ key: 'NOTAT_I_SAK',
+ value: process.env.NOTAT_I_SAK,
+ },
];
module.exports = function (app) {
diff --git a/yarn.lock b/yarn.lock
index 793602e08b..cb9a237640 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2376,6 +2376,17 @@ __metadata:
languageName: node
linkType: hard
+"@formatjs/icu-messageformat-parser@npm:2.7.0":
+ version: 2.7.0
+ resolution: "@formatjs/icu-messageformat-parser@npm:2.7.0"
+ dependencies:
+ "@formatjs/ecma402-abstract": 1.17.2
+ "@formatjs/icu-skeleton-parser": 1.6.2
+ tslib: ^2.4.0
+ checksum: 5c289b0090a3549fdeb5ee4c382666cf085be77c8a10abcee879e12e064126ec803a48d7f564a3cb5baf4529ef5fde3a61b30f9c54481279f0fb2cf2e9be1e7e
+ languageName: node
+ linkType: hard
+
"@formatjs/icu-skeleton-parser@npm:1.6.2":
version: 1.6.2
resolution: "@formatjs/icu-skeleton-parser@npm:1.6.2"
@@ -2408,6 +2419,17 @@ __metadata:
languageName: node
linkType: hard
+"@formatjs/intl-displaynames@npm:6.6.1":
+ version: 6.6.1
+ resolution: "@formatjs/intl-displaynames@npm:6.6.1"
+ dependencies:
+ "@formatjs/ecma402-abstract": 1.17.2
+ "@formatjs/intl-localematcher": 0.4.2
+ tslib: ^2.4.0
+ checksum: e70c18f5f6228fbf937434c9168eac4d42c7f115410b42b66785ba43db4604184849d9e55b76ca4ce116359fec645b5e41e06b036dcb0966387c19753970c8e5
+ languageName: node
+ linkType: hard
+
"@formatjs/intl-listformat@npm:7.4.2":
version: 7.4.2
resolution: "@formatjs/intl-listformat@npm:7.4.2"
@@ -2419,6 +2441,17 @@ __metadata:
languageName: node
linkType: hard
+"@formatjs/intl-listformat@npm:7.5.0":
+ version: 7.5.0
+ resolution: "@formatjs/intl-listformat@npm:7.5.0"
+ dependencies:
+ "@formatjs/ecma402-abstract": 1.17.2
+ "@formatjs/intl-localematcher": 0.4.2
+ tslib: ^2.4.0
+ checksum: 55de558bc7981a0ad442dada2500f369ad05176e7a997cf6ac502b8d446b2ae339477360219553c05d3fce7526823620866d1ba06d4006a00f4712aead5335ab
+ languageName: node
+ linkType: hard
+
"@formatjs/intl-localematcher@npm:0.4.2":
version: 0.4.2
resolution: "@formatjs/intl-localematcher@npm:0.4.2"
@@ -2459,6 +2492,26 @@ __metadata:
languageName: node
linkType: hard
+"@formatjs/intl@npm:2.9.5":
+ version: 2.9.5
+ resolution: "@formatjs/intl@npm:2.9.5"
+ dependencies:
+ "@formatjs/ecma402-abstract": 1.17.2
+ "@formatjs/fast-memoize": 2.2.0
+ "@formatjs/icu-messageformat-parser": 2.7.0
+ "@formatjs/intl-displaynames": 6.6.1
+ "@formatjs/intl-listformat": 7.5.0
+ intl-messageformat: 10.5.4
+ tslib: ^2.4.0
+ peerDependencies:
+ typescript: 5
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 12f6ac51a6630a967dc2a446eab6bf2e1c046aa2a693c550c2fa594bcb095cecf2e38efcc1e07611261c00ffa58a2372d16460e4716fac073fc1b54d302e2520
+ languageName: node
+ linkType: hard
+
"@fpsak-frontend/assets@1.0.0, @fpsak-frontend/assets@workspace:packages/assets":
version: 0.0.0-use.local
resolution: "@fpsak-frontend/assets@workspace:packages/assets"
@@ -5357,6 +5410,7 @@ __metadata:
"@k9-sak-web/sak-infosider": 1.0.0
"@k9-sak-web/sak-meldinger": 1.0.0
"@k9-sak-web/sak-meny-marker-behandling": 1.0.0
+ "@k9-sak-web/sak-notat": 1.0.0
"@k9-sak-web/sak-soknadsperiodestripe": 1.0.0
"@k9-sak-web/types": 1.0.0
"@navikt/ds-react": 5.6.1
@@ -5499,6 +5553,23 @@ __metadata:
languageName: unknown
linkType: soft
+"@k9-sak-web/sak-notat@1.0.0, @k9-sak-web/sak-notat@workspace:packages/sak-notat":
+ version: 0.0.0-use.local
+ resolution: "@k9-sak-web/sak-notat@workspace:packages/sak-notat"
+ dependencies:
+ "@fpsak-frontend/utils": 1.0.0
+ "@k9-sak-web/types": 1.0.0
+ "@navikt/aksel-icons": 5.6.1
+ "@navikt/ds-react": 5.6.1
+ "@navikt/ft-form-hooks": 4.2.7
+ "@navikt/ft-form-validators": ^2.1.3
+ date-fns: 2.30.0
+ react: 17.0.2
+ react-hook-form: 7.47.0
+ react-intl: 6.4.7
+ languageName: unknown
+ linkType: soft
+
"@k9-sak-web/sak-soknadsperiodestripe@1.0.0, @k9-sak-web/sak-soknadsperiodestripe@workspace:packages/sak-soknadsperiodestripe":
version: 0.0.0-use.local
resolution: "@k9-sak-web/sak-soknadsperiodestripe@workspace:packages/sak-soknadsperiodestripe"
@@ -5660,6 +5731,13 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/aksel-icons@npm:5.7.6, @navikt/aksel-icons@npm:^5.7.6":
+ version: 5.7.6
+ resolution: "@navikt/aksel-icons@npm:5.7.6::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Faksel-icons%2F5.7.6%2F0c3fc6f5044f60eb47358df7412be01365b82622"
+ checksum: bb2e4e652682992716a010f2a1f58bbde3ffad773dedee079f2af3ab3f8d45580cb2fa97ed446d7b4d36818e3d9b0bf0269736b9dbe51f3e43ab36042531ec18
+ languageName: node
+ linkType: hard
+
"@navikt/aksel-icons@npm:^5.6.1":
version: 5.6.5
resolution: "@navikt/aksel-icons@npm:5.6.5::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Faksel-icons%2F5.6.5%2Fb3ccad41f712cd660d0451bbcd912b1e082d3387"
@@ -5674,6 +5752,13 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ds-css@npm:5.7.6":
+ version: 5.7.6
+ resolution: "@navikt/ds-css@npm:5.7.6::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fds-css%2F5.7.6%2Ffef98381e0ed44b133390f7e2ed272b6fb5ec89e"
+ checksum: 52f83487fb8d3d7070ccf9540c2fd41199a6e03af0c59099abadb0ed243002e770a92e6cdfe6e43641c413db843411a462f5903944abe76c08aa9c1d37a1242b
+ languageName: node
+ linkType: hard
+
"@navikt/ds-icons@npm:3.4.3":
version: 3.4.3
resolution: "@navikt/ds-icons@npm:3.4.3::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fds-icons%2F3.4.3%2Feaa8fc38f6d184806d3405a5efbc9d137c2b8d27"
@@ -5703,10 +5788,29 @@ __metadata:
languageName: node
linkType: hard
-"@navikt/ds-tailwind@npm:^5.5.0":
- version: 5.5.0
- resolution: "@navikt/ds-tailwind@npm:5.5.0::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fds-tailwind%2F5.5.0%2F0b61d1b5fcf8952350677cc10c4269833fde3afd"
- checksum: b7013e6b00a0a5520e55682aa612a955841d9928d0dd01cf6333dd74e8f72c5fc876543e57b5922353b7aabbacb54248cb4995c414eddbf3cf7b1691d95e1b7f
+"@navikt/ds-react@npm:5.7.6":
+ version: 5.7.6
+ resolution: "@navikt/ds-react@npm:5.7.6::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fds-react%2F5.7.6%2Fefba043f4e215f4724e122f19698431904529d71"
+ dependencies:
+ "@floating-ui/react": 0.25.4
+ "@navikt/aksel-icons": ^5.7.6
+ "@navikt/ds-tokens": ^5.7.6
+ "@radix-ui/react-tabs": 1.0.0
+ "@radix-ui/react-toggle-group": 1.0.0
+ clsx: ^1.2.1
+ date-fns: 2.29.3
+ react-day-picker: 8.3.4
+ peerDependencies:
+ "@types/react": ^17.0.30 || ^18.0.0
+ react: ^17.0.0 || ^18.0.0
+ checksum: 24e830a3d2e0cc748e039c2c021e7ddf7b5e3c2ac15037504b568dda01f99da1334565c135c528fc798d734ef6abdd13f1eab61181f4e97fcac6284c3b97ba11
+ languageName: node
+ linkType: hard
+
+"@navikt/ds-tailwind@npm:^5.6.1":
+ version: 5.7.6
+ resolution: "@navikt/ds-tailwind@npm:5.7.6::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fds-tailwind%2F5.7.6%2F7347b5fae15e49e32c63c68a6539e573c86b7e0c"
+ checksum: 5ba1f69b3cd4ab394bc412b2f6cba53db52262413255a77bec96cf57c425ea4d4aa86860c3a545d12b063ad790da18c2ec04fb8397ed3909c1fcd3e44c3c60b9
languageName: node
linkType: hard
@@ -5717,6 +5821,13 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ds-tokens@npm:^5.7.6":
+ version: 5.7.6
+ resolution: "@navikt/ds-tokens@npm:5.7.6::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fds-tokens%2F5.7.6%2Ffbe6fee9d2df3add79e38162a491972814a4d625"
+ checksum: 14a11a909ca3ed791c9762840116844ca218b6fa5b64b9b5e200ec78612d68c8370dafe9a4ee1b86ebb82061cfd48de4f28c0cac549473a0a829493298750a3d
+ languageName: node
+ linkType: hard
+
"@navikt/familie-endringslogg@npm:9.0.3":
version: 9.0.3
resolution: "@navikt/familie-endringslogg@npm:9.0.3::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Ffamilie-endringslogg%2F9.0.3%2F0935613ba550b711a10ddd2e0d35e2f5a9e9567b"
@@ -5866,6 +5977,39 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ft-form-hooks@npm:4.2.7":
+ version: 4.2.7
+ resolution: "@navikt/ft-form-hooks@npm:4.2.7::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-form-hooks%2F4.2.7%2F69906de7f7d8f4e603efd6f2255181602f5ce89b"
+ dependencies:
+ "@navikt/aksel-icons": 5.6.1
+ "@navikt/ds-css": 5.6.1
+ "@navikt/ds-react": 5.6.1
+ "@navikt/ft-form-validators": ^2.1.3
+ "@navikt/ft-types": ^2.2.3
+ "@navikt/ft-ui-komponenter": ^2.1.7
+ "@navikt/ft-utils": ^2.1.3
+ classnames: 2.3.2
+ dayjs: 1.11.9
+ lodash.throttle: 4.1.1
+ react: 18.2.0
+ react-hook-form: 7.47.0
+ peerDependencies:
+ "@navikt/aksel-icons": 3.1.2
+ "@navikt/ds-css": 2.8.11
+ "@navikt/ds-react": 2.8.11
+ "@navikt/ft-form-validators": 2.x
+ "@navikt/ft-types": 2.x
+ "@navikt/ft-ui-komponenter": 2.x
+ "@navikt/ft-utils": 2.x
+ classnames: 2.3.2
+ dayjs: 1.11.7
+ lodash.throttle: 4.1.1
+ react: 18.2.0
+ react-hook-form: 7.43.9
+ checksum: 628b12750c9aba9c1859f5c8111c937c0fdf386f3ede69d0906b09eae51e7412eee7461260d56ebab4407306ad526f297713c1916cb3ded1f39086e5a4bc8052
+ languageName: node
+ linkType: hard
+
"@navikt/ft-form-hooks@npm:4.2.9, @navikt/ft-form-hooks@npm:^4.2.9":
version: 4.2.9
resolution: "@navikt/ft-form-hooks@npm:4.2.9::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-form-hooks%2F4.2.9%2F813a0066ebc606a8e2e8ec7096ee30a95a174c34"
@@ -5919,6 +6063,13 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ft-kodeverk@npm:^2.2.4":
+ version: 2.2.4
+ resolution: "@navikt/ft-kodeverk@npm:2.2.4::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-kodeverk%2F2.2.4%2F4fa5be8270009aef3c237e46b826e2a04a4d135d"
+ checksum: 4ebce757442c56ec75a703faf83e57b7a4db10b570db4fb5a81e031ed390d32c978e537600de199d200dffa92327ccfb4e4f085012ff85b0e3e96ab15dbede3e
+ languageName: node
+ linkType: hard
+
"@navikt/ft-konstanter@npm:^2.1.3":
version: 2.1.3
resolution: "@navikt/ft-konstanter@npm:2.1.3::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-konstanter%2F2.1.3%2F55d650fbc5c627e408eb880f1d577182b43e2b75"
@@ -6040,6 +6191,17 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ft-types@npm:^2.2.4":
+ version: 2.2.4
+ resolution: "@navikt/ft-types@npm:2.2.4::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-types%2F2.2.4%2Fe7f939aeb3a79dab91f047e7b2cc2ed313a57b60"
+ dependencies:
+ "@navikt/ft-kodeverk": ^2.2.4
+ peerDependencies:
+ "@navikt/ft-kodeverk": 2.x
+ checksum: 7bfee031d4baa889dd90bc89c26f687bb0df1df2b4d9b1967b04d38635ac7be42bea0951cc01e070ba6e82b460247f5d3767d6a4e3da7808bdcac54803001f43
+ languageName: node
+ linkType: hard
+
"@navikt/ft-ui-komponenter@npm:2.1.9, @navikt/ft-ui-komponenter@npm:^2.1.9":
version: 2.1.9
resolution: "@navikt/ft-ui-komponenter@npm:2.1.9::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-ui-komponenter%2F2.1.9%2F2c3d2dca9e064720fb0eae417872c1453e4d7b75"
@@ -6065,6 +6227,31 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ft-ui-komponenter@npm:^2.1.7":
+ version: 2.1.11
+ resolution: "@navikt/ft-ui-komponenter@npm:2.1.11::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-ui-komponenter%2F2.1.11%2F1b127a4927555d8a3bc67929283282f6a2eecea2"
+ dependencies:
+ "@navikt/aksel-icons": 5.7.6
+ "@navikt/ds-css": 5.7.6
+ "@navikt/ds-react": 5.7.6
+ "@navikt/ft-utils": ^2.1.4
+ classnames: 2.3.2
+ react: 18.2.0
+ react-intl: 6.5.1
+ react-modal: 3.16.1
+ peerDependencies:
+ "@navikt/aksel-icons": 3.1.2
+ "@navikt/ds-css": 2.8.11
+ "@navikt/ds-react": 2.8.11
+ "@navikt/ft-utils": 2.x
+ classnames: 2.3.2
+ react: 18.2.0
+ react-intl: 6.3.2
+ react-modal: 3.16.1
+ checksum: 93f58d626dd0ef6883bdb4e5cddf673d56193de5a3e2a90da6d33fcf2e7468dd4a8560db2cea6a1ac00fa4a4b70bbe81c79ec2ae3dc6c4d83d786a799b3ba328
+ languageName: node
+ linkType: hard
+
"@navikt/ft-utils@npm:^2.1.3":
version: 2.1.3
resolution: "@navikt/ft-utils@npm:2.1.3::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-utils%2F2.1.3%2F39750ce6112c8bdd9c2c2ce078d1e3034846ce1f"
@@ -6082,6 +6269,23 @@ __metadata:
languageName: node
linkType: hard
+"@navikt/ft-utils@npm:^2.1.4":
+ version: 2.1.4
+ resolution: "@navikt/ft-utils@npm:2.1.4::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fft-utils%2F2.1.4%2F61679a524ff57e25d134487e83633fe8f9a4ff43"
+ dependencies:
+ "@navikt/ft-kodeverk": ^2.2.4
+ "@navikt/ft-types": ^2.2.4
+ dayjs: 1.11.9
+ react-intl: 6.5.1
+ peerDependencies:
+ "@navikt/ft-kodeverk": 2.x
+ "@navikt/ft-types": 2.x
+ dayjs: 1.11.7
+ react-intl: 6.3.2
+ checksum: 2a2d9f7e56795b1b5787eaff93abe3086c5f2181d83c8d9159ed04f3a53584f39d72ca52c69b611e54e129d8dfed65ee9f7dbfea69f3a2d438b07a9bf79b4d71
+ languageName: node
+ linkType: hard
+
"@navikt/k9-fe-array-utils@npm:1.0.4":
version: 1.0.4
resolution: "@navikt/k9-fe-array-utils@npm:1.0.4::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Fk9-fe-array-utils%2F1.0.4%2Fab0a746ab7ac634f3b3e0857dd32cb8015c87813"
@@ -14649,7 +14853,7 @@ __metadata:
languageName: node
linkType: hard
-"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.1":
+"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.1":
version: 3.3.1
resolution: "fast-glob@npm:3.3.1"
dependencies:
@@ -16330,6 +16534,18 @@ __metadata:
languageName: node
linkType: hard
+"intl-messageformat@npm:10.5.4":
+ version: 10.5.4
+ resolution: "intl-messageformat@npm:10.5.4"
+ dependencies:
+ "@formatjs/ecma402-abstract": 1.17.2
+ "@formatjs/fast-memoize": 2.2.0
+ "@formatjs/icu-messageformat-parser": 2.7.0
+ tslib: ^2.4.0
+ checksum: 1ac36b37134c435956762b5e9078314bb1d999992253c7ec884d135bf94eea160a3feede9d3c61c3b8a3016ca1553ba3fa3132bf95be4400c59ea95cb85a5ad6
+ languageName: node
+ linkType: hard
+
"invariant@npm:^2.2.4":
version: 2.2.4
resolution: "invariant@npm:2.2.4"
@@ -16591,7 +16807,7 @@ __metadata:
languageName: node
linkType: hard
-"is-node-process@npm:^1.2.0":
+"is-node-process@npm:^1.0.1, is-node-process@npm:^1.2.0":
version: 1.2.0
resolution: "is-node-process@npm:1.2.0"
checksum: 930765cdc6d81ab8f1bbecbea4a8d35c7c6d88a3ff61f3630e0fc7f22d624d7661c1df05c58547d0eb6a639dfa9304682c8e342c4113a6ed51472b704cee2928
@@ -17569,6 +17785,15 @@ __metadata:
languageName: node
linkType: hard
+"jiti@npm:^1.19.1":
+ version: 1.20.0
+ resolution: "jiti@npm:1.20.0"
+ bin:
+ jiti: bin/jiti.js
+ checksum: 7924062b5675142e3e272a27735be84b7bfc0a0eb73217fc2dcafa034f37c4f7b4b9ffc07dd98bcff0f739a8811ce1544db205ae7e97b1c86f0df92c65ce3c72
+ languageName: node
+ linkType: hard
+
"js-levenshtein@npm:^1.1.6":
version: 1.1.6
resolution: "js-levenshtein@npm:1.1.6"
@@ -17896,7 +18121,7 @@ __metadata:
"@navikt/aksel-icons": 5.6.1
"@navikt/ds-css": 5.6.1
"@navikt/ds-react": 5.6.1
- "@navikt/ds-tailwind": ^5.5.0
+ "@navikt/ds-tailwind": ^5.6.1
"@navikt/familie-endringslogg": 9.0.3
"@navikt/ft-plattform-komponenter": 2.3.5
"@pmmmwh/react-refresh-webpack-plugin": 0.5.11
@@ -17983,6 +18208,7 @@ __metadata:
lint-staged: 13.3.0
mini-css-extract-plugin: 2.7.6
msw: 1.3.1
+ msw-storybook-addon: ^1.8.0
node-cache: 5.1.2
postcss: ^8.4.30
postcss-import: ^15.1.0
@@ -19212,6 +19438,17 @@ __metadata:
languageName: node
linkType: hard
+"msw-storybook-addon@npm:^1.8.0":
+ version: 1.8.0
+ resolution: "msw-storybook-addon@npm:1.8.0"
+ dependencies:
+ is-node-process: ^1.0.1
+ peerDependencies:
+ msw: ">=0.35.0 <2.0.0"
+ checksum: 14d7ab064fcc548fe8169f029a2f02184387bd85267ea3c36d8076e671a13dc36349123f2f66fbd2930cedac929cf3ecbe7d45221d72918a9e83321305f3072c
+ languageName: node
+ linkType: hard
+
"msw@npm:1.3.1":
version: 1.3.1
resolution: "msw@npm:1.3.1"
@@ -22126,6 +22363,30 @@ __metadata:
languageName: node
linkType: hard
+"react-intl@npm:6.5.1":
+ version: 6.5.1
+ resolution: "react-intl@npm:6.5.1"
+ dependencies:
+ "@formatjs/ecma402-abstract": 1.17.2
+ "@formatjs/icu-messageformat-parser": 2.7.0
+ "@formatjs/intl": 2.9.5
+ "@formatjs/intl-displaynames": 6.6.1
+ "@formatjs/intl-listformat": 7.5.0
+ "@types/hoist-non-react-statics": ^3.3.1
+ "@types/react": 16 || 17 || 18
+ hoist-non-react-statics: ^3.3.2
+ intl-messageformat: 10.5.4
+ tslib: ^2.4.0
+ peerDependencies:
+ react: ^16.6.0 || 17 || 18
+ typescript: 5
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 9cdf4549d490f34bc664923b3eaaf42aed8e3a9453ebdeffb96cf7a21f5db251b39ae2a3885cdb365579759f6e46ec2bb8f6717324851768efd77e2ccf7fc820
+ languageName: node
+ linkType: hard
+
"react-is@npm:18.1.0":
version: 18.1.0
resolution: "react-is@npm:18.1.0"
@@ -22923,7 +23184,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4":
+"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.4":
version: 1.22.4
resolution: "resolve@npm:1.22.4"
dependencies:
@@ -22936,6 +23197,19 @@ __metadata:
languageName: node
linkType: hard
+"resolve@npm:^1.22.2":
+ version: 1.22.8
+ resolution: "resolve@npm:1.22.8"
+ dependencies:
+ is-core-module: ^2.13.0
+ path-parse: ^1.0.7
+ supports-preserve-symlinks-flag: ^1.0.0
+ bin:
+ resolve: bin/resolve
+ checksum: f8a26958aa572c9b064562750b52131a37c29d072478ea32e129063e2da7f83e31f7f11e7087a18225a8561cfe8d2f0df9dbea7c9d331a897571c0a2527dbb4c
+ languageName: node
+ linkType: hard
+
"resolve@npm:^2.0.0-next.4":
version: 2.0.0-next.4
resolution: "resolve@npm:2.0.0-next.4"
@@ -22949,7 +23223,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@^1.22.4#~builtin":
+"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.10.0#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.4#~builtin":
version: 1.22.4
resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=c3c19d"
dependencies:
@@ -22962,6 +23236,19 @@ __metadata:
languageName: node
linkType: hard
+"resolve@patch:resolve@^1.22.2#~builtin":
+ version: 1.22.8
+ resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d"
+ dependencies:
+ is-core-module: ^2.13.0
+ path-parse: ^1.0.7
+ supports-preserve-symlinks-flag: ^1.0.0
+ bin:
+ resolve: bin/resolve
+ checksum: 5479b7d431cacd5185f8db64bfcb7286ae5e31eb299f4c4f404ad8aa6098b77599563ac4257cb2c37a42f59dfc06a1bec2bcf283bb448f319e37f0feb9a09847
+ languageName: node
+ linkType: hard
+
"resolve@patch:resolve@^2.0.0-next.4#~builtin":
version: 2.0.0-next.4
resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d"
@@ -24329,18 +24616,18 @@ __metadata:
linkType: hard
"tailwindcss@npm:^3.3.3":
- version: 3.3.3
- resolution: "tailwindcss@npm:3.3.3"
+ version: 3.3.4
+ resolution: "tailwindcss@npm:3.3.4"
dependencies:
"@alloc/quick-lru": ^5.2.0
arg: ^5.0.2
chokidar: ^3.5.3
didyoumean: ^1.2.2
dlv: ^1.1.3
- fast-glob: ^3.2.12
+ fast-glob: ^3.3.0
glob-parent: ^6.0.2
is-glob: ^4.0.3
- jiti: ^1.18.2
+ jiti: ^1.19.1
lilconfig: ^2.1.0
micromatch: ^4.0.5
normalize-path: ^3.0.0
@@ -24357,7 +24644,7 @@ __metadata:
bin:
tailwind: lib/cli.js
tailwindcss: lib/cli.js
- checksum: 0195c7a3ebb0de5e391d2a883d777c78a4749f0c532d204ee8aea9129f2ed8e701d8c0c276aa5f7338d07176a3c2a7682c1d0ab9c8a6c2abe6d9325c2954eb50
+ checksum: 08fbd9caef721ab5100488f056e083c0753f5e1d65bdc37e84d9c5d46e9a0b00bfceeef1a8a1da616166508b2ba9443f7d56e93b89960d25a57085277229064e
languageName: node
linkType: hard
@@ -26105,9 +26392,9 @@ __metadata:
linkType: hard
"yaml@npm:^2.1.1":
- version: 2.3.2
- resolution: "yaml@npm:2.3.2"
- checksum: acd80cc24df12c808c6dec8a0176d404ef9e6f08ad8786f746ecc9d8974968c53c6e8a67fdfabcc5f99f3dc59b6bb0994b95646ff03d18e9b1dcd59eccc02146
+ version: 2.3.3
+ resolution: "yaml@npm:2.3.3"
+ checksum: cdfd132e7e0259f948929efe8835923df05c013c273c02bb7a2de9b46ac3af53c2778a35b32c7c0f877cc355dc9340ed564018c0242bfbb1278c2a3e53a0e99e
languageName: node
linkType: hard