VORKOUT-8 #13
@ -109,6 +109,11 @@ const api = {
|
|||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async getUserById(userId: number): Promise<User> {
|
||||||
|
const response = await base.get<User>(`/account/${userId}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
@ -8,6 +8,9 @@ interface ContentDrawerProps {
|
|||||||
closeDrawer: () => void;
|
closeDrawer: () => void;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
type: 'create' | 'edit';
|
type: 'create' | 'edit';
|
||||||
|
login?: string;
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ContentDrawer({
|
export default function ContentDrawer({
|
||||||
@ -15,6 +18,9 @@ export default function ContentDrawer({
|
|||||||
closeDrawer,
|
closeDrawer,
|
||||||
children,
|
children,
|
||||||
type,
|
type,
|
||||||
|
login,
|
||||||
|
name,
|
||||||
|
email,
|
||||||
}: ContentDrawerProps) {
|
}: ContentDrawerProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [width, setWidth] = useState<number | string>('30%');
|
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 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12, flex: 1 }}>
|
||||||
<Avatar
|
<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}
|
size={40}
|
||||||
style={{ flexShrink: 0 }}
|
style={{ flexShrink: 0 }}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<Typography.Text strong style={{ display: 'block' }}>
|
<Typography.Text strong style={{ display: 'block' }}>
|
||||||
Александр Александров
|
{name}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<Typography.Text type="secondary" style={{ fontSize: 14 }}>
|
<Typography.Text type="secondary" style={{ fontSize: 14 }}>
|
||||||
alexandralex@vorkout.ru
|
{email}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -152,7 +160,6 @@ export default function ContentDrawer({
|
|||||||
placement="right"
|
placement="right"
|
||||||
open={open}
|
open={open}
|
||||||
width={width}
|
width={width}
|
||||||
destroyOnClose={true}
|
|
||||||
closable={false}
|
closable={false}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useUserSelector } from '@/store/userStore';
|
||||||
import { Divider, Menu, Tooltip } from 'antd';
|
import { Divider, Menu, Tooltip } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -13,6 +14,7 @@ export default function SiderMenu({
|
|||||||
selectedKey,
|
selectedKey,
|
||||||
hangleMenuClick,
|
hangleMenuClick,
|
||||||
}: SiderMenuProps) {
|
}: SiderMenuProps) {
|
||||||
|
const user = useUserSelector();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const collapseStyle = collapsed
|
const collapseStyle = collapsed
|
||||||
? { fontSize: '12px' }
|
? { fontSize: '12px' }
|
||||||
@ -74,15 +76,17 @@ export default function SiderMenu({
|
|||||||
label: t('settings'),
|
label: t('settings'),
|
||||||
className: 'no-expand-icon',
|
className: 'no-expand-icon',
|
||||||
children: [
|
children: [
|
||||||
{
|
user && (user.role === 'OWNER' || user.role === 'ADMIN')
|
||||||
key: '/accounts',
|
? {
|
||||||
label: !collapsed ? (
|
key: '/accounts',
|
||||||
<Tooltip title={t('accounts')}>{t('accounts')}</Tooltip>
|
label: !collapsed ? (
|
||||||
) : (
|
<Tooltip title={t('accounts')}>{t('accounts')}</Tooltip>
|
||||||
t('accounts')
|
) : (
|
||||||
),
|
t('accounts')
|
||||||
style: collapseStyle,
|
),
|
||||||
},
|
style: collapseStyle,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
{
|
{
|
||||||
key: '/events-list',
|
key: '/events-list',
|
||||||
label: !collapsed ? (
|
label: !collapsed ? (
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useUserSelector } from '@/store/userStore';
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ const getBase64 = (file: FileType): Promise<string> =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default function UserCreate() {
|
export default function UserCreate() {
|
||||||
|
const user = useUserSelector();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [previewOpen, setPreviewOpen] = useState(false);
|
const [previewOpen, setPreviewOpen] = useState(false);
|
||||||
const [previewImage, setPreviewImage] = useState('');
|
const [previewImage, setPreviewImage] = useState('');
|
||||||
@ -187,9 +189,11 @@ export default function UserCreate() {
|
|||||||
rules={[{ required: true, message: t('roleMessage') }]}
|
rules={[{ required: true, message: t('roleMessage') }]}
|
||||||
>
|
>
|
||||||
<Select placeholder={t('roleMessage')}>
|
<Select placeholder={t('roleMessage')}>
|
||||||
<Option value="Директор магазина">Директор магазина</Option>
|
{user && user.role === 'OWNER' ? (
|
||||||
<Option value="Менеджер">Менеджер</Option>
|
<Option value="ADMIN">{t('ADMIN')}</Option>
|
||||||
<Option value="Кассир">Кассир</Option>
|
) : undefined}
|
||||||
|
<Option value="EDITOR">{t('EDITOR')}</Option>
|
||||||
|
<Option value="VIEWER">{t('VIEWER')}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@ -199,10 +203,10 @@ export default function UserCreate() {
|
|||||||
rules={[{ required: true, message: t('statusMessage') }]}
|
rules={[{ required: true, message: t('statusMessage') }]}
|
||||||
>
|
>
|
||||||
<Select placeholder={t('statusMessage')}>
|
<Select placeholder={t('statusMessage')}>
|
||||||
<Option value="ACTIVE">Активен</Option>
|
<Option value="ACTIVE">{t('ACTIVE')}</Option>
|
||||||
<Option value="DISABLED">Неактивен</Option>
|
<Option value="DISABLED">{t('DISABLED')}</Option>
|
||||||
<Option value="BLOCKED">Заблокирован</Option>
|
<Option value="BLOCKED">{t('BLOCKED')}</Option>
|
||||||
<Option value="DELETED">Удален</Option>
|
<Option value="DELETED">{t('DELETED')}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
@ -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 { Button, Form, Input, Select } from 'antd';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const { Option } = Select;
|
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 { 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 (
|
return (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
<Form
|
<Form
|
||||||
|
form={form}
|
||||||
name="user-edit-form"
|
name="user-edit-form"
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
// onFinish={onFinish}
|
// onFinish={onFinish}
|
||||||
initialValues={{
|
initialValues={{ ...user }}
|
||||||
name: 'Александр Александров',
|
|
||||||
login: 'alexandralex@vorkout.ru',
|
|
||||||
password: 'jKUUl776GHd',
|
|
||||||
email: 'alexandralex@vorkout.ru',
|
|
||||||
tenant: 'text',
|
|
||||||
role: 'Директор магазина',
|
|
||||||
status: 'Активен',
|
|
||||||
}}
|
|
||||||
style={{ flex: 1, display: 'flex', flexDirection: 'column' }}
|
style={{ flex: 1, display: 'flex', flexDirection: 'column' }}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@ -71,9 +89,11 @@ export default function UserEdit() {
|
|||||||
rules={[{ required: true, message: t('roleMessage') }]}
|
rules={[{ required: true, message: t('roleMessage') }]}
|
||||||
>
|
>
|
||||||
<Select placeholder={t('roleMessage')}>
|
<Select placeholder={t('roleMessage')}>
|
||||||
<Option value="Директор магазина">Директор магазина</Option>
|
{currentUser && currentUser.role === 'OWNER' ? (
|
||||||
<Option value="Менеджер">Менеджер</Option>
|
<Option value="ADMIN">{t('ADMIN')}</Option>
|
||||||
<Option value="Кассир">Кассир</Option>
|
) : undefined}
|
||||||
|
<Option value="EDITOR">{t('EDITOR')}</Option>
|
||||||
|
<Option value="VIEWER">{t('VIEWER')}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@ -83,10 +103,10 @@ export default function UserEdit() {
|
|||||||
rules={[{ required: true, message: t('statusMessage') }]}
|
rules={[{ required: true, message: t('statusMessage') }]}
|
||||||
>
|
>
|
||||||
<Select placeholder={t('statusMessage')}>
|
<Select placeholder={t('statusMessage')}>
|
||||||
<Option value="ACTIVE">Активен</Option>
|
<Option value="ACTIVE">{t('ACTIVE')}</Option>
|
||||||
<Option value="DISABLED">Неактивен</Option>
|
<Option value="DISABLED">{t('DISABLED')}</Option>
|
||||||
<Option value="BLOCKED">Заблокирован</Option>
|
<Option value="BLOCKED">{t('BLOCKED')}</Option>
|
||||||
<Option value="DELETED">Удален</Option>
|
<Option value="DELETED">{t('DELETED')}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
@ -7,13 +7,28 @@ import UserCreate from '@/components/UserCreate';
|
|||||||
import { Avatar, Table } from 'antd';
|
import { Avatar, Table } from 'antd';
|
||||||
import { TableProps } from 'antd/lib';
|
import { TableProps } from 'antd/lib';
|
||||||
import { UserService } from '@/services/userService';
|
import { UserService } from '@/services/userService';
|
||||||
|
import UserEdit from '@/components/UserEdit';
|
||||||
|
|
||||||
export default function AccountsPage() {
|
export default function AccountsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [open, setOpen] = useState(false);
|
const [openCreate, setOpenCreate] = useState(false);
|
||||||
|
|
||||||
const showDrawer = () => setOpen(true);
|
const [activeAccount, setActiveAccount] = useState<
|
||||||
const closeDrawer = () => setOpen(false);
|
{ 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>({
|
const [accounts, setAccounts] = useState<AllUserResponse>({
|
||||||
amountCount: 0,
|
amountCount: 0,
|
||||||
@ -49,7 +64,23 @@ export default function AccountsPage() {
|
|||||||
dataIndex: 'nameLogin',
|
dataIndex: 'nameLogin',
|
||||||
key: 'nameLogin',
|
key: 'nameLogin',
|
||||||
render: (text, record) => (
|
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
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: '32px',
|
height: '32px',
|
||||||
@ -124,7 +155,7 @@ export default function AccountsPage() {
|
|||||||
width: '18px',
|
width: '18px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
onClick={showDrawer}
|
onClick={showCreateDrawer}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -140,9 +171,23 @@ export default function AccountsPage() {
|
|||||||
rowKey={'id'}
|
rowKey={'id'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ContentDrawer open={open} closeDrawer={closeDrawer} type="create">
|
<ContentDrawer
|
||||||
|
open={openCreate}
|
||||||
|
closeDrawer={closeCreateDrawer}
|
||||||
|
type="create"
|
||||||
|
>
|
||||||
<UserCreate />
|
<UserCreate />
|
||||||
</ContentDrawer>
|
</ContentDrawer>
|
||||||
|
<ContentDrawer
|
||||||
|
login={activeAccount?.login}
|
||||||
|
name={activeAccount?.name}
|
||||||
|
email={activeAccount?.email}
|
||||||
|
open={openEdit}
|
||||||
|
closeDrawer={closeEditDrawer}
|
||||||
|
type="edit"
|
||||||
|
>
|
||||||
|
<UserEdit userId={activeAccount?.id} />
|
||||||
|
</ContentDrawer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,18 @@ export class UserService {
|
|||||||
return user;
|
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);
|
const allUsers = api.getUsers(page, limit);
|
||||||
return allUsers;
|
return allUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async getUserById(userId: number): Promise<User> {
|
||||||
|
console.log('getUserById');
|
||||||
|
const user = api.getUserById(userId);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user