Skip to content

Commit dc3803b

Browse files
Make UX more intuitive when fritekst save has failed
1 parent 1971656 commit dc3803b

File tree

5 files changed

+55
-11
lines changed

5 files changed

+55
-11
lines changed

frontend/src/components/case/innlogget/begrunnelse/begrunnelse-page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ const RenderCasebegrunnelsePage = ({ data }: Props) => {
138138
<BegrunnelseText
139139
caseId={data.id}
140140
value={data.fritekst}
141+
type={data.type}
141142
description={skjema.begrunnelse.begrunnelse_text.description[data.type]}
142143
placeholder={skjema.begrunnelse.begrunnelse_text.placeholder[data.type]}
143144
label={skjema.begrunnelse.begrunnelse_text.title[data.type]}

frontend/src/components/case/innlogget/begrunnelse/begrunnelse-text.tsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,25 @@ import { isError } from '@app/functions/is-api-error';
44
import { useOnUnmount } from '@app/hooks/use-on-unmount';
55
import { useTranslation } from '@app/language/use-translation';
66
import { useUpdateCaseMutation } from '@app/redux-api/case/api';
7+
import type { CaseType } from '@app/redux-api/case/types';
78
import { Textarea, type TextareaProps } from '@navikt/ds-react';
8-
import { useCallback, useEffect, useState } from 'react';
9+
import type { SerializedError } from '@reduxjs/toolkit';
10+
import type { FetchBaseQueryError } from '@reduxjs/toolkit/query';
11+
import { type ReactNode, useCallback, useEffect, useState } from 'react';
912

1013
interface Props extends Omit<TextareaProps, 'label' | 'onError' | 'onChange'> {
1114
caseId: string;
1215
value: string;
1316
label: string;
1417
modified: string;
18+
type: CaseType;
1519
}
1620

17-
export const BegrunnelseText = ({ caseId, value, modified, error, ...props }: Props) => {
21+
export const BegrunnelseText = ({ caseId, value, modified, error, type, ...props }: Props) => {
1822
const [localValue, setLocalValue] = useState(value);
19-
const [updateCase, status] = useUpdateCaseMutation({ fixedCacheKey: caseId });
23+
const [updateCase, { reset, ...status }] = useUpdateCaseMutation({ fixedCacheKey: caseId });
2024
const [lastSaved, setLastSaved] = useState<string>(modified);
21-
const { skjema } = useTranslation();
22-
const { failed } = skjema.begrunnelse.autosave;
25+
const errorMessage = useErrorMessage(type, status.error, error);
2326

2427
const updateFritekst = useCallback(
2528
async (newValue: string) => {
@@ -29,17 +32,15 @@ export const BegrunnelseText = ({ caseId, value, modified, error, ...props }: Pr
2932
[caseId, updateCase],
3033
);
3134

32-
const unauthorized = isError(status.error) && status.error.status === 401;
33-
3435
useEffect(() => {
35-
if (value === localValue || unauthorized) {
36+
if (value === localValue || status.isError) {
3637
return;
3738
}
3839

3940
const timeout = setTimeout(() => updateFritekst(localValue), 1000);
4041

4142
return () => clearTimeout(timeout);
42-
}, [value, localValue, updateFritekst, unauthorized]);
43+
}, [value, localValue, updateFritekst, status.isError]);
4344

4445
useOnUnmount(() => {
4546
if (value !== localValue) {
@@ -54,13 +55,31 @@ export const BegrunnelseText = ({ caseId, value, modified, error, ...props }: Pr
5455
maxLength={0}
5556
minLength={1}
5657
minRows={10}
57-
onChange={({ target }) => setLocalValue(target.value)}
58+
onChange={({ target }) => {
59+
reset(); // Reset (error) status for every change, so the user can see if the next save attempt fails or succeeds
60+
setLocalValue(target.value);
61+
}}
5862
value={localValue}
5963
placeholder="Skriv her"
60-
error={status.isError ? failed : error}
64+
error={errorMessage}
6165
{...props}
6266
/>
6367
<AutosaveProgressIndicator {...status} lastSaved={lastSaved} />
6468
</div>
6569
);
6670
};
71+
72+
const useErrorMessage = (
73+
type: CaseType,
74+
rtkqError: FetchBaseQueryError | SerializedError | undefined,
75+
validationError: ReactNode,
76+
) => {
77+
const { skjema } = useTranslation();
78+
const { failed } = skjema.begrunnelse.autosave;
79+
80+
if (isError(rtkqError) && rtkqError.status === 409) {
81+
return skjema.begrunnelse.errors.finished[type];
82+
}
83+
84+
return rtkqError === undefined ? validationError : failed;
85+
};

frontend/src/language/en.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ export const en: Translations = {
129129
[CaseType.ETTERSENDELSE_KLAGE]: 'Delete additional documentation and return to start page',
130130
[CaseType.ETTERSENDELSE_ANKE]: 'Delete additional documentation and return to start page',
131131
},
132+
errors: {
133+
finished: {
134+
[CaseType.KLAGE]: 'The complaint has already been submitted',
135+
[CaseType.ANKE]: 'The appeal has already been submitted',
136+
[CaseType.ETTERSENDELSE_KLAGE]: 'The additional documentation has already been submitted',
137+
[CaseType.ETTERSENDELSE_ANKE]: 'The additional documentation has already been submitted',
138+
},
139+
},
132140
},
133141
summary: {
134142
title: {

frontend/src/language/nb.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ export const nb = {
133133
[CaseType.ETTERSENDELSE_KLAGE]: 'Slett ettersendelsen og returner til hovedsiden',
134134
[CaseType.ETTERSENDELSE_ANKE]: 'Slett ettersendelsen og returner til hovedsiden',
135135
},
136+
errors: {
137+
finished: {
138+
[CaseType.KLAGE]: 'Klagen er allerede sendt inn',
139+
[CaseType.ANKE]: 'Anken er allerede sendt inn',
140+
[CaseType.ETTERSENDELSE_KLAGE]: 'Ettersendelsen er allerede sendt inn',
141+
[CaseType.ETTERSENDELSE_ANKE]: 'Ettersendelsen er allerede sendt inn',
142+
},
143+
},
136144
},
137145
summary: {
138146
title: {

frontend/src/language/nn.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ export const nn: Translations = {
132132
[CaseType.ETTERSENDELSE_KLAGE]: 'Slett ettersendinga og gå tilbake til hovudsida',
133133
[CaseType.ETTERSENDELSE_ANKE]: 'Slett ettersendinga og gå tilbake til hovudsida',
134134
},
135+
errors: {
136+
finished: {
137+
[CaseType.KLAGE]: 'Klaga er allereie sendt inn',
138+
[CaseType.ANKE]: 'Anka er allereie sendt inn',
139+
[CaseType.ETTERSENDELSE_KLAGE]: 'Ettersendinga er allereie sendt inn',
140+
[CaseType.ETTERSENDELSE_ANKE]: 'Ettersendinga er allereie sendt inn',
141+
},
142+
},
135143
},
136144
summary: {
137145
title: {

0 commit comments

Comments
 (0)