🐛(frontend) fix mail domain creation form

- allow to submit form by pressing "Enter" key
- force focus on form when form is submited
but is invalid
- add error 500 handling
- update related e2e tests
This commit is contained in:
daproclaima
2024-08-21 14:14:48 +02:00
committed by Sebastien Nobour
parent 237d64b4c5
commit b5d8e92d1e
3 changed files with 253 additions and 80 deletions

View File

@@ -2,10 +2,16 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { Button, Input, Loader, ModalSize } from '@openfun/cunningham-react';
import { useRouter } from 'next/navigation';
import React from 'react';
import { Controller, FormProvider, useForm } from 'react-hook-form';
import {
Controller,
FormProvider,
UseFormReturn,
useForm,
} from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import { APIError } from '@/api';
import { Box, Text, TextErrors } from '@/components';
import { Modal } from '@/components/Modal';
import { useCreateMailDomain } from '@/features/mail-domains';
@@ -14,7 +20,68 @@ import { default as MailDomainsLogo } from '../assets/mail-domains-logo.svg';
const FORM_ID = 'form-add-mail-domain';
export const ModalCreateMailDomain = () => {
const useAddMailDomainApiError = ({
error,
methods,
}: {
error: APIError | null;
methods: UseFormReturn<{ name: string }> | null;
}): string[] | undefined => {
const [errorCauses, setErrorCauses] = React.useState<undefined | string[]>(
undefined,
);
const { t } = useTranslation();
React.useEffect(() => {
if (methods && t && error) {
let causes = undefined;
if (error.cause?.length) {
const parseCauses = (causes: string[]) =>
causes.reduce((arrayCauses, cause) => {
switch (cause) {
case 'Mail domain with this name already exists.':
case 'Mail domain with this Slug already exists.':
methods.setError('name', {
type: 'manual',
message: t(
'This mail domain is already used. Please, choose another one.',
),
});
break;
default:
arrayCauses.push(cause);
}
return arrayCauses;
}, [] as string[]);
causes = parseCauses(error.cause);
}
if (error.status === 500 || !error.cause) {
causes = [
t(
'Your request cannot be processed because the server is experiencing an error. If the problem ' +
'persists, please contact our support to resolve the issue: suiteterritoriale@anct.gouv.fr.',
),
];
}
setErrorCauses(causes);
}
}, [methods, t, error]);
React.useEffect(() => {
if (errorCauses && methods) {
methods.setFocus('name');
}
}, [methods, errorCauses]);
return errorCauses;
};
export const ModalAddMailDomain = () => {
const { t } = useTranslation();
const router = useRouter();
@@ -42,28 +109,16 @@ export const ModalCreateMailDomain = () => {
},
});
const onSubmitCallback = () => {
void methods.handleSubmit(({ name }, event) => {
event?.preventDefault();
const errorCauses = useAddMailDomainApiError({ error, methods });
const onSubmitCallback = (event: React.FormEvent) => {
event.preventDefault();
void methods.handleSubmit(({ name }) => {
void createMailDomain(name);
})();
};
const causes = error?.cause?.filter((cause) => {
const isFound = cause === 'Mail domain with this name already exists.';
if (isFound) {
methods.setError('name', {
type: 'manual',
message: t(
'This mail domain is already used. Please, choose another one.',
),
});
}
return !isFound;
});
if (!methods) {
return null;
}
@@ -82,7 +137,8 @@ export const ModalCreateMailDomain = () => {
onClose={() => router.push('/mail-domains/')}
rightActions={
<Button
onClick={onSubmitCallback}
type="submit"
form={FORM_ID}
disabled={!methods.watch('name') || isPending}
>
{t('Add the domain')}
@@ -98,8 +154,16 @@ export const ModalCreateMailDomain = () => {
</>
}
>
{!!errorCauses?.length ? (
<TextErrors
$margin={{ bottom: 'small' }}
$textAlign="left"
causes={errorCauses}
/>
) : null}
<FormProvider {...methods}>
<form action="" id={FORM_ID}>
<form id={FORM_ID} onSubmit={onSubmitCallback}>
<Controller
control={methods.control}
name="name"
@@ -123,7 +187,6 @@ export const ModalCreateMailDomain = () => {
)}
/>
</form>
{!!causes?.length ? <TextErrors causes={causes} /> : null}
{isPending && (
<Box $align="center">