asb_cloud_front/src/components/UserMenu.tsx

111 lines
5.0 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
)
})