Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saksnummer #530

Merged
merged 3 commits into from
Mar 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified frontend/bun.lockb
Binary file not shown.
12 changes: 6 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@
},
"devDependencies": {
"@types/bun": "1.2.5",
"@types/react": "19.0.10",
"@types/react": "19.0.11",
"@types/react-dom": "19.0.4",
"@types/react-redux": "7.1.34",
"@vitejs/plugin-react": "4.3.4",
"typescript": "5.8.2",
"vite": "6.2.1",
"vite": "6.2.2",
"vite-tsconfig-paths": "5.1.4"
},
"dependencies": {
"@biomejs/biome": "1.9.4",
"@grafana/faro-react": "1.14.1",
"@grafana/faro-web-sdk": "1.14.1",
"@grafana/faro-web-tracing": "1.14.1",
"@navikt/aksel-icons": "7.17.2",
"@navikt/ds-css": "7.17.2",
"@navikt/ds-react": "7.17.2",
"@navikt/aksel-icons": "7.17.3",
"@navikt/ds-css": "7.17.3",
"@navikt/ds-react": "7.17.3",
"@navikt/fnrvalidator": "2.1.5",
"@navikt/nav-dekoratoren-moduler": "3.2.2",
"@reduxjs/toolkit": "2.6.1",
Expand All @@ -40,6 +40,6 @@
"react-redux": "9.2.0",
"react-router": "7.3.0",
"react-router-dom": "7.3.0",
"styled-components": "6.1.15"
"styled-components": "6.1.16"
}
}
74 changes: 34 additions & 40 deletions frontend/src/components/case/common/saksnummer.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { FormFieldsIds } from '@app/components/case/common/form-fields-ids';
import { useTranslation } from '@app/language/use-translation';
import { PencilIcon } from '@navikt/aksel-icons';
import { BodyShort, Button, Label, TextField } from '@navikt/ds-react';
import { useEffect, useRef, useState } from 'react';
import { styled } from 'styled-components';
import { BodyShort, Heading, TextField } from '@navikt/ds-react';
import { useEffect, useState } from 'react';

interface Props {
interface UserSaksnummerProps {
value: string | null;
internalSaksnummer?: string | null;
onChange: (saksnummer: string | null) => void;
error: string | undefined;
}

export const DebouncedSaksnummer = ({ value, onChange, ...props }: Props) => {
interface Props extends UserSaksnummerProps {
internalSaksnummer: string | null;
}

const DebouncedUserSaksnummer = ({ value, onChange, error }: UserSaksnummerProps) => {
const [localValue, setLocalValue] = useState(value);

useEffect(() => {
Expand All @@ -25,56 +26,49 @@ export const DebouncedSaksnummer = ({ value, onChange, ...props }: Props) => {
return () => clearTimeout(timeout);
}, [onChange, value, localValue]);

return <Saksnummer {...props} value={localValue} onChange={setLocalValue} />;
return <UserSaksnummer error={error} value={localValue} onChange={setLocalValue} />;
};

export const Saksnummer = ({ value, internalSaksnummer, onChange, error }: Props) => {
const inputRef = useRef<HTMLInputElement>(null);
const InternalSaksnummer = ({ internalSaksnummer }: { internalSaksnummer: string }) => {
const { skjema } = useTranslation();

const usersaksnummer = (
if (typeof internalSaksnummer === 'string' && internalSaksnummer.length !== 0) {
return (
<section>
<Heading size="xsmall">{skjema.begrunnelse.saksnummer.internalTitle}</Heading>
<BodyShort>{internalSaksnummer}</BodyShort>
</section>
);
}
};

const UserSaksnummer = ({ value, onChange, error }: UserSaksnummerProps) => {
const { skjema } = useTranslation();

return (
<TextField
id={FormFieldsIds.SAKSNUMMER}
label={skjema.begrunnelse.saksnummer.title}
value={value ?? ''}
onChange={({ target }) => onChange(target.value)}
htmlSize={24}
error={error}
ref={inputRef}
/>
);
};

if (value !== null) {
return usersaksnummer;
export const Saksnummer = ({ value, internalSaksnummer, onChange, error }: Props) => {
if (typeof internalSaksnummer === 'string' && internalSaksnummer.length !== 0) {
return <InternalSaksnummer internalSaksnummer={internalSaksnummer} />;
}

return <UserSaksnummer value={value} onChange={onChange} error={error} />;
};

export const DebouncedSaksnummer = ({ value, internalSaksnummer, onChange, error }: Props) => {
if (typeof internalSaksnummer === 'string' && internalSaksnummer.length !== 0) {
return (
<div>
<Label>{skjema.begrunnelse.saksnummer.internalTitle}</Label>
<Row>
<BodyShort>{internalSaksnummer}</BodyShort>
<Button
title={skjema.begrunnelse.saksnummer.change}
onClick={() => {
onChange(internalSaksnummer);
setTimeout(() => inputRef.current?.focus(), 0);
}}
size="small"
icon={<PencilIcon aria-hidden />}
variant="tertiary"
/>
</Row>
</div>
);
return <InternalSaksnummer internalSaksnummer={internalSaksnummer} />;
}

return usersaksnummer;
return <DebouncedUserSaksnummer value={value} onChange={onChange} error={error} />;
};

const Row = styled.div`
display: flex;
flex-direction: row;
align-items: center;
column-gap: 8px;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useTranslation } from '@app/language/use-translation';
import { AppEventEnum } from '@app/logging/action';
import { appEvent } from '@app/logging/logger';
import { useDeleteAttachmentMutation, useDeleteCaseMutation, useUpdateCaseMutation } from '@app/redux-api/case/api';
import { type Case, CaseStatus, CaseType, type CaseUpdatable } from '@app/redux-api/case/types';
import { type Case, CaseStatus, CaseType, type UpdateCaseFields } from '@app/redux-api/case/types';
import { API_PATH } from '@app/redux-api/common';
import { CenteredContainer } from '@app/styled-components/common';
import { BodyLong, Button, GuidePanel } from '@navikt/ds-react';
Expand Down Expand Up @@ -89,7 +89,7 @@ const RenderCasebegrunnelsePage = ({ data }: Props) => {
const isEttersendelseKlage = data.type === CaseType.ETTERSENDELSE_KLAGE;

const onChange = useCallback(
async <T extends keyof CaseUpdatable>(key: T, value: CaseUpdatable[T]) => {
async <T extends keyof UpdateCaseFields>(key: T, value: UpdateCaseFields[T]) => {
await updateCase({ key, value, id: data.id });
},
[data.id, updateCase],
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/components/case/uinnlogget/session-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useIsAuthenticated } from '@app/hooks/use-user';
import type { Innsendingsytelse } from '@app/innsendingsytelser/innsendingsytelser';
import { useLanguage } from '@app/language/use-language';
import { useTranslation } from '@app/language/use-translation';
import { CASE_TYPE_PATH_SEGMENTS, type CaseType } from '@app/redux-api/case/types';
import { CASE_TYPE_PATH_SEGMENTS, type CaseType, type DeepLinkParams } from '@app/redux-api/case/types';
import { useMemo } from 'react';
import { Navigate, useSearchParams } from 'react-router-dom';
import { LoadingPage } from '../../loading-page/loading-page';
import type { ISessionCase } from './types';
Expand All @@ -19,8 +20,16 @@ export const KlageSessionLoader = ({ Component, innsendingsytelse, type }: Props
const { isAuthenticated, isLoadingAuth } = useIsAuthenticated();
const [query] = useSearchParams();
const internalSaksnummer = getQueryValue(query.get('saksnummer'));
const sakSakstype = getQueryValue(query.get('sakstype'));
const sakFagsaksystem = getQueryValue(query.get('fagsystem'));
const caseIsAtKA = getBooleanQueryValue(query.get('ka')) ? true : null;
const [data, isLoading] = useSessionCase(type, innsendingsytelse, internalSaksnummer, caseIsAtKA);

const deepLinkParams: DeepLinkParams = useMemo(
() => ({ internalSaksnummer, sakSakstype, sakFagsaksystem, caseIsAtKA }),
[internalSaksnummer, sakSakstype, sakFagsaksystem, caseIsAtKA],
);

const [data, isLoading] = useSessionCase(type, innsendingsytelse, deepLinkParams);
const { case_loader: klage_loader, user_loader } = useTranslation();
const language = useLanguage();

Expand Down
6 changes: 2 additions & 4 deletions frontend/src/components/case/uinnlogget/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import type { ISODate } from '@app/domain/date/date';
import type { Innsendingsytelse } from '@app/innsendingsytelser/innsendingsytelser';
import type { CaseType, Reason } from '@app/redux-api/case/types';
import type { CaseType, DeepLinkParams, Reason } from '@app/redux-api/case/types';
import type { IName } from '@app/redux-api/user/types';

export interface ISessionCase {
export interface ISessionCase extends DeepLinkParams {
readonly id: string;
readonly type: CaseType;
readonly checkboxesSelected: Reason[];
readonly foedselsnummer: string;
readonly navn: IName;
readonly caseIsAtKA: boolean | null;
readonly fritekst: string;
readonly userSaksnummer: string | null;
readonly internalSaksnummer: string | null;
readonly vedtakDate: ISODate | null;
readonly innsendingsytelse: Innsendingsytelse;
readonly hasVedlegg: boolean;
Expand Down
15 changes: 4 additions & 11 deletions frontend/src/hooks/use-session-klage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ISessionCase } from '@app/components/case/uinnlogget/types';
import type { Innsendingsytelse } from '@app/innsendingsytelser/innsendingsytelser';
import type { CaseType } from '@app/redux-api/case/types';
import type { CaseType, DeepLinkParams } from '@app/redux-api/case/types';
import { useAppDispatch, useAppSelector } from '@app/redux/configure-store';
import { getSessionCaseKey } from '@app/redux/session/klage/helpers';
import { loadOrCreateSessionCase } from '@app/redux/session/session';
Expand All @@ -9,8 +9,7 @@ import { useEffect, useMemo } from 'react';
export const useSessionCase = (
type: CaseType,
innsendingsytelse: Innsendingsytelse,
internalSaksnummer: string | null,
caseIsAtKA: true | null,
deepLinkParams: DeepLinkParams,
): [ISessionCase, false] | [undefined, true] => {
const dispatch = useAppDispatch();
const sessionCaseMap = useAppSelector((state) => state.session);
Expand All @@ -22,15 +21,9 @@ export const useSessionCase = (

useEffect(() => {
if (data === undefined) {
dispatch(
loadOrCreateSessionCase({
type,
innsendingsytelse,
data: { innsendingsytelse, internalSaksnummer, caseIsAtKA },
}),
);
dispatch(loadOrCreateSessionCase({ type, innsendingsytelse, deepLinkParams }));
}
}, [dispatch, innsendingsytelse, internalSaksnummer, data, type, caseIsAtKA]);
}, [data, dispatch, deepLinkParams, innsendingsytelse, type]);

if (data === undefined) {
return [undefined, true];
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/logging/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export enum AppEventEnum {
CASE_INVALID = 'Invalid case data',
CASE_JOURNALFØRT = 'Case journalført',
CASE_RESUME_SESSION = 'Resume session case',
CASE_RESUME_SESSION_WITH_SAKSNUMMER = 'Resume session case with internal saksnummer',
CASE_RESUME_SESSION_WITH_CHANGED_DEEP_LINK = 'Resume session case changed deep link',
CASE_SUBMIT = 'Click submit button',
CASE_VALID = 'Valid case data',
CLEAR_ERRORS = 'Clear errors',
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/redux-api/case/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { AppEventEnum } from '@app/logging/action';
import { appEvent } from '@app/logging/logger';
import type {
CreateCaseParams,
DeleteAttachmentParams,
ResumeCaseParams,
UpdateCaseParams,
Expand All @@ -11,6 +10,7 @@ import { type Attachment, type BaseCase, type Case, CaseStatus, type FinalizedCa
import { API_BASE_QUERY, API_PATH } from '@app/redux-api/common';
import { ServerSentEventManager, ServerSentEventType } from '@app/redux-api/server-sent-events';
import { createApi } from '@reduxjs/toolkit/query/react';
import type { CreateCaseFields } from './types';

type BaseUpdateResponse = Pick<BaseCase, 'modifiedByUser'>;

Expand Down Expand Up @@ -59,7 +59,7 @@ export const caseApi = createApi({
dispatch(caseApi.util.updateQueryData('getCase', data.id, () => data));
},
}),
createCase: builder.mutation<Case, CreateCaseParams>({
createCase: builder.mutation<Case, CreateCaseFields>({
query: (body) => ({
method: 'POST',
url: '/klanker',
Expand Down
26 changes: 5 additions & 21 deletions frontend/src/redux-api/case/params.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
import type { Innsendingsytelse } from '@app/innsendingsytelser/innsendingsytelser';
import type { BaseCase, CaseType, CaseUpdatable } from '@app/redux-api/case/types';
import type { BaseCase, CaseType, DeepLinkParams, UpdateCaseFields } from '@app/redux-api/case/types';

export type CreateCaseParams = Pick<
BaseCase,
| 'innsendingsytelse'
| 'userSaksnummer'
| 'vedtakDate'
| 'internalSaksnummer'
| 'fritekst'
| 'hasVedlegg'
| 'type'
| 'caseIsAtKA'
| 'checkboxesSelected'
| 'language'
>;

interface CaseUpdate<T extends keyof CaseUpdatable> {
interface CaseUpdate<T extends keyof UpdateCaseFields> {
readonly id: BaseCase['id'];
readonly key: T;
readonly value: CaseUpdatable[T];
readonly value: UpdateCaseFields[T];
}

export type UpdateCaseParams = CaseUpdate<keyof CaseUpdatable>;
export type UpdateCaseParams = CaseUpdate<keyof UpdateCaseFields>;

export interface UploadAttachmentParams {
file: File;
Expand All @@ -33,9 +19,7 @@ export interface DeleteAttachmentParams {
attachmentId: number;
}

export interface ResumeCaseParams {
export interface ResumeCaseParams extends DeepLinkParams {
readonly type: CaseType;
readonly innsendingsytelse: Innsendingsytelse;
readonly internalSaksnummer: string | null;
readonly caseIsAtKA: true | null;
}
41 changes: 24 additions & 17 deletions frontend/src/redux-api/case/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,37 @@ export interface FinalizedCase {
readonly modifiedByUser: ISODateTime;
}

export interface BaseCase {
export interface DeepLinkParams {
readonly caseIsAtKA: boolean | null;
readonly internalSaksnummer: string | null;
readonly sakFagsaksystem: string | null;
readonly sakSakstype: string | null;
}

interface ReadOnlyFields {
readonly id: string;
readonly fritekst: string;
readonly status: CaseStatus;
readonly finalizedDate: ISODate | null;
readonly journalpostId: string | null;
readonly modifiedByUser: ISODateTime;
readonly status: CaseStatus;
readonly vedlegg: Attachment[];
readonly journalpostId: string | null;
readonly finalizedDate: ISODate | null;
readonly vedtakDate: ISODate | null;
readonly userSaksnummer: string | null;
readonly internalSaksnummer: string | null;
readonly language: Languages;
readonly innsendingsytelse: Innsendingsytelse;
}

export interface UpdateCaseFields extends DeepLinkParams {
readonly checkboxesSelected: Reason[];
readonly fritekst: string;
readonly hasVedlegg: boolean;
readonly userSaksnummer: string | null;
readonly vedtakDate: ISODate | null;
}

export interface CreateCaseFields extends UpdateCaseFields {
readonly type: CaseType;
readonly checkboxesSelected: Reason[];
readonly caseIsAtKA: boolean | null;
readonly innsendingsytelse: Innsendingsytelse;
readonly language: Languages;
}

export type CaseUpdatable = Pick<
BaseCase,
'vedtakDate' | 'checkboxesSelected' | 'userSaksnummer' | 'hasVedlegg' | 'fritekst' | 'caseIsAtKA'
>;
export type BaseCase = ReadOnlyFields & CreateCaseFields;

export interface Klage extends BaseCase {
readonly type: CaseType.KLAGE;
Expand All @@ -52,7 +60,6 @@ export interface Anke extends BaseCase {

export interface EttersendelseKlage extends BaseCase {
readonly type: CaseType.ETTERSENDELSE_KLAGE;
readonly caseIsAtKA: boolean | null;
}

export interface EttersendelseAnke extends BaseCase {
Expand Down
Loading
Loading