mirror of https://gitee.com/answerdev/answer.git
refactor(ui): Optimizing schema forms
This commit is contained in:
parent
ba66cccb8b
commit
bc904d8d59
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue