Skip to content

Commit 506cb3d

Browse files
CCM-8579: Client side validation
1 parent 0b9cdc1 commit 506cb3d

File tree

3 files changed

+59
-40
lines changed

3 files changed

+59
-40
lines changed

frontend/src/components/forms/LetterTemplateForm/LetterTemplateForm.tsx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { FC, useActionState } from 'react';
3+
import { FC, useActionState, useState } from 'react';
44
import {
55
TextInput,
66
HintText,
@@ -16,6 +16,7 @@ import {
1616
alphabeticalLanguageList,
1717
alphabeticalLetterTypeList,
1818
CreateLetterTemplate,
19+
FormErrorState,
1920
PageComponentProps,
2021
} from 'nhs-notify-web-template-management-utils';
2122
import content from '@content/content';
@@ -24,6 +25,7 @@ import { NHSNotifyMain } from '@atoms/NHSNotifyMain/NHSNotifyMain';
2425
import { NHSNotifyButton } from '@atoms/NHSNotifyButton/NHSNotifyButton';
2526
import FileUpload from '@atoms/FileUpload/FileUpload';
2627
import { getBasePath } from '@utils/get-base-path';
28+
import { $CreateLetterTemplateSchema } from './form-schema';
2729

2830
export const LetterTemplateForm: FC<
2931
PageComponentProps<CreateLetterTemplate>
@@ -50,6 +52,9 @@ export const LetterTemplateForm: FC<
5052
} = content.components.templateFormLetter;
5153

5254
const [state, action] = useActionState(processFormActions, initialState);
55+
const [validationError, setValidationError] = useState<
56+
FormErrorState | undefined
57+
>(state.validationError);
5358

5459
const [letterTemplateName, letterTemplateNameHandler] =
5560
useTextInput<HTMLInputElement>(state.name);
@@ -61,19 +66,29 @@ export const LetterTemplateForm: FC<
6166
useTextInput<HTMLSelectElement>(state.language);
6267

6368
const templateNameError =
64-
state.validationError?.fieldErrors.letterTemplateName?.join(', ');
69+
validationError?.fieldErrors.letterTemplateName?.join(', ');
6570

6671
const templateLetterTypeError =
67-
state.validationError?.fieldErrors.letterTemplateLetterType?.join(', ');
72+
validationError?.fieldErrors.letterTemplateLetterType?.join(', ');
6873

6974
const templateLanguageError =
70-
state.validationError?.fieldErrors.letterTemplateLanguage?.join(', ');
75+
validationError?.fieldErrors.letterTemplateLanguage?.join(', ');
7176

7277
const templatePdfError =
73-
state.validationError?.fieldErrors.letterTemplatePdf?.join(', ');
78+
validationError?.fieldErrors.letterTemplatePdf?.join(', ');
7479

7580
const templateCsvError =
76-
state.validationError?.fieldErrors.letterTemplateCsv?.join(', ');
81+
validationError?.fieldErrors.letterTemplateCsv?.join(', ');
82+
83+
const validateForm = (event: React.FormEvent<HTMLFormElement>) => {
84+
const formData = new FormData(event.currentTarget);
85+
const data = Object.fromEntries(formData);
86+
const validationResult = $CreateLetterTemplateSchema.safeParse(data);
87+
if (!validationResult.success) {
88+
event.preventDefault();
89+
setValidationError(validationResult.error.flatten());
90+
}
91+
};
7792

7893
return (
7994
<>
@@ -87,6 +102,7 @@ export const LetterTemplateForm: FC<
87102
<NHSNotifyFormWrapper
88103
action={action}
89104
formId='create-letter-template'
105+
formAttributes={{ onSubmit: validateForm }}
90106
>
91107
<h1 className='nhsuk-heading-xl' data-testid='page-heading'>
92108
{pageHeading}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { LANGUAGE_LIST, LETTER_TYPE_LIST } from 'nhs-notify-backend-client';
2+
import { z } from 'zod';
3+
4+
export const $CreateLetterTemplateSchema = z.object({
5+
letterTemplateName: z
6+
.string({ message: 'Enter a template name' })
7+
.min(1, { message: 'Enter a template name' }),
8+
letterTemplateLetterType: z.enum(LETTER_TYPE_LIST, {
9+
message: 'Choose a letter type',
10+
}),
11+
letterTemplateLanguage: z.enum(LANGUAGE_LIST, {
12+
message: 'Choose a language',
13+
}),
14+
letterTemplatePdf: z
15+
.instanceof(File, {
16+
message: 'Select a letter template PDF',
17+
})
18+
.refine((pdf) => pdf.size <= 5 * 1024 * 1024, {
19+
message: `The letter template PDF is too large. The file must be smaller than 5MB`,
20+
})
21+
.refine((pdf) => pdf.type === 'application/pdf', {
22+
message: 'Select a letter template PDF',
23+
}),
24+
letterTemplateCsv: z
25+
.instanceof(File, {
26+
message: 'Select a valid test data .csv file',
27+
})
28+
.refine((csv) => csv.size <= 10 * 1024, {
29+
message: `The test data CSV is too large. The file must be smaller than 10KB`,
30+
})
31+
.refine((csv) => csv.size === 0 || csv.type === 'text/csv', {
32+
message: 'Select a valid test data .csv file',
33+
}),
34+
});

frontend/src/components/forms/LetterTemplateForm/server-action.ts

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,13 @@
1-
import { z } from 'zod';
1+
'use server';
2+
23
import { createLetterTemplate } from '@utils/form-actions';
34
import { redirect, RedirectType } from 'next/navigation';
4-
import { LANGUAGE_LIST, LETTER_TYPE_LIST } from 'nhs-notify-backend-client';
55
import {
66
CreateLetterTemplate,
77
LetterTemplate,
88
TemplateFormState,
99
} from 'nhs-notify-web-template-management-utils';
10-
11-
const $CreateLetterTemplateSchema = z.object({
12-
letterTemplateName: z
13-
.string({ message: 'Enter a template name' })
14-
.min(1, { message: 'Enter a template name' }),
15-
letterTemplateLetterType: z.enum(LETTER_TYPE_LIST, {
16-
message: 'Choose a letter type',
17-
}),
18-
letterTemplateLanguage: z.enum(LANGUAGE_LIST, {
19-
message: 'Choose a language',
20-
}),
21-
letterTemplatePdf: z
22-
.instanceof(File, {
23-
message: 'Select a letter template PDF',
24-
})
25-
.refine((pdf) => pdf.size <= 5 * 1024 * 1024, {
26-
message: `The letter template PDF is too large. The file must be smaller than 5MB`,
27-
})
28-
.refine((pdf) => pdf.type === 'application/pdf', {
29-
message: 'Select a letter template PDF',
30-
}),
31-
letterTemplateCsv: z
32-
.instanceof(File, {
33-
message: 'Select a valid test data .csv file',
34-
})
35-
.refine((csv) => csv.size <= 10 * 1024, {
36-
message: `The test data CSV is too large. The file must be smaller than 10KB`,
37-
})
38-
.refine((csv) => csv.size === 0 || csv.type === 'text/csv', {
39-
message: 'Select a valid test data .csv file',
40-
}),
41-
});
10+
import { $CreateLetterTemplateSchema } from './form-schema';
4211

4312
export async function processFormActions(
4413
formState: TemplateFormState<CreateLetterTemplate | LetterTemplate>,

0 commit comments

Comments
 (0)