mirror of https://gitee.com/answerdev/answer.git
refactor(users/settings): refactoring forms according to specifications
This commit is contained in:
parent
50133f5fe3
commit
32f7a0a89c
|
@ -640,7 +640,8 @@ ui:
|
||||||
account: Account
|
account: Account
|
||||||
interface: Interface
|
interface: Interface
|
||||||
profile:
|
profile:
|
||||||
btn_name: Update profile
|
heading: Profile
|
||||||
|
btn_name: Save
|
||||||
display_name:
|
display_name:
|
||||||
label: Display Name
|
label: Display Name
|
||||||
msg: Display name cannot be empty.
|
msg: Display name cannot be empty.
|
||||||
|
@ -658,7 +659,7 @@ ui:
|
||||||
custom: Custom
|
custom: Custom
|
||||||
btn_refresh: Refresh
|
btn_refresh: Refresh
|
||||||
custom_text: You can upload your image.
|
custom_text: You can upload your image.
|
||||||
default: Default
|
default: System
|
||||||
msg: Please upload an avatar
|
msg: Please upload an avatar
|
||||||
bio:
|
bio:
|
||||||
label: About Me (optional)
|
label: About Me (optional)
|
||||||
|
@ -670,10 +671,12 @@ ui:
|
||||||
label: Location (optional)
|
label: Location (optional)
|
||||||
placeholder: "City, Country"
|
placeholder: "City, Country"
|
||||||
notification:
|
notification:
|
||||||
|
heading: Notifications
|
||||||
email:
|
email:
|
||||||
label: Email Notifications
|
label: Email Notifications
|
||||||
radio: "Answers to your questions, comments, and more"
|
radio: "Answers to your questions, comments, and more"
|
||||||
account:
|
account:
|
||||||
|
heading: Account
|
||||||
change_email_btn: Change email
|
change_email_btn: Change email
|
||||||
change_pass_btn: Change password
|
change_pass_btn: Change password
|
||||||
change_email_info: >-
|
change_email_info: >-
|
||||||
|
@ -694,6 +697,7 @@ ui:
|
||||||
pass_confirm:
|
pass_confirm:
|
||||||
label: Confirm New Password
|
label: Confirm New Password
|
||||||
interface:
|
interface:
|
||||||
|
heading: Interface
|
||||||
lang:
|
lang:
|
||||||
label: Interface Language
|
label: Interface Language
|
||||||
text: User interface language. It will change when you refresh the page.
|
text: User interface language. It will change when you refresh the page.
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import ModifyEmail from './components/ModifyEmail';
|
import ModifyEmail from './components/ModifyEmail';
|
||||||
import ModifyPassword from './components/ModifyPass';
|
import ModifyPassword from './components/ModifyPass';
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
|
const { t } = useTranslation('translation', {
|
||||||
|
keyPrefix: 'settings.account',
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<h3 className="mb-4">{t('heading')}</h3>
|
||||||
<ModifyEmail />
|
<ModifyEmail />
|
||||||
<ModifyPassword />
|
<ModifyPassword />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import React, { useEffect, useState, FormEvent } from 'react';
|
import React, { useEffect, useState, FormEvent } from 'react';
|
||||||
import { Form, Button } from 'react-bootstrap';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { LangsType, FormDataType } from '@/common/interface';
|
import type { LangsType, FormDataType } from '@/common/interface';
|
||||||
|
@ -7,6 +6,7 @@ import { useToast } from '@/hooks';
|
||||||
import { updateUserInterface } from '@/services';
|
import { updateUserInterface } from '@/services';
|
||||||
import { localize } from '@/utils';
|
import { localize } from '@/utils';
|
||||||
import { loggedUserInfoStore } from '@/stores';
|
import { loggedUserInfoStore } from '@/stores';
|
||||||
|
import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components';
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
const { t } = useTranslation('translation', {
|
const { t } = useTranslation('translation', {
|
||||||
|
@ -15,19 +15,34 @@ const Index = () => {
|
||||||
const loggedUserInfo = loggedUserInfoStore.getState().user;
|
const loggedUserInfo = loggedUserInfoStore.getState().user;
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [langs, setLangs] = useState<LangsType[]>();
|
const [langs, setLangs] = useState<LangsType[]>();
|
||||||
const [formData, setFormData] = useState<FormDataType>({
|
const schema: JSONSchema = {
|
||||||
lang: {
|
title: t('heading'),
|
||||||
value: loggedUserInfo.language,
|
properties: {
|
||||||
isInvalid: false,
|
lang: {
|
||||||
errorMsg: '',
|
type: 'string',
|
||||||
|
title: t('lang.label'),
|
||||||
|
description: t('lang.text'),
|
||||||
|
enum: langs?.map((_) => _.value),
|
||||||
|
enumNames: langs?.map((_) => _.label),
|
||||||
|
default: loggedUserInfo.language,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
const uiSchema: UISchema = {
|
||||||
|
lang: {
|
||||||
|
'ui:widget': 'select',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const [formData, setFormData] = useState<FormDataType>(initFormData(schema));
|
||||||
|
|
||||||
const getLangs = async () => {
|
const getLangs = async () => {
|
||||||
const res: LangsType[] = await localize.loadLanguageOptions();
|
const res: LangsType[] = await localize.loadLanguageOptions();
|
||||||
setLangs(res);
|
setLangs(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOnChange = (d) => {
|
||||||
|
setFormData(d);
|
||||||
|
};
|
||||||
const handleSubmit = (event: FormEvent) => {
|
const handleSubmit = (event: FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const lang = formData.lang.value;
|
const lang = formData.lang.value;
|
||||||
|
@ -48,39 +63,16 @@ const Index = () => {
|
||||||
getLangs();
|
getLangs();
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<Form noValidate onSubmit={handleSubmit}>
|
<>
|
||||||
<Form.Group controlId="emailSend" className="mb-3">
|
<h3 className="mb-4">{t('heading')}</h3>
|
||||||
<Form.Label>{t('lang.label')}</Form.Label>
|
<SchemaForm
|
||||||
<Form.Select
|
schema={schema}
|
||||||
value={formData.lang.value}
|
uiSchema={uiSchema}
|
||||||
isInvalid={formData.lang.isInvalid}
|
formData={formData}
|
||||||
onChange={(e) => {
|
onChange={handleOnChange}
|
||||||
setFormData({
|
onSubmit={handleSubmit}
|
||||||
lang: {
|
/>
|
||||||
value: e.target.value,
|
</>
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
{langs?.map((item) => {
|
|
||||||
return (
|
|
||||||
<option value={item.value} key={item.label}>
|
|
||||||
{item.label}
|
|
||||||
</option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Form.Select>
|
|
||||||
<Form.Text as="div">{t('lang.text')}</Form.Text>
|
|
||||||
<Form.Control.Feedback type="invalid">
|
|
||||||
{formData.lang.errorMsg}
|
|
||||||
</Form.Control.Feedback>
|
|
||||||
</Form.Group>
|
|
||||||
|
|
||||||
<Button variant="primary" type="submit">
|
|
||||||
{t('save', { keyPrefix: 'btns' })}
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,33 @@
|
||||||
import React, { useState, FormEvent, useEffect } from 'react';
|
import React, { useState, FormEvent, useEffect } from 'react';
|
||||||
import { Form, Button } from 'react-bootstrap';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { FormDataType } from '@/common/interface';
|
import type { FormDataType } from '@/common/interface';
|
||||||
import { useToast } from '@/hooks';
|
import { useToast } from '@/hooks';
|
||||||
import { setNotice, getLoggedUserInfo } from '@/services';
|
import { setNotice, getLoggedUserInfo } from '@/services';
|
||||||
|
import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components';
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const { t } = useTranslation('translation', {
|
const { t } = useTranslation('translation', {
|
||||||
keyPrefix: 'settings.notification',
|
keyPrefix: 'settings.notification',
|
||||||
});
|
});
|
||||||
const [formData, setFormData] = useState<FormDataType>({
|
const schema: JSONSchema = {
|
||||||
notice_switch: {
|
title: t('heading'),
|
||||||
value: false,
|
properties: {
|
||||||
isInvalid: false,
|
notice_switch: {
|
||||||
errorMsg: '',
|
type: 'boolean',
|
||||||
|
title: t('email.label'),
|
||||||
|
label: t('email.radio'),
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
const uiSchema: UISchema = {
|
||||||
|
notice_switch: {
|
||||||
|
'ui:widget': 'switch',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const [formData, setFormData] = useState<FormDataType>(initFormData(schema));
|
||||||
|
|
||||||
const getProfile = () => {
|
const getProfile = () => {
|
||||||
getLoggedUserInfo().then((res) => {
|
getLoggedUserInfo().then((res) => {
|
||||||
|
@ -47,34 +57,20 @@ const Index = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getProfile();
|
getProfile();
|
||||||
}, []);
|
}, []);
|
||||||
|
const handleChange = (ud) => {
|
||||||
|
setFormData(ud);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Form noValidate onSubmit={handleSubmit}>
|
<>
|
||||||
<Form.Group controlId="emailSend" className="mb-3">
|
<h3 className="mb-4">{t('heading')}</h3>
|
||||||
<Form.Label>{t('email.label')}</Form.Label>
|
<SchemaForm
|
||||||
<Form.Check
|
schema={schema}
|
||||||
required
|
uiSchema={uiSchema}
|
||||||
type="checkbox"
|
formData={formData}
|
||||||
label={t('email.radio')}
|
onChange={handleChange}
|
||||||
checked={formData.notice_switch.value}
|
onSubmit={handleSubmit}
|
||||||
onChange={(e) => {
|
/>
|
||||||
setFormData({
|
</>
|
||||||
notice_switch: {
|
|
||||||
value: e.target.checked,
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Form.Control.Feedback type="invalid">
|
|
||||||
{formData.notice_switch.errorMsg}
|
|
||||||
</Form.Control.Feedback>
|
|
||||||
</Form.Group>
|
|
||||||
|
|
||||||
<Button variant="primary" type="submit">
|
|
||||||
{t('save', { keyPrefix: 'btns' })}
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React, { FormEvent, useState, useEffect } from 'react';
|
import React, { FormEvent, useState, useEffect } from 'react';
|
||||||
import { Form, Button } from 'react-bootstrap';
|
import { Form, Button, Stack, ButtonGroup } from 'react-bootstrap';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
import MD5 from 'md5';
|
import MD5 from 'md5';
|
||||||
|
|
||||||
import type { FormDataType } from '@/common/interface';
|
import type { FormDataType } from '@/common/interface';
|
||||||
import { UploadImg, Avatar } from '@/components';
|
import { UploadImg, Avatar, Icon } from '@/components';
|
||||||
import { loggedUserInfoStore } from '@/stores';
|
import { loggedUserInfoStore } from '@/stores';
|
||||||
import { useToast } from '@/hooks';
|
import { useToast } from '@/hooks';
|
||||||
import { modifyUserInfo, getLoggedUserInfo } from '@/services';
|
import { modifyUserInfo, getLoggedUserInfo } from '@/services';
|
||||||
|
@ -19,7 +19,7 @@ const Index: React.FC = () => {
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const { user, update } = loggedUserInfoStore();
|
const { user, update } = loggedUserInfoStore();
|
||||||
const [mailHash, setMailHash] = useState('');
|
const [mailHash, setMailHash] = useState('');
|
||||||
const [count, setCount] = useState(0);
|
const [count] = useState(0);
|
||||||
|
|
||||||
const [formData, setFormData] = useState<FormDataType>({
|
const [formData, setFormData] = useState<FormDataType>({
|
||||||
display_name: {
|
display_name: {
|
||||||
|
@ -60,6 +60,40 @@ const Index: React.FC = () => {
|
||||||
const handleChange = (params: FormDataType) => {
|
const handleChange = (params: FormDataType) => {
|
||||||
setFormData({ ...formData, ...params });
|
setFormData({ ...formData, ...params });
|
||||||
};
|
};
|
||||||
|
const handleAvatarChange = (evt) => {
|
||||||
|
const { value: v } = evt.currentTarget;
|
||||||
|
if (v === 'gravatar') {
|
||||||
|
handleChange({
|
||||||
|
avatar: {
|
||||||
|
...formData.avatar,
|
||||||
|
type: 'gravatar',
|
||||||
|
gravatar: `https://www.gravatar.com/avatar/${mailHash}`,
|
||||||
|
isInvalid: false,
|
||||||
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (v === 'custom') {
|
||||||
|
handleChange({
|
||||||
|
avatar: {
|
||||||
|
...formData.avatar,
|
||||||
|
type: 'custom',
|
||||||
|
isInvalid: false,
|
||||||
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (v === 'default') {
|
||||||
|
handleChange({
|
||||||
|
avatar: {
|
||||||
|
...formData.avatar,
|
||||||
|
type: 'default',
|
||||||
|
isInvalid: false,
|
||||||
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const avatarUpload = (path: string) => {
|
const avatarUpload = (path: string) => {
|
||||||
setFormData({
|
setFormData({
|
||||||
|
@ -73,6 +107,17 @@ const Index: React.FC = () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const removeCustomAvatar = () => {
|
||||||
|
setFormData({
|
||||||
|
...formData,
|
||||||
|
avatar: {
|
||||||
|
...formData.avatar,
|
||||||
|
custom: '',
|
||||||
|
isInvalid: false,
|
||||||
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const checkValidated = (): boolean => {
|
const checkValidated = (): boolean => {
|
||||||
let bol = true;
|
let bol = true;
|
||||||
|
@ -201,265 +246,220 @@ const Index: React.FC = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshGravatar = () => {
|
// const refreshGravatar = () => {
|
||||||
setCount((pre) => pre + 1);
|
// setCount((pre) => pre + 1);
|
||||||
};
|
// };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getProfile();
|
getProfile();
|
||||||
}, []);
|
}, []);
|
||||||
return (
|
return (
|
||||||
<Form noValidate onSubmit={handleSubmit}>
|
<>
|
||||||
<Form.Group controlId="displayName" className="mb-3">
|
<h3 className="mb-4">{t('heading')}</h3>
|
||||||
<Form.Label>{t('display_name.label')}</Form.Label>
|
<Form noValidate onSubmit={handleSubmit}>
|
||||||
<Form.Control
|
<Form.Group controlId="displayName" className="mb-3">
|
||||||
required
|
<Form.Label>{t('display_name.label')}</Form.Label>
|
||||||
type="text"
|
<Form.Control
|
||||||
value={formData.display_name.value}
|
required
|
||||||
isInvalid={formData.display_name.isInvalid}
|
type="text"
|
||||||
onChange={(e) =>
|
value={formData.display_name.value}
|
||||||
handleChange({
|
isInvalid={formData.display_name.isInvalid}
|
||||||
display_name: {
|
onChange={(e) =>
|
||||||
value: e.target.value,
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Form.Control.Feedback type="invalid">
|
|
||||||
{formData.display_name.errorMsg}
|
|
||||||
</Form.Control.Feedback>
|
|
||||||
</Form.Group>
|
|
||||||
|
|
||||||
<Form.Group controlId="userName" className="mb-3">
|
|
||||||
<Form.Label>{t('username.label')}</Form.Label>
|
|
||||||
<Form.Control
|
|
||||||
required
|
|
||||||
type="text"
|
|
||||||
value={formData.username.value}
|
|
||||||
isInvalid={formData.username.isInvalid}
|
|
||||||
onChange={(e) =>
|
|
||||||
handleChange({
|
|
||||||
username: {
|
|
||||||
value: e.target.value,
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Form.Text as="div">{t('username.caption')}</Form.Text>
|
|
||||||
<Form.Control.Feedback type="invalid">
|
|
||||||
{formData.username.errorMsg}
|
|
||||||
</Form.Control.Feedback>
|
|
||||||
</Form.Group>
|
|
||||||
|
|
||||||
<Form.Group className="mb-3">
|
|
||||||
<Form.Label>{t('avatar.label')}</Form.Label>
|
|
||||||
<div className="mb-2">
|
|
||||||
<Form.Check
|
|
||||||
inline
|
|
||||||
type="radio"
|
|
||||||
id="gravatar"
|
|
||||||
label={t('avatar.gravatar')}
|
|
||||||
className="mb-0"
|
|
||||||
checked={formData.avatar.type === 'gravatar'}
|
|
||||||
onChange={() =>
|
|
||||||
handleChange({
|
handleChange({
|
||||||
avatar: {
|
display_name: {
|
||||||
...formData.avatar,
|
value: e.target.value,
|
||||||
type: 'gravatar',
|
|
||||||
gravatar: `https://www.gravatar.com/avatar/${mailHash}`,
|
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Form.Check
|
<Form.Control.Feedback type="invalid">
|
||||||
inline
|
{formData.display_name.errorMsg}
|
||||||
type="radio"
|
</Form.Control.Feedback>
|
||||||
label={t('avatar.custom')}
|
</Form.Group>
|
||||||
id="custom"
|
|
||||||
className="mb-0"
|
|
||||||
checked={formData.avatar.type === 'custom'}
|
|
||||||
onChange={() =>
|
|
||||||
handleChange({
|
|
||||||
avatar: {
|
|
||||||
...formData.avatar,
|
|
||||||
type: 'custom',
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Form.Check
|
|
||||||
inline
|
|
||||||
type="radio"
|
|
||||||
id="default"
|
|
||||||
label={t('avatar.default')}
|
|
||||||
className="mb-0"
|
|
||||||
checked={formData.avatar.type === 'default'}
|
|
||||||
onChange={() =>
|
|
||||||
handleChange({
|
|
||||||
avatar: {
|
|
||||||
...formData.avatar,
|
|
||||||
type: 'default',
|
|
||||||
isInvalid: false,
|
|
||||||
errorMsg: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex align-items-center">
|
|
||||||
{formData.avatar.type === 'gravatar' && (
|
|
||||||
<>
|
|
||||||
<Avatar
|
|
||||||
size="128px"
|
|
||||||
avatar={formData.avatar.gravatar}
|
|
||||||
searchStr={`s=256&d=identicon${
|
|
||||||
count > 0 ? `&t=${new Date().valueOf()}` : ''
|
|
||||||
}`}
|
|
||||||
className="me-3 rounded"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
variant="outline-secondary"
|
|
||||||
className="mb-2"
|
|
||||||
onClick={refreshGravatar}>
|
|
||||||
{t('avatar.btn_refresh')}
|
|
||||||
</Button>
|
|
||||||
<div>
|
|
||||||
<Form.Text className="text-muted mt-0">
|
|
||||||
<Trans i18nKey="settings.profile.gravatar_text">
|
|
||||||
You can change your image on{' '}
|
|
||||||
<a
|
|
||||||
href="https://gravatar.com"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer">
|
|
||||||
gravatar.com
|
|
||||||
</a>
|
|
||||||
</Trans>
|
|
||||||
</Form.Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{formData.avatar.type === 'custom' && (
|
<Form.Group controlId="userName" className="mb-3">
|
||||||
<>
|
<Form.Label>{t('username.label')}</Form.Label>
|
||||||
<Avatar
|
<Form.Control
|
||||||
size="128px"
|
required
|
||||||
searchStr="s=256"
|
type="text"
|
||||||
avatar={formData.avatar.custom}
|
value={formData.username.value}
|
||||||
className="me-3 rounded"
|
isInvalid={formData.username.isInvalid}
|
||||||
/>
|
onChange={(e) =>
|
||||||
<div>
|
handleChange({
|
||||||
<UploadImg
|
username: {
|
||||||
type="avatar"
|
value: e.target.value,
|
||||||
uploadCallback={avatarUpload}
|
isInvalid: false,
|
||||||
className="mb-2"
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Form.Text as="div">{t('username.caption')}</Form.Text>
|
||||||
|
<Form.Control.Feedback type="invalid">
|
||||||
|
{formData.username.errorMsg}
|
||||||
|
</Form.Control.Feedback>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>{t('avatar.label')}</Form.Label>
|
||||||
|
<div className="mb-3">
|
||||||
|
<Form.Select
|
||||||
|
name="avatar.type"
|
||||||
|
value={formData.avatar.type}
|
||||||
|
onChange={handleAvatarChange}>
|
||||||
|
<option value="gravatar" key="gravatar">
|
||||||
|
{t('avatar.gravatar')}
|
||||||
|
</option>
|
||||||
|
<option value="default" key="default">
|
||||||
|
{t('avatar.default')}
|
||||||
|
</option>
|
||||||
|
<option value="custom" key="custom">
|
||||||
|
{t('avatar.custom')}
|
||||||
|
</option>
|
||||||
|
</Form.Select>
|
||||||
|
</div>
|
||||||
|
<div className="d-flex">
|
||||||
|
{formData.avatar.type === 'gravatar' && (
|
||||||
|
<Stack>
|
||||||
|
<Avatar
|
||||||
|
size="160px"
|
||||||
|
avatar={formData.avatar.gravatar}
|
||||||
|
searchStr={`s=256&d=identicon${
|
||||||
|
count > 0 ? `&t=${new Date().valueOf()}` : ''
|
||||||
|
}`}
|
||||||
|
className="me-3 rounded"
|
||||||
/>
|
/>
|
||||||
<div>
|
<Form.Text className="text-muted mt-1">
|
||||||
<Form.Text className="text-muted mt-0">
|
<Trans i18nKey="settings.profile.avatar.gravatar_text">
|
||||||
<Trans i18nKey="settings.profile.avatar.text">
|
You can change image on
|
||||||
You can upload your image.
|
<a
|
||||||
</Trans>
|
href="https://gravatar.com"
|
||||||
</Form.Text>
|
target="_blank"
|
||||||
</div>
|
rel="noreferrer">
|
||||||
</div>
|
gravatar.com
|
||||||
</>
|
</a>
|
||||||
)}
|
</Trans>
|
||||||
{formData.avatar.type === 'default' && (
|
</Form.Text>
|
||||||
<Avatar size="128px" avatar="" className="me-3 rounded" />
|
</Stack>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
<Form.Control
|
|
||||||
isInvalid={formData.avatar.isInvalid}
|
|
||||||
className="d-none"
|
|
||||||
/>
|
|
||||||
<Form.Control.Feedback type="invalid">
|
|
||||||
{formData.avatar.errorMsg}
|
|
||||||
</Form.Control.Feedback>
|
|
||||||
</Form.Group>
|
|
||||||
|
|
||||||
<Form.Group controlId="bio" className="mb-3">
|
{formData.avatar.type === 'custom' && (
|
||||||
<Form.Label>{t('bio.label')}</Form.Label>
|
<Stack>
|
||||||
<Form.Control
|
<Stack direction="horizontal" className="align-items-start">
|
||||||
className="font-monospace"
|
<Avatar
|
||||||
required
|
size="160px"
|
||||||
as="textarea"
|
searchStr="s=256"
|
||||||
rows={5}
|
avatar={formData.avatar.custom}
|
||||||
value={formData.bio.value}
|
className="me-2 bg-gray-300 "
|
||||||
isInvalid={formData.bio.isInvalid}
|
/>
|
||||||
onChange={(e) =>
|
<ButtonGroup vertical className="fit-content">
|
||||||
handleChange({
|
<UploadImg type="avatar" uploadCallback={avatarUpload}>
|
||||||
bio: {
|
<Icon name="cloud-upload" />
|
||||||
value: e.target.value,
|
</UploadImg>
|
||||||
isInvalid: false,
|
<Button
|
||||||
errorMsg: '',
|
variant="outline-secondary"
|
||||||
},
|
onClick={removeCustomAvatar}>
|
||||||
})
|
<Icon name="trash" />
|
||||||
}
|
</Button>
|
||||||
/>
|
</ButtonGroup>
|
||||||
<Form.Control.Feedback type="invalid">
|
</Stack>
|
||||||
{formData.bio.errorMsg}
|
<Form.Text className="text-muted mt-1">
|
||||||
</Form.Control.Feedback>
|
<Trans i18nKey="settings.profile.avatar.text">
|
||||||
</Form.Group>
|
You can upload your image.
|
||||||
|
</Trans>
|
||||||
|
</Form.Text>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
{formData.avatar.type === 'default' && (
|
||||||
|
<Avatar size="160px" avatar="" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Form.Control
|
||||||
|
isInvalid={formData.avatar.isInvalid}
|
||||||
|
className="d-none"
|
||||||
|
/>
|
||||||
|
<Form.Control.Feedback type="invalid">
|
||||||
|
{formData.avatar.errorMsg}
|
||||||
|
</Form.Control.Feedback>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
<Form.Group controlId="website" className="mb-3">
|
<Form.Group controlId="bio" className="mb-3">
|
||||||
<Form.Label>{t('website.label')}</Form.Label>
|
<Form.Label>{t('bio.label')}</Form.Label>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
required
|
className="font-monospace"
|
||||||
type="text"
|
required
|
||||||
placeholder={t('website.placeholder')}
|
as="textarea"
|
||||||
value={formData.website.value}
|
rows={5}
|
||||||
isInvalid={formData.website.isInvalid}
|
value={formData.bio.value}
|
||||||
onChange={(e) =>
|
isInvalid={formData.bio.isInvalid}
|
||||||
handleChange({
|
onChange={(e) =>
|
||||||
website: {
|
handleChange({
|
||||||
value: e.target.value,
|
bio: {
|
||||||
isInvalid: false,
|
value: e.target.value,
|
||||||
errorMsg: '',
|
isInvalid: false,
|
||||||
},
|
errorMsg: '',
|
||||||
})
|
},
|
||||||
}
|
})
|
||||||
/>
|
}
|
||||||
<Form.Control.Feedback type="invalid">
|
/>
|
||||||
{formData.website.errorMsg}
|
<Form.Control.Feedback type="invalid">
|
||||||
</Form.Control.Feedback>
|
{formData.bio.errorMsg}
|
||||||
</Form.Group>
|
</Form.Control.Feedback>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
<Form.Group controlId="email" className="mb-3">
|
<Form.Group controlId="website" className="mb-3">
|
||||||
<Form.Label>{t('location.label')}</Form.Label>
|
<Form.Label>{t('website.label')}</Form.Label>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
required
|
required
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={t('location.placeholder')}
|
placeholder={t('website.placeholder')}
|
||||||
value={formData.location.value}
|
value={formData.website.value}
|
||||||
isInvalid={formData.location.isInvalid}
|
isInvalid={formData.website.isInvalid}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleChange({
|
handleChange({
|
||||||
location: {
|
website: {
|
||||||
value: e.target.value,
|
value: e.target.value,
|
||||||
isInvalid: false,
|
isInvalid: false,
|
||||||
errorMsg: '',
|
errorMsg: '',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Form.Control.Feedback type="invalid">
|
<Form.Control.Feedback type="invalid">
|
||||||
{formData.location.errorMsg}
|
{formData.website.errorMsg}
|
||||||
</Form.Control.Feedback>
|
</Form.Control.Feedback>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<Button variant="primary" type="submit">
|
<Form.Group controlId="email" className="mb-3">
|
||||||
{t('btn_name')}
|
<Form.Label>{t('location.label')}</Form.Label>
|
||||||
</Button>
|
<Form.Control
|
||||||
</Form>
|
required
|
||||||
|
type="text"
|
||||||
|
placeholder={t('location.placeholder')}
|
||||||
|
value={formData.location.value}
|
||||||
|
isInvalid={formData.location.isInvalid}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleChange({
|
||||||
|
location: {
|
||||||
|
value: e.target.value,
|
||||||
|
isInvalid: false,
|
||||||
|
errorMsg: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Form.Control.Feedback type="invalid">
|
||||||
|
{formData.location.errorMsg}
|
||||||
|
</Form.Control.Feedback>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
|
<Button variant="primary" type="submit">
|
||||||
|
{t('btn_name')}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue