refactor(ui): Optimizing schema forms

This commit is contained in:
robin 2022-11-15 16:08:42 +08:00
parent ba66cccb8b
commit bc904d8d59
3 changed files with 53 additions and 31 deletions

View File

@ -51,8 +51,7 @@ export interface UISchema {
| 'url'
| 'week';
empty?: string;
invalid?: string;
validator?: (value) => boolean;
validator?: (value) => Promise<string | true | void> | true | string;
textRender?: () => React.ReactElement;
imageType?: Type.UploadType;
acceptType?: string;
@ -109,21 +108,50 @@ const SchemaForm: FC<IProps> = ({
};
const syncValidator = () => {
const errors: string[] = [];
const errors: Array<{ key: string; msg: string }> = [];
const promises: Array<{
key: string;
promise;
}> = [];
keys.forEach((key) => {
const { validator } = uiSchema[key]?.['ui:options'] || {};
if (validator instanceof Function) {
const value = formData[key]?.value;
if (!validator(value)) {
errors.push(key);
}
promises.push({
key,
promise: validator(value),
});
}
});
return errors;
return Promise.allSettled(promises.map((item) => item.promise)).then(
(results) => {
results.forEach((result, index) => {
const { key } = promises[index];
if (result.status === 'rejected') {
errors.push({
key,
msg: result.reason.message,
});
}
if (result.status === 'fulfilled') {
const msg = result.value;
if (typeof msg === 'string') {
errors.push({
key,
msg,
});
}
}
});
return errors;
},
);
};
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const errors = requiredValidator();
if (errors.length > 0) {
formData = errors.reduce((acc, cur) => {
@ -131,30 +159,29 @@ const SchemaForm: FC<IProps> = ({
...formData[cur],
isInvalid: true,
errorMsg:
uiSchema[cur]['ui:options']?.empty ||
`${schema.properties[cur].title} ${t('form.empty')}`,
uiSchema[cur]?.['ui:options']?.empty ||
`${schema.properties[cur].title} ${t('empty')}`,
};
return acc;
}, formData);
if (onChange instanceof Function) {
onChange(formData);
onChange({ ...formData });
}
return;
}
const syncErrors = syncValidator();
const syncErrors = await syncValidator();
if (syncErrors.length > 0) {
formData = syncErrors.reduce((acc, cur) => {
acc[cur] = {
...formData[cur],
acc[cur.key] = {
...formData[cur.key],
isInvalid: true,
errorMsg:
uiSchema[cur]['ui:options']?.invalid ||
`${schema.properties[cur].title} ${t('form.invalid')}`,
cur.msg || `${schema.properties[cur.key].title} ${t('invalid')}`,
};
return acc;
}, formData);
if (onChange instanceof Function) {
onChange(formData);
onChange({ ...formData });
}
return;
}

View File

@ -52,34 +52,32 @@ const General: FC = () => {
const uiSchema: UISchema = {
site_url: {
'ui:options': {
invalid: t('site_url.validate'),
validator: (value) => {
let url: URL | undefined;
try {
url = new URL(value);
} catch (ex) {
// eslint-disable-next-line no-empty
return t('site_url.validate');
}
// only can input url with root pathname
if (
!url ||
/^https?:$/.test(url.protocol) === false ||
url.pathname !== '/' ||
!url.search ||
!url.hash
url.search !== '' ||
url.hash !== ''
) {
return false;
return t('site_url.validate');
}
return true;
},
},
},
contact_email: {
'ui:options': {
invalid: t('contact_email.validate'),
validator: (value) => {
if (Pattern.email.test(value)) {
return false;
if (!Pattern.email.test(value)) {
return t('contact_email.validate');
}
return true;
},
@ -91,7 +89,6 @@ const General: FC = () => {
const onSubmit = (evt) => {
evt.preventDefault();
evt.stopPropagation();
const reqParams: Type.AdminSettingsGeneral = {
name: formData.name.value,
description: formData.description.value,

View File

@ -81,10 +81,9 @@ const Smtp: FC = () => {
},
smtp_port: {
'ui:options': {
invalid: t('smtp_port.msg'),
validator: (value) => {
if (!/^[1-9][0-9]*$/.test(value) || Number(value) > 65535) {
return false;
return t('smtp_port.msg');
}
return true;
},
@ -92,10 +91,9 @@ const Smtp: FC = () => {
},
test_email_recipient: {
'ui:options': {
invalid: t('test_email_recipient.msg'),
validator: (value) => {
if (value && !pattern.email.test(value)) {
return false;
return t('test_email_recipient.msg');
}
return true;
},