Merge branch 'feat/ui-0.7.0' of git.backyard.segmentfault.com:opensource/answer into feat/ui-0.7.0

This commit is contained in:
haitao(lj) 2022-12-13 16:43:33 +08:00
commit 56bb48b80b
7 changed files with 107 additions and 43 deletions

View File

@ -1094,6 +1094,8 @@ ui:
fields: fields:
password: password:
label: Password label: Password
text: The user will be logged out and need to login again.
msg: Password must be at 8 - 32 characters in length.
btn_cancel: Cancel btn_cancel: Cancel
btn_submit: Submit btn_submit: Submit
user_modal: user_modal:
@ -1102,11 +1104,14 @@ ui:
fields: fields:
display_name: display_name:
label: Display Name label: Display Name
msg: display_name must be at maximum 30 characters in length.
email: email:
label: Email label: Email
msg: Email is not valid. msg: Email is not valid.
password: password:
label: Password label: Password
msg: Password must be at 8 - 32 characters in length.
btn_cancel: Cancel btn_cancel: Cancel
btn_submit: Submit btn_submit: Submit

View File

@ -78,7 +78,7 @@ const Index: FC = () => {
) : ( ) : (
<> <>
<div className="text-muted">{t('follow_tag_tip')}</div> <div className="text-muted">{t('follow_tag_tip')}</div>
<NavLink className="d-inline-block my-2" to="/tags"> <NavLink className="d-inline-block mt-3" to="/tags">
<Button size="sm" variant="outline-primary"> <Button size="sm" variant="outline-primary">
{t('follow_a_tag')} {t('follow_a_tag')}
</Button> </Button>

View File

@ -129,7 +129,7 @@ const QuestionList: FC<Props> = ({ source }) => {
{li.status === 2 ? ` [${t('closed')}]` : ''} {li.status === 2 ? ` [${t('closed')}]` : ''}
</NavLink> </NavLink>
</h5> </h5>
<div className="d-flex flex-column flex-md-row align-items-md-center fs-14 mb-3 text-secondary"> <div className="d-flex flex-column flex-md-row align-items-md-center fs-14 mb-2 text-secondary">
<QuestionLastUpdate q={li} /> <QuestionLastUpdate q={li} />
<div className="ms-0 ms-md-3 mt-2 mt-md-0"> <div className="ms-0 ms-md-3 mt-2 mt-md-0">
<span> <span>

View File

@ -6,13 +6,14 @@ import ReactDOM from 'react-dom/client';
import type * as Type from '@/common/interface'; import type * as Type from '@/common/interface';
import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components'; import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components';
import { handleFormError } from '@/utils';
const div = document.createElement('div'); const div = document.createElement('div');
const root = ReactDOM.createRoot(div); const root = ReactDOM.createRoot(div);
interface IProps { interface IProps {
title?: string; title?: string;
onConfirm?: (formData: any) => void; onConfirm?: (formData: any) => Promise<any>;
} }
const useChangePasswordModal = (props: IProps = {}) => { const useChangePasswordModal = (props: IProps = {}) => {
const { t } = useTranslation('translation', { const { t } = useTranslation('translation', {
@ -29,6 +30,7 @@ const useChangePasswordModal = (props: IProps = {}) => {
password: { password: {
type: 'string', type: 'string',
title: t('form.fields.password.label'), title: t('form.fields.password.label'),
description: t('form.fields.password.text'),
}, },
}, },
}; };
@ -36,6 +38,14 @@ const useChangePasswordModal = (props: IProps = {}) => {
password: { password: {
'ui:options': { 'ui:options': {
type: 'password', type: 'password',
validator: (value) => {
const MIN_LENGTH = 8;
const MAX_LENGTH = 32;
if (value.length < MIN_LENGTH || value.length > MAX_LENGTH) {
return t('form.fields.password.msg');
}
return true;
},
}, },
}, },
}; };
@ -69,17 +79,25 @@ const useChangePasswordModal = (props: IProps = {}) => {
onConfirm({ onConfirm({
password: formData.password.value, password: formData.password.value,
user_id: userId, user_id: userId,
}); })
setFormData({ .then(() => {
password: { setFormData({
value: '', password: {
isInvalid: false, value: '',
errorMsg: '', isInvalid: false,
}, errorMsg: '',
}); },
setUserId(''); });
setUserId('');
onClose();
})
.catch((err) => {
if (err.isError) {
const data = handleFormError(err, formData);
setFormData({ ...data });
}
});
} }
onClose();
}; };
const handleOnChange = (data) => { const handleOnChange = (data) => {

View File

@ -7,13 +7,14 @@ import ReactDOM from 'react-dom/client';
import pattern from '@/common/pattern'; import pattern from '@/common/pattern';
import type * as Type from '@/common/interface'; import type * as Type from '@/common/interface';
import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components'; import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components';
import { handleFormError } from '@/utils';
const div = document.createElement('div'); const div = document.createElement('div');
const root = ReactDOM.createRoot(div); const root = ReactDOM.createRoot(div);
interface IProps { interface IProps {
title?: string; title?: string;
onConfirm?: (formData: any) => void; onConfirm?: (formData: any) => Promise<any>;
} }
const useAddUserModal = (props: IProps = {}) => { const useAddUserModal = (props: IProps = {}) => {
const { t } = useTranslation('translation', { const { t } = useTranslation('translation', {
@ -41,6 +42,16 @@ const useAddUserModal = (props: IProps = {}) => {
}, },
}; };
const uiSchema: UISchema = { const uiSchema: UISchema = {
display_name: {
'ui:options': {
validator: (value) => {
if (value.length > 30) {
return t('form.fields.display_name.msg');
}
return true;
},
},
},
email: { email: {
'ui:options': { 'ui:options': {
type: 'email', type: 'email',
@ -55,6 +66,14 @@ const useAddUserModal = (props: IProps = {}) => {
password: { password: {
'ui:options': { 'ui:options': {
type: 'password', type: 'password',
validator: (value) => {
const MIN_LENGTH = 8;
const MAX_LENGTH = 32;
if (value.length < MIN_LENGTH || value.length > MAX_LENGTH) {
return t('form.fields.password.msg');
}
return true;
},
}, },
}, },
}; };
@ -88,26 +107,34 @@ const useAddUserModal = (props: IProps = {}) => {
display_name: formData.display_name.value, display_name: formData.display_name.value,
email: formData.email.value, email: formData.email.value,
password: formData.password.value, password: formData.password.value,
}); })
setFormData({ .then(() => {
display_name: { setFormData({
value: '', display_name: {
isInvalid: false, value: '',
errorMsg: '', isInvalid: false,
}, errorMsg: '',
email: { },
value: '', email: {
isInvalid: false, value: '',
errorMsg: '', isInvalid: false,
}, errorMsg: '',
password: { },
value: '', password: {
isInvalid: false, value: '',
errorMsg: '', isInvalid: false,
}, errorMsg: '',
}); },
});
onClose();
})
.catch((err) => {
if (err.isError) {
const data = handleFormError(err, formData);
setFormData({ ...data });
}
});
} }
onClose();
}; };
const handleOnChange = (data) => { const handleOnChange = (data) => {

View File

@ -74,20 +74,34 @@ const Users: FC = () => {
const userModal = useUserModal({ const userModal = useUserModal({
onConfirm: (userModel) => { onConfirm: (userModel) => {
addUser(userModel).then(() => { return new Promise((resolve, reject) => {
if (/all|staff/.test(curFilter) && curPage === 1) { addUser(userModel)
refreshUsers(); .then(() => {
} if (/all|staff/.test(curFilter) && curPage === 1) {
refreshUsers();
}
resolve(true);
})
.catch((e) => {
reject(e);
});
}); });
}, },
}); });
const changePasswordModal = useChangePasswordModal({ const changePasswordModal = useChangePasswordModal({
onConfirm: (rd) => { onConfirm: (rd) => {
updateUserPassword(rd).then(() => { return new Promise((resolve, reject) => {
Toast.onShow({ updateUserPassword(rd)
msg: t('update_password', { keyPrefix: 'toast' }), .then(() => {
variant: 'success', Toast.onShow({
}); msg: t('update_password', { keyPrefix: 'toast' }),
variant: 'success',
});
resolve(true);
})
.catch((e) => {
reject(e);
});
}); });
}, },
}); });

View File

@ -108,7 +108,7 @@ const Index: FC = () => {
<Form.Control <Form.Control
autoComplete="off" autoComplete="off"
required required
type="text" type="email"
placeholder="" placeholder=""
value={formData.e_mail.value} value={formData.e_mail.value}
isInvalid={formData.e_mail.isInvalid} isInvalid={formData.e_mail.isInvalid}