forked from ddrilling/asb_cloud_front
111 lines
5.0 KiB
TypeScript
Executable File
111 lines
5.0 KiB
TypeScript
Executable File
import { memo, ReactNode, useCallback, useState } from 'react'
|
||
import { useNavigate, useLocation } from 'react-router-dom'
|
||
import { Button, Collapse, Drawer, DrawerProps, Form, FormRule, Input, Popconfirm } from 'antd'
|
||
import { useForm } from 'antd/lib/form/Form'
|
||
|
||
import { useUser } from '@asb/context'
|
||
import { Grid, GridItem } from '@components/Grid'
|
||
import LoaderPortal from '@components/LoaderPortal'
|
||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||
import { isURLAvailable, removeUser } from '@utils'
|
||
import { AuthService } from '@api'
|
||
|
||
import '@styles/components/user_menu.less'
|
||
|
||
export type UserMenuProps = DrawerProps & {
|
||
isAdmin?: boolean
|
||
additional?: ReactNode
|
||
}
|
||
|
||
type ChangePasswordForm = {
|
||
'new-password': string
|
||
}
|
||
|
||
const newPasswordRules: FormRule[] = [{ required: true, message: 'Пожалуйста, введите новый пароль!' }]
|
||
|
||
const confirmPasswordRules: FormRule[] = [({ getFieldValue }) => ({ validator(_, value: string) {
|
||
if (value !== getFieldValue('new-password'))
|
||
return Promise.reject('Пароли не совпадают!')
|
||
return Promise.resolve()
|
||
}})]
|
||
|
||
export const UserMenu = memo<UserMenuProps>(({ isAdmin, additional, ...other }) => {
|
||
const [showLoader, setShowLoader] = useState<boolean>(false)
|
||
|
||
const [changeLoginForm] = useForm<ChangePasswordForm>()
|
||
const navigate = useNavigate()
|
||
const location = useLocation()
|
||
const user = useUser()
|
||
|
||
const navigateTo = useCallback((to: string) => navigate(to, { state: { from: location.pathname }}), [navigate, location.pathname])
|
||
|
||
const onChangePasswordOk = useCallback(() => invokeWebApiWrapperAsync(
|
||
async (values: any) => {
|
||
await AuthService.changePassword(user.id ?? -1, `${values['new-password']}`)
|
||
removeUser()
|
||
navigateTo('/login')
|
||
},
|
||
setShowLoader,
|
||
`Не удалось сменить пароль пользователя ${user.login}`,
|
||
{ actionName: 'Смена пароля пользователя' },
|
||
), [navigateTo])
|
||
|
||
const logout = useCallback(() => {
|
||
removeUser()
|
||
navigateTo('/login')
|
||
}, [navigateTo])
|
||
|
||
return (
|
||
<Drawer
|
||
closable
|
||
placement={'left'}
|
||
className={'user-menu'}
|
||
title={'Профиль пользователя'}
|
||
{...other}
|
||
>
|
||
<div className={'profile-links'}>
|
||
{isAdmin ? (
|
||
<Button onClick={() => navigateTo('/')}>Вернуться на сайт</Button>
|
||
) : isURLAvailable('/admin') && (
|
||
<Button onClick={() => navigateTo('/admin')}>Панель администратора</Button>
|
||
)}
|
||
<Button type={'ghost'} onClick={logout}>Выход</Button>
|
||
</div>
|
||
<Collapse>
|
||
<Collapse.Panel header={'Данные'} key={'summary'}>
|
||
<Grid>
|
||
<GridItem row={1} col={1}>Логин:</GridItem>
|
||
<GridItem row={1} col={2}>{user.login}</GridItem>
|
||
<GridItem row={2} col={1}>Фамилия:</GridItem>
|
||
<GridItem row={2} col={2}>{user.surname}</GridItem>
|
||
<GridItem row={3} col={1}>Имя:</GridItem>
|
||
<GridItem row={3} col={2}>{user.name}</GridItem>
|
||
<GridItem row={4} col={1}>Отчество:</GridItem>
|
||
<GridItem row={4} col={2}>{user.patronymic}</GridItem>
|
||
<GridItem row={5} col={1}>E-mail:</GridItem>
|
||
<GridItem row={5} col={2}>{user.email}</GridItem>
|
||
</Grid>
|
||
</Collapse.Panel>
|
||
<Collapse.Panel header={'Смена пароля'} key={'change-password'}>
|
||
<LoaderPortal show={showLoader}>
|
||
<Form name={'change-password'} form={changeLoginForm} autoComplete={'off'} onFinish={onChangePasswordOk}>
|
||
<Form.Item name={'new-password'} label={'Новый пароль'} rules={newPasswordRules}>
|
||
<Input.Password placeholder={'Впишите новый пароль'} />
|
||
</Form.Item>
|
||
<Form.Item required name={'confirm-password'} rules={confirmPasswordRules} label={'Подтверждение пароля'}>
|
||
<Input.Password />
|
||
</Form.Item>
|
||
<Form.Item>
|
||
<Popconfirm title={'Вы уверены что хотите сменить пароль?'} onConfirm={changeLoginForm.submit} placement={'topRight'}>
|
||
<Button type={'primary'}>Сменить</Button>
|
||
</Popconfirm>
|
||
</Form.Item>
|
||
</Form>
|
||
</LoaderPortal>
|
||
</Collapse.Panel>
|
||
{additional}
|
||
</Collapse>
|
||
</Drawer>
|
||
)
|
||
})
|