feat: add user profile settings tab
This commit is contained in:
@ -557,6 +557,7 @@ const Admin: React.FC<AdminProps> = ({
|
||||
<TabNavContent>
|
||||
{items.map((item, idx) => (
|
||||
<NavItem
|
||||
key={item.name}
|
||||
onClick={(tab, top) => {
|
||||
if ($tabNav && $tabNav.current) {
|
||||
const pos = $tabNav.current.getBoundingClientRect();
|
||||
|
@ -78,6 +78,7 @@ const Icon = styled.div`
|
||||
|
||||
type InputProps = {
|
||||
variant?: 'normal' | 'alternate';
|
||||
disabled?: boolean;
|
||||
label?: string;
|
||||
width?: string;
|
||||
floatingLabel?: boolean;
|
||||
@ -116,6 +117,7 @@ function useCombinedRefs(...refs: any) {
|
||||
const Input = React.forwardRef(
|
||||
(
|
||||
{
|
||||
disabled = false,
|
||||
width = 'auto',
|
||||
variant = 'normal',
|
||||
type = 'text',
|
||||
@ -160,6 +162,7 @@ const Input = React.forwardRef(
|
||||
onChange={e => {
|
||||
setHasValue((e.currentTarget.value !== '' || floatingLabel) ?? false);
|
||||
}}
|
||||
disabled={disabled}
|
||||
hasValue={hasValue}
|
||||
ref={combinedRef}
|
||||
id={id}
|
||||
|
@ -27,6 +27,7 @@ export const Default = () => {
|
||||
<BaseStyles />
|
||||
<Settings
|
||||
profile={profile}
|
||||
onChangeUserInfo={action('change user info')}
|
||||
onResetPassword={action('reset password')}
|
||||
onProfileAvatarRemove={action('remove')}
|
||||
onProfileAvatarChange={action('profile avatar change')}
|
||||
|
@ -10,6 +10,11 @@ const PasswordInput = styled(Input)`
|
||||
margin-bottom: 0;
|
||||
`;
|
||||
|
||||
const UserInfoInput = styled(Input)`
|
||||
margin-top: 30px;
|
||||
margin-bottom: 0;
|
||||
`;
|
||||
|
||||
const FormError = styled.span`
|
||||
font-size: 12px;
|
||||
color: rgba(${props => props.theme.colors.warning});
|
||||
@ -240,6 +245,7 @@ const SaveButton = styled(Button)`
|
||||
type SettingsProps = {
|
||||
onProfileAvatarChange: () => void;
|
||||
onProfileAvatarRemove: () => void;
|
||||
onChangeUserInfo: (data: UserInfoData, done: () => void) => void;
|
||||
onResetPassword: (password: string, done: () => void) => void;
|
||||
profile: TaskUser;
|
||||
};
|
||||
@ -300,9 +306,93 @@ const ResetPasswordTab: React.FC<ResetPasswordTabProps> = ({ onResetPassword })
|
||||
);
|
||||
};
|
||||
|
||||
type UserInfoData = {
|
||||
full_name: string;
|
||||
bio: string;
|
||||
initials: string;
|
||||
email: string;
|
||||
};
|
||||
type UserInfoTabProps = {
|
||||
profile: TaskUser;
|
||||
onProfileAvatarChange: () => void;
|
||||
onProfileAvatarRemove: () => void;
|
||||
onChangeUserInfo: (data: UserInfoData, done: () => void) => void;
|
||||
};
|
||||
|
||||
const EMAIL_PATTERN = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i;
|
||||
const INITIALS_PATTERN = /^[a-zA-Z]{2,3}$/i;
|
||||
|
||||
const UserInfoTab: React.FC<UserInfoTabProps> = ({
|
||||
profile,
|
||||
onProfileAvatarRemove,
|
||||
onProfileAvatarChange,
|
||||
onChangeUserInfo,
|
||||
}) => {
|
||||
const [active, setActive] = useState(true);
|
||||
const { register, handleSubmit, errors } = useForm<UserInfoData>();
|
||||
const done = () => {
|
||||
setActive(true);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<AvatarSettings
|
||||
onProfileAvatarRemove={onProfileAvatarRemove}
|
||||
onProfileAvatarChange={onProfileAvatarChange}
|
||||
profile={profile.profileIcon}
|
||||
/>
|
||||
<form
|
||||
onSubmit={handleSubmit(data => {
|
||||
setActive(false);
|
||||
onChangeUserInfo(data, done);
|
||||
})}
|
||||
>
|
||||
<UserInfoInput
|
||||
ref={register({ required: 'Full name is required' })}
|
||||
name="full_name"
|
||||
defaultValue={profile.fullName}
|
||||
width="100%"
|
||||
label="Name"
|
||||
/>
|
||||
{errors.full_name && <FormError>{errors.full_name.message}</FormError>}
|
||||
<UserInfoInput
|
||||
defaultValue={profile.profileIcon && profile.profileIcon.initials ? profile.profileIcon.initials : ''}
|
||||
ref={register({
|
||||
required: 'Initials is required',
|
||||
pattern: { value: INITIALS_PATTERN, message: 'Intials must be between two to four characters' },
|
||||
})}
|
||||
name="initials"
|
||||
width="100%"
|
||||
label="Initials "
|
||||
/>
|
||||
{errors.initials && <FormError>{errors.initials.message}</FormError>}
|
||||
<UserInfoInput disabled defaultValue={profile.username ?? ''} width="100%" label="Username " />
|
||||
<UserInfoInput
|
||||
width="100%"
|
||||
name="email"
|
||||
ref={register({
|
||||
required: 'Email is required',
|
||||
pattern: { value: EMAIL_PATTERN, message: 'Must be a valid email' },
|
||||
})}
|
||||
defaultValue={profile.email ?? ''}
|
||||
label="Email"
|
||||
/>
|
||||
{errors.email && <FormError>{errors.email.message}</FormError>}
|
||||
<UserInfoInput width="100%" name="bio" ref={register()} defaultValue={profile.bio ?? ''} label="Bio" />
|
||||
{errors.bio && <FormError>{errors.bio.message}</FormError>}
|
||||
<SettingActions>
|
||||
<SaveButton disabled={!active} type="submit">
|
||||
Save Change
|
||||
</SaveButton>
|
||||
</SettingActions>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Settings: React.FC<SettingsProps> = ({
|
||||
onProfileAvatarRemove,
|
||||
onProfileAvatarChange,
|
||||
onChangeUserInfo,
|
||||
onResetPassword,
|
||||
profile,
|
||||
}) => {
|
||||
@ -315,6 +405,7 @@ const Settings: React.FC<SettingsProps> = ({
|
||||
<TabNavContent>
|
||||
{items.map((item, idx) => (
|
||||
<NavItem
|
||||
key={item.name}
|
||||
onClick={(tab, top) => {
|
||||
if ($tabNav && $tabNav.current) {
|
||||
const pos = $tabNav.current.getBoundingClientRect();
|
||||
@ -332,23 +423,12 @@ const Settings: React.FC<SettingsProps> = ({
|
||||
</TabNav>
|
||||
<TabContentWrapper>
|
||||
<Tab tab={0} currentTab={currentTab}>
|
||||
<AvatarSettings
|
||||
onProfileAvatarRemove={onProfileAvatarRemove}
|
||||
<UserInfoTab
|
||||
onProfileAvatarChange={onProfileAvatarChange}
|
||||
profile={profile.profileIcon}
|
||||
onProfileAvatarRemove={onProfileAvatarRemove}
|
||||
profile={profile}
|
||||
onChangeUserInfo={onChangeUserInfo}
|
||||
/>
|
||||
<Input defaultValue={profile.fullName} width="100%" label="Name" />
|
||||
<Input
|
||||
defaultValue={profile.profileIcon && profile.profileIcon.initials ? profile.profileIcon.initials : ''}
|
||||
width="100%"
|
||||
label="Initials "
|
||||
/>
|
||||
<Input defaultValue={profile.username ?? ''} width="100%" label="Username " />
|
||||
<Input width="100%" label="Email" />
|
||||
<Input width="100%" label="Bio" />
|
||||
<SettingActions>
|
||||
<SaveButton>Save Change</SaveButton>
|
||||
</SettingActions>
|
||||
</Tab>
|
||||
<Tab tab={1} currentTab={currentTab}>
|
||||
<ResetPasswordTab onResetPassword={onResetPassword} />
|
||||
|
Reference in New Issue
Block a user