feat(AccountsPage): add userEdit

This commit is contained in:
Vladislav Syrochkin 2025-06-24 16:23:43 +05:00
parent aae56a8c73
commit e5dfdc3464
7 changed files with 139 additions and 44 deletions

View File

@ -109,6 +109,11 @@ const api = {
);
return response.data;
},
async getUserById(userId: number): Promise<User> {
const response = await base.get<User>(`/account/${userId}`);
return response.data;
},
};
export default api;

View File

@ -8,6 +8,9 @@ interface ContentDrawerProps {
closeDrawer: () => void;
children: React.ReactNode;
type: 'create' | 'edit';
login?: string;
name?: string;
email?: string;
}
export default function ContentDrawer({
@ -15,6 +18,9 @@ export default function ContentDrawer({
closeDrawer,
children,
type,
login,
name,
email,
}: ContentDrawerProps) {
const { t } = useTranslation();
const [width, setWidth] = useState<number | string>('30%');
@ -59,16 +65,18 @@ export default function ContentDrawer({
<div style={{ display: 'flex', alignItems: 'center', gap: 12, flex: 1 }}>
<Avatar
src="https://cdn-icons-png.flaticon.com/512/219/219986.png"
src={
login ? `https://gamma.heado.ru/go/ava?name=${login}` : undefined
}
size={40}
style={{ flexShrink: 0 }}
/>
<div>
<Typography.Text strong style={{ display: 'block' }}>
Александр Александров
{name}
</Typography.Text>
<Typography.Text type="secondary" style={{ fontSize: 14 }}>
alexandralex@vorkout.ru
{email}
</Typography.Text>
</div>
</div>
@ -152,7 +160,6 @@ export default function ContentDrawer({
placement="right"
open={open}
width={width}
destroyOnClose={true}
closable={false}
>
{children}

View File

@ -1,3 +1,4 @@
import { useUserSelector } from '@/store/userStore';
import { Divider, Menu, Tooltip } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
@ -13,6 +14,7 @@ export default function SiderMenu({
selectedKey,
hangleMenuClick,
}: SiderMenuProps) {
const user = useUserSelector();
const { t } = useTranslation();
const collapseStyle = collapsed
? { fontSize: '12px' }
@ -74,7 +76,8 @@ export default function SiderMenu({
label: t('settings'),
className: 'no-expand-icon',
children: [
{
user && (user.role === 'OWNER' || user.role === 'ADMIN')
? {
key: '/accounts',
label: !collapsed ? (
<Tooltip title={t('accounts')}>{t('accounts')}</Tooltip>
@ -82,7 +85,8 @@ export default function SiderMenu({
t('accounts')
),
style: collapseStyle,
},
}
: undefined,
{
key: '/events-list',
label: !collapsed ? (

View File

@ -11,6 +11,7 @@ import {
} from 'antd';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useUserSelector } from '@/store/userStore';
const { Option } = Select;
@ -25,6 +26,7 @@ const getBase64 = (file: FileType): Promise<string> =>
});
export default function UserCreate() {
const user = useUserSelector();
const { t } = useTranslation();
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState('');
@ -187,9 +189,11 @@ export default function UserCreate() {
rules={[{ required: true, message: t('roleMessage') }]}
>
<Select placeholder={t('roleMessage')}>
<Option value="Директор магазина">Директор магазина</Option>
<Option value="Менеджер">Менеджер</Option>
<Option value="Кассир">Кассир</Option>
{user && user.role === 'OWNER' ? (
<Option value="ADMIN">{t('ADMIN')}</Option>
) : undefined}
<Option value="EDITOR">{t('EDITOR')}</Option>
<Option value="VIEWER">{t('VIEWER')}</Option>
</Select>
</Form.Item>
@ -199,10 +203,10 @@ export default function UserCreate() {
rules={[{ required: true, message: t('statusMessage') }]}
>
<Select placeholder={t('statusMessage')}>
<Option value="ACTIVE">Активен</Option>
<Option value="DISABLED">Неактивен</Option>
<Option value="BLOCKED">Заблокирован</Option>
<Option value="DELETED">Удален</Option>
<Option value="ACTIVE">{t('ACTIVE')}</Option>
<Option value="DISABLED">{t('DISABLED')}</Option>
<Option value="BLOCKED">{t('BLOCKED')}</Option>
<Option value="DELETED">{t('DELETED')}</Option>
</Select>
</Form.Item>

View File

@ -1,25 +1,43 @@
import { UserService } from '@/services/userService';
import { useUserSelector } from '@/store/userStore';
import { User } from '@/types/user';
import { Button, Form, Input, Select } from 'antd';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
const { Option } = Select;
export default function UserEdit() {
interface UserEditProps {
userId?: number;
}
export default function UserEdit({ userId }: UserEditProps) {
const currentUser = useUserSelector();
const [form] = Form.useForm();
const { t } = useTranslation();
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
async function getUser() {
if (typeof userId === 'undefined') {
return;
}
const user = await UserService.getUserById(userId);
setUser(user);
form.setFieldsValue({ ...user });
}
getUser();
}, []);
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<Form
form={form}
name="user-edit-form"
layout="vertical"
// onFinish={onFinish}
initialValues={{
name: 'Александр Александров',
login: 'alexandralex@vorkout.ru',
password: 'jKUUl776GHd',
email: 'alexandralex@vorkout.ru',
tenant: 'text',
role: 'Директор магазина',
status: 'Активен',
}}
initialValues={{ ...user }}
style={{ flex: 1, display: 'flex', flexDirection: 'column' }}
>
<Form.Item
@ -71,9 +89,11 @@ export default function UserEdit() {
rules={[{ required: true, message: t('roleMessage') }]}
>
<Select placeholder={t('roleMessage')}>
<Option value="Директор магазина">Директор магазина</Option>
<Option value="Менеджер">Менеджер</Option>
<Option value="Кассир">Кассир</Option>
{currentUser && currentUser.role === 'OWNER' ? (
<Option value="ADMIN">{t('ADMIN')}</Option>
) : undefined}
<Option value="EDITOR">{t('EDITOR')}</Option>
<Option value="VIEWER">{t('VIEWER')}</Option>
</Select>
</Form.Item>
@ -83,10 +103,10 @@ export default function UserEdit() {
rules={[{ required: true, message: t('statusMessage') }]}
>
<Select placeholder={t('statusMessage')}>
<Option value="ACTIVE">Активен</Option>
<Option value="DISABLED">Неактивен</Option>
<Option value="BLOCKED">Заблокирован</Option>
<Option value="DELETED">Удален</Option>
<Option value="ACTIVE">{t('ACTIVE')}</Option>
<Option value="DISABLED">{t('DISABLED')}</Option>
<Option value="BLOCKED">{t('BLOCKED')}</Option>
<Option value="DELETED">{t('DELETED')}</Option>
</Select>
</Form.Item>

View File

@ -7,13 +7,28 @@ import UserCreate from '@/components/UserCreate';
import { Avatar, Table } from 'antd';
import { TableProps } from 'antd/lib';
import { UserService } from '@/services/userService';
import UserEdit from '@/components/UserEdit';
export default function AccountsPage() {
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const [openCreate, setOpenCreate] = useState(false);
const showDrawer = () => setOpen(true);
const closeDrawer = () => setOpen(false);
const [activeAccount, setActiveAccount] = useState<
{ login: string; id: number; name: string; email: string } | undefined
>(undefined);
const showCreateDrawer = () => setOpenCreate(true);
const closeCreateDrawer = () => {
setActiveAccount(undefined);
setOpenCreate(false);
};
const [openEdit, setOpenEdit] = useState(false);
const showEditDrawer = () => setOpenEdit(true);
const closeEditDrawer = () => {
setActiveAccount(undefined);
setOpenEdit(false);
};
const [accounts, setAccounts] = useState<AllUserResponse>({
amountCount: 0,
@ -49,7 +64,23 @@ export default function AccountsPage() {
dataIndex: 'nameLogin',
key: 'nameLogin',
render: (text, record) => (
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
<div
onClick={() => {
setActiveAccount({
login: record.login,
id: record.id,
name: record.name,
email: record.email || '',
});
showEditDrawer();
}}
style={{
display: 'flex',
alignItems: 'center',
gap: '16px',
cursor: 'pointer',
}}
>
<div
style={{
height: '32px',
@ -124,7 +155,7 @@ export default function AccountsPage() {
width: '18px',
cursor: 'pointer',
}}
onClick={showDrawer}
onClick={showCreateDrawer}
/>
}
/>
@ -140,9 +171,23 @@ export default function AccountsPage() {
rowKey={'id'}
/>
<ContentDrawer open={open} closeDrawer={closeDrawer} type="create">
<ContentDrawer
open={openCreate}
closeDrawer={closeCreateDrawer}
type="create"
>
<UserCreate />
</ContentDrawer>
<ContentDrawer
login={activeAccount?.login}
name={activeAccount?.name}
email={activeAccount?.email}
open={openEdit}
closeDrawer={closeEditDrawer}
type="edit"
>
<UserEdit userId={activeAccount?.id} />
</ContentDrawer>
</>
);
}

View File

@ -9,8 +9,18 @@ export class UserService {
return user;
}
static async getUsers(page: number = 1, limit: number = 10): Promise<AllUserResponse> {
static async getUsers(
page: number = 1,
limit: number = 10
): Promise<AllUserResponse> {
console.log('getUsers');
const allUsers = api.getUsers(page, limit);
return allUsers;
}
static async getUserById(userId: number): Promise<User> {
console.log('getUserById');
const user = api.getUserById(userId);
return user;
}
}