refactor(ui): use schemaForm

This commit is contained in:
robin 2022-11-10 11:15:34 +08:00
parent 26f606e285
commit c9c13a1331
2 changed files with 166 additions and 410 deletions

View File

@ -1,7 +1,7 @@
import React, { FC, useEffect, useState } from 'react';
import { Form, Button } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import { SchemaForm, JSONSchema, initFormData, UISchema } from '@/components';
import type * as Type from '@/common/interface';
import { useToast } from '@/hooks';
import { siteInfoStore } from '@/stores';
@ -17,91 +17,70 @@ const General: FC = () => {
const updateSiteInfo = siteInfoStore((state) => state.update);
const { data: setting } = useGeneralSetting();
const [formData, setFormData] = useState<Type.FormDataType>({
name: {
value: '',
isInvalid: false,
errorMsg: '',
const schema: JSONSchema = {
title: t('title'),
description: t('description'),
required: ['name', 'site_url', 'contact_email'],
properties: {
name: {
type: 'string',
title: t('name.label'),
description: t('name.text'),
},
site_url: {
type: 'string',
title: t('site_url.label'),
description: t('site_url.text'),
},
short_description: {
type: 'string',
title: t('short_description.label'),
description: t('short_description.text'),
},
description: {
type: 'string',
title: t('description.label'),
description: t('description.text'),
},
contact_email: {
type: 'string',
title: t('contact_email.label'),
description: t('contact_email.text'),
},
},
};
const uiSchema: UISchema = {
site_url: {
value: '',
isInvalid: false,
errorMsg: '',
},
short_description: {
value: '',
isInvalid: false,
errorMsg: '',
},
description: {
value: '',
isInvalid: false,
errorMsg: '',
'ui:options': {
invalid: t('site_url.validate'),
validator: (value) => {
if (!/^(https?):\/\/([\w.]+\/?)\S*$/.test(value)) {
return false;
}
return true;
},
},
},
contact_email: {
value: '',
isInvalid: false,
errorMsg: '',
'ui:options': {
invalid: t('contact_email.validate'),
validator: (value) => {
if (
!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value)
) {
return false;
}
return true;
},
},
},
});
const checkValidated = (): boolean => {
let ret = true;
const { name, site_url, contact_email } = formData;
if (!name.value) {
ret = false;
formData.name = {
value: '',
isInvalid: true,
errorMsg: t('name.msg'),
};
}
if (!site_url.value) {
ret = false;
formData.site_url = {
value: '',
isInvalid: true,
errorMsg: t('site_url.msg'),
};
} else if (!/^(https?):\/\/([\w.]+\/?)\S*$/.test(site_url.value)) {
ret = false;
formData.site_url = {
value: formData.site_url.value,
isInvalid: true,
errorMsg: t('site_url.validate'),
};
}
if (!contact_email.value) {
ret = false;
formData.contact_email = {
value: '',
isInvalid: true,
errorMsg: t('contact_email.msg'),
};
} else if (
!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(
contact_email.value,
)
) {
ret = false;
formData.contact_email = {
value: formData.contact_email.value,
isInvalid: true,
errorMsg: t('contact_email.validate'),
};
}
setFormData({
...formData,
});
return ret;
};
const [formData, setFormData] = useState(initFormData(schema));
const onSubmit = (evt) => {
evt.preventDefault();
evt.stopPropagation();
if (checkValidated() === false) {
return;
}
const reqParams: Type.AdminSettingsGeneral = {
name: formData.name.value,
description: formData.description.value,
@ -126,19 +105,7 @@ const General: FC = () => {
setFormData({ ...formData });
});
};
const onFieldChange = (fieldName, fieldValue) => {
if (!formData[fieldName]) {
return;
}
const fieldData: Type.FormDataType = {
[fieldName]: {
value: fieldValue,
isInvalid: false,
errorMsg: '',
},
};
setFormData({ ...formData, ...fieldData });
};
useEffect(() => {
if (!setting) {
return;
@ -149,87 +116,21 @@ const General: FC = () => {
});
setFormData({ ...formData, ...formMeta });
}, [setting]);
const handleOnChange = (data) => {
setFormData(data);
};
return (
<>
<h3 className="mb-4">{t('page_title')}</h3>
<Form noValidate onSubmit={onSubmit}>
<Form.Group controlId="siteName" className="mb-3">
<Form.Label>{t('name.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.name.value}
isInvalid={formData.name.isInvalid}
onChange={(evt) => onFieldChange('name', evt.target.value)}
/>
<Form.Text as="div">{t('name.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.name.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="siteUrl" className="mb-3">
<Form.Label>{t('site_url.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.site_url.value}
isInvalid={formData.site_url.isInvalid}
onChange={(evt) => onFieldChange('site_url', evt.target.value)}
/>
<Form.Text as="div">{t('site_url.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.site_url.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="shortDescription" className="mb-3">
<Form.Label>{t('short_description.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.short_description.value}
isInvalid={formData.short_description.isInvalid}
onChange={(evt) =>
onFieldChange('short_description', evt.target.value)
}
/>
<Form.Text as="div">{t('short_description.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.short_description.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="description" className="mb-3">
<Form.Label>{t('description.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.description.value}
isInvalid={formData.description.isInvalid}
onChange={(evt) => onFieldChange('description', evt.target.value)}
/>
<Form.Text as="div">{t('description.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.description.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="contact_email" className="mb-3">
<Form.Label>{t('contact_email.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.contact_email.value}
isInvalid={formData.contact_email.isInvalid}
onChange={(evt) => onFieldChange('contact_email', evt.target.value)}
/>
<Form.Text as="div">{t('contact_email.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.contact_email.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Button variant="primary" type="submit">
{t('save', { keyPrefix: 'btns' })}
</Button>
</Form>
<SchemaForm
schema={schema}
formData={formData}
onSubmit={onSubmit}
uiSchema={uiSchema}
onChange={handleOnChange}
/>
</>
);
};

View File

@ -1,11 +1,12 @@
import React, { FC, useEffect, useState } from 'react';
import { Form, Button, Stack } from 'react-bootstrap';
import { useTranslation } from 'react-i18next';
import type * as Type from '@/common/interface';
import { useToast } from '@/hooks';
import { useSmtpSetting, updateSmtpSetting } from '@/services';
import pattern from '@/common/pattern';
import { SchemaForm, JSONSchema, UISchema } from '@/components';
import { initFormData } from '../../../components/SchemaForm/index';
const Smtp: FC = () => {
const { t } = useTranslation('translation', {
@ -13,90 +14,103 @@ const Smtp: FC = () => {
});
const Toast = useToast();
const { data: setting } = useSmtpSetting();
const [formData, setFormData] = useState<Type.FormDataType>({
from_email: {
value: '',
isInvalid: false,
errorMsg: '',
},
from_name: {
value: '',
isInvalid: false,
errorMsg: '',
},
smtp_host: {
value: '',
isInvalid: false,
errorMsg: '',
const schema: JSONSchema = {
title: t('title'),
description: t('description'),
properties: {
from_email: {
type: 'string',
title: t('from_email.label'),
description: t('from_email.text'),
},
from_name: {
type: 'string',
title: t('from_name.label'),
description: t('from_name.text'),
},
smtp_host: {
type: 'string',
title: t('smtp_host.label'),
description: t('smtp_host.text'),
},
encryption: {
type: 'boolean',
title: t('encryption.label'),
description: t('encryption.text'),
enum: [true, false],
enumNames: ['SSL', ''],
},
smtp_port: {
type: 'string',
title: t('smtp_port.label'),
description: t('smtp_port.text'),
},
smtp_authentication: {
type: 'boolean',
title: t('smtp_authentication.label'),
enum: [true, false],
enumNames: [t('smtp_authentication.yes'), t('smtp_authentication.no')],
},
smtp_username: {
type: 'string',
title: t('smtp_username.label'),
description: t('smtp_username.text'),
},
smtp_password: {
type: 'string',
title: t('smtp_password.label'),
description: t('smtp_password.text'),
},
test_email_recipient: {
type: 'string',
title: t('test_email_recipient.label'),
description: t('test_email_recipient.text'),
},
},
};
const uiSchema: UISchema = {
encryption: {
value: '',
isInvalid: false,
errorMsg: '',
},
smtp_port: {
value: '',
isInvalid: false,
errorMsg: '',
},
smtp_authentication: {
value: 'yes',
isInvalid: false,
errorMsg: '',
},
smtp_username: {
value: '',
isInvalid: false,
errorMsg: '',
'ui:widget': 'radio',
},
smtp_password: {
value: '',
isInvalid: false,
errorMsg: '',
'ui:options': {
type: 'password',
},
},
smtp_authentication: {
'ui:widget': 'radio',
},
smtp_port: {
'ui:options': {
invalid: t('smtp_port.msg'),
validator: (value) => {
if (!/^[1-9][0-9]*$/.test(value) || Number(value) > 65535) {
return false;
}
return true;
},
},
},
test_email_recipient: {
value: '',
isInvalid: false,
errorMsg: '',
'ui:options': {
invalid: t('test_email_recipient.msg'),
validator: (value) => {
if (value && !pattern.email.test(value)) {
return false;
}
return true;
},
},
},
});
const checkValidated = (): boolean => {
let ret = true;
const { smtp_port, test_email_recipient } = formData;
if (
!/^[1-9][0-9]*$/.test(smtp_port.value) ||
Number(smtp_port.value) > 65535
) {
ret = false;
formData.smtp_port = {
value: smtp_port.value,
isInvalid: true,
errorMsg: t('smtp_port.msg'),
};
}
if (
test_email_recipient.value &&
!pattern.email.test(test_email_recipient.value)
) {
ret = false;
formData.test_email_recipient = {
value: test_email_recipient.value,
isInvalid: true,
errorMsg: t('test_email_recipient.msg'),
};
}
setFormData({
...formData,
});
return ret;
};
const [formData, setFormData] = useState<Type.FormDataType>(
initFormData(schema),
);
const onSubmit = (evt) => {
evt.preventDefault();
evt.stopPropagation();
if (!checkValidated()) {
return;
}
const reqParams: Type.AdminSettingsSmtp = {
from_email: formData.from_email.value,
from_name: formData.from_name.value,
@ -124,19 +138,7 @@ const Smtp: FC = () => {
setFormData({ ...formData });
});
};
const onFieldChange = (fieldName, fieldValue) => {
if (!formData[fieldName]) {
return;
}
const fieldData: Type.FormDataType = {
[fieldName]: {
value: fieldValue,
isInvalid: false,
errorMsg: '',
},
};
setFormData({ ...formData, ...fieldData });
};
useEffect(() => {
if (!setting) {
return;
@ -152,166 +154,19 @@ const Smtp: FC = () => {
setFormData(formState);
}, [setting]);
const handleOnChange = (data) => {
setFormData(data);
};
return (
<>
<h3 className="mb-4">{t('page_title')}</h3>
<Form noValidate onSubmit={onSubmit}>
<Form.Group controlId="fromEmail" className="mb-3">
<Form.Label>{t('from_email.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.from_email.value}
isInvalid={formData.from_email.isInvalid}
onChange={(evt) => onFieldChange('from_email', evt.target.value)}
/>
<Form.Text as="div">{t('from_email.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.from_email.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="fromName" className="mb-3">
<Form.Label>{t('from_name.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.from_name.value}
isInvalid={formData.from_name.isInvalid}
onChange={(evt) => onFieldChange('from_name', evt.target.value)}
/>
<Form.Text as="div">{t('from_name.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.from_name.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="smtpHost" className="mb-3">
<Form.Label>{t('smtp_host.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.smtp_host.value}
isInvalid={formData.smtp_host.isInvalid}
onChange={(evt) => onFieldChange('smtp_host', evt.target.value)}
/>
<Form.Text as="div">{t('smtp_host.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.smtp_host.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="encryption" className="mb-3">
<Form.Label>{t('encryption.label')}</Form.Label>
<Stack direction="horizontal">
<Form.Check
inline
label={t('encryption.ssl')}
name="smtp_encryption"
id="smtp_encryption_ssl"
checked={formData.encryption.value === 'SSL'}
onChange={() => onFieldChange('encryption', 'SSL')}
type="radio"
/>
<Form.Check
inline
label={t('encryption.none')}
name="smtp_encryption"
id="smtp_encryption_none"
checked={!formData.encryption.value}
onChange={() => onFieldChange('encryption', '')}
type="radio"
/>
</Stack>
<Form.Text as="div">{t('encryption.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.encryption.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="smtpPort" className="mb-3">
<Form.Label>{t('smtp_port.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.smtp_port.value}
isInvalid={formData.smtp_port.isInvalid}
onChange={(evt) => onFieldChange('smtp_port', evt.target.value)}
/>
<Form.Text as="div">{t('smtp_port.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.smtp_port.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="smtpAuthentication" className="mb-3">
<Form.Label>{t('smtp_authentication.label')}</Form.Label>
<Stack direction="horizontal">
<Form.Check
inline
label={t('smtp_authentication.yes')}
name="smtp_authentication"
id="smtp_authentication_yes"
checked={!!formData.smtp_authentication.value}
onChange={() => onFieldChange('smtp_authentication', true)}
type="radio"
/>
<Form.Check
inline
label={t('smtp_authentication.no')}
name="smtp_authentication"
id="smtp_authentication_no"
checked={!formData.smtp_authentication.value}
onChange={() => onFieldChange('smtp_authentication', false)}
type="radio"
/>
</Stack>
<Form.Control.Feedback type="invalid">
{formData.smtp_authentication.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="smtpUsername" className="mb-3">
<Form.Label>{t('smtp_username.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.smtp_username.value}
isInvalid={formData.smtp_username.isInvalid}
onChange={(evt) => onFieldChange('smtp_username', evt.target.value)}
/>
<Form.Control.Feedback type="invalid">
{formData.smtp_username.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="smtpPassword" className="mb-3">
<Form.Label>{t('smtp_password.label')}</Form.Label>
<Form.Control
required
type="password"
value={formData.smtp_password.value}
isInvalid={formData.smtp_password.isInvalid}
onChange={(evt) => onFieldChange('smtp_password', evt.target.value)}
/>
<Form.Control.Feedback type="invalid">
{formData.smtp_password.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="testEmailRecipient" className="mb-3">
<Form.Label>{t('test_email_recipient.label')}</Form.Label>
<Form.Control
required
type="text"
value={formData.test_email_recipient.value}
isInvalid={formData.test_email_recipient.isInvalid}
onChange={(evt) =>
onFieldChange('test_email_recipient', evt.target.value)
}
/>
<Form.Text as="div">{t('test_email_recipient.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.test_email_recipient.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Button variant="primary" type="submit">
{t('save', { keyPrefix: 'btns' })}
</Button>
</Form>
<SchemaForm
schema={schema}
uiSchema={uiSchema}
formData={formData}
onChange={handleOnChange}
onSubmit={onSubmit}
/>
</>
);
};