refactor(Form): centralize error management
This commit is contained in:
@@ -2,6 +2,7 @@ import * as React from 'react';
|
|||||||
import { FormProvider, useForm, useWatch } from 'react-hook-form';
|
import { FormProvider, useForm, useWatch } from 'react-hook-form';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import useFormatMessage from 'hooks/useFormatMessage';
|
||||||
|
|
||||||
const noop = () => null;
|
const noop = () => null;
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ function Form(props) {
|
|||||||
...formProps
|
...formProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const formatMessage = useFormatMessage();
|
||||||
|
|
||||||
const methods = useForm({
|
const methods = useForm({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
reValidateMode,
|
reValidateMode,
|
||||||
@@ -25,6 +28,8 @@ function Form(props) {
|
|||||||
mode,
|
mode,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { setError } = methods;
|
||||||
|
|
||||||
const form = useWatch({ control: methods.control });
|
const form = useWatch({ control: methods.control });
|
||||||
const prevDefaultValues = React.useRef(defaultValues);
|
const prevDefaultValues = React.useRef(defaultValues);
|
||||||
|
|
||||||
@@ -44,12 +49,51 @@ function Form(props) {
|
|||||||
}
|
}
|
||||||
}, [defaultValues]);
|
}, [defaultValues]);
|
||||||
|
|
||||||
|
const handleErrors = React.useCallback(
|
||||||
|
function (errors) {
|
||||||
|
if (!errors) return;
|
||||||
|
|
||||||
|
let shouldSetGenericGeneralError = true;
|
||||||
|
const fieldNames = Object.keys(defaultValues);
|
||||||
|
|
||||||
|
Object.entries(errors).forEach(([fieldName, fieldErrors]) => {
|
||||||
|
if (fieldNames.includes(fieldName) && Array.isArray(fieldErrors)) {
|
||||||
|
shouldSetGenericGeneralError = false;
|
||||||
|
setError(fieldName, {
|
||||||
|
type: 'fieldRequestError',
|
||||||
|
message: fieldErrors.join(', '),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// in case of general errors
|
||||||
|
if (Array.isArray(errors.general)) {
|
||||||
|
for (const error of errors.general) {
|
||||||
|
shouldSetGenericGeneralError = false;
|
||||||
|
setError('root.general', { type: 'requestError', message: error });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSetGenericGeneralError) {
|
||||||
|
setError('root.general', {
|
||||||
|
type: 'requestError',
|
||||||
|
message: formatMessage('form.genericError'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[defaultValues, formatMessage, setError],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<form
|
<form
|
||||||
onSubmit={methods.handleSubmit((data, event) =>
|
onSubmit={methods.handleSubmit(async (data, event) => {
|
||||||
onSubmit?.(data, event, methods.setError),
|
try {
|
||||||
)}
|
return await onSubmit?.(data);
|
||||||
|
} catch (errors) {
|
||||||
|
handleErrors(errors);
|
||||||
|
}
|
||||||
|
})}
|
||||||
{...formProps}
|
{...formProps}
|
||||||
>
|
>
|
||||||
{render ? render(methods) : children}
|
{render ? render(methods) : children}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function InstallationForm() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async ({ fullName, email, password }, e, setError) => {
|
const handleSubmit = async ({ fullName, email, password }) => {
|
||||||
try {
|
try {
|
||||||
await install({
|
await install({
|
||||||
fullName,
|
fullName,
|
||||||
@@ -77,29 +77,8 @@ function InstallationForm() {
|
|||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errors = error?.response?.data?.errors;
|
const errors = error?.response?.data?.errors;
|
||||||
if (errors) {
|
|
||||||
const fieldNames = Object.keys(defaultValues);
|
|
||||||
Object.entries(errors).forEach(([fieldName, fieldErrors]) => {
|
|
||||||
if (fieldNames.includes(fieldName) && Array.isArray(fieldErrors)) {
|
|
||||||
setError(fieldName, {
|
|
||||||
type: 'fieldRequestError',
|
|
||||||
message: fieldErrors.join(', '),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const generalError = getGeneralErrorMessage({
|
throw errors;
|
||||||
error,
|
|
||||||
fallbackMessage: formatMessage('installationForm.error'),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (generalError) {
|
|
||||||
setError('root.general', {
|
|
||||||
type: 'requestError',
|
|
||||||
message: generalError,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
export default function useFormatMessage() {
|
export default function useFormatMessage() {
|
||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
return (id, values = {}) => formatMessage({ id }, values);
|
|
||||||
|
const customFormatMessage = React.useCallback(
|
||||||
|
(id, values = {}) => formatMessage({ id }, values),
|
||||||
|
[formatMessage],
|
||||||
|
);
|
||||||
|
|
||||||
|
return customFormatMessage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,7 @@
|
|||||||
"webhookUrlInfo.description": "You'll need to configure your application with this webhook URL.",
|
"webhookUrlInfo.description": "You'll need to configure your application with this webhook URL.",
|
||||||
"webhookUrlInfo.helperText": "We've generated a custom webhook URL for you to send requests to. <link>Learn more about webhooks</link>.",
|
"webhookUrlInfo.helperText": "We've generated a custom webhook URL for you to send requests to. <link>Learn more about webhooks</link>.",
|
||||||
"webhookUrlInfo.copy": "Copy",
|
"webhookUrlInfo.copy": "Copy",
|
||||||
|
"form.genericError": "Something went wrong. Please try again.",
|
||||||
"installationForm.title": "Installation",
|
"installationForm.title": "Installation",
|
||||||
"installationForm.fullNameFieldLabel": "Full name",
|
"installationForm.fullNameFieldLabel": "Full name",
|
||||||
"installationForm.emailFieldLabel": "Email",
|
"installationForm.emailFieldLabel": "Email",
|
||||||
@@ -141,7 +142,6 @@
|
|||||||
"installationForm.passwordMinLength": "Password must be at least 6 characters long.",
|
"installationForm.passwordMinLength": "Password must be at least 6 characters long.",
|
||||||
"installationForm.mandatoryInput": "{inputName} is required.",
|
"installationForm.mandatoryInput": "{inputName} is required.",
|
||||||
"installationForm.success": "The admin account has been created, and thus, the installation has been completed. You can now log in <link>here</link>.",
|
"installationForm.success": "The admin account has been created, and thus, the installation has been completed. You can now log in <link>here</link>.",
|
||||||
"installationForm.error": "Something went wrong. Please try again.",
|
|
||||||
"signupForm.title": "Sign up",
|
"signupForm.title": "Sign up",
|
||||||
"signupForm.fullNameFieldLabel": "Full name",
|
"signupForm.fullNameFieldLabel": "Full name",
|
||||||
"signupForm.emailFieldLabel": "Email",
|
"signupForm.emailFieldLabel": "Email",
|
||||||
|
|||||||
Reference in New Issue
Block a user