VORKOUT-9 #6

Merged
vlad.dev merged 11 commits from VORKOUT-9 into master 2025-04-29 12:15:41 +05:00
10 changed files with 158 additions and 43 deletions
Showing only changes of commit 53729813ff - Show all commits

View File

@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>VORKOUT</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

View File

@ -1,6 +1,7 @@
import { Drawer } from 'antd';
import { useEffect, useState } from 'react';
import { Avatar, Typography } from 'antd';
import { useTranslation } from 'react-i18next';
interface ContentDrawerProps {
open: boolean;
@ -15,6 +16,7 @@ export default function ContentDrawer({
children,
type,
}: ContentDrawerProps) {
const { t } = useTranslation();
const [width, setWidth] = useState<number | string>('30%');
const calculateWidths = () => {
@ -123,7 +125,7 @@ export default function ContentDrawer({
fontSize: '20px',
}}
>
Новая учетная запись
{t('newAccount')}
</div>
<div
@ -133,6 +135,7 @@ export default function ContentDrawer({
height: '24px',
width: '24px',
}}
onClick={closeDrawer}
>
<img
src="./icons/drawer/delete.svg"

View File

@ -10,6 +10,7 @@ import {
UploadProps,
} from 'antd';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
const { Option } = Select;
@ -24,6 +25,7 @@ const getBase64 = (file: FileType): Promise<string> =>
});
export default function UserCreate() {
const { t } = useTranslation();
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState('');
@ -64,7 +66,9 @@ export default function UserCreate() {
/>
</div>
<span style={{ fontSize: '14px', color: '#8c8c8c' }}>Выбрать фото</span>
<span style={{ fontSize: '14px', color: '#8c8c8c' }}>
{t('selectPhoto')}
</span>
</div>
);
@ -135,54 +139,54 @@ export default function UserCreate() {
style={{ flex: 1, display: 'flex', flexDirection: 'column' }}
>
<Form.Item
label="Имя"
label={t('name')}
name="name"
rules={[{ required: true, message: 'Введите имя' }]}
rules={[{ required: true, message: t('nameMessage') }]}
>
<Input />
</Form.Item>
<Form.Item
label="Логин"
label={t('login')}
name="login"
rules={[{ required: true, message: 'Введите логин' }]}
rules={[{ required: true, message: t('loginMessage') }]}
>
<Input />
</Form.Item>
<Form.Item
label="Пароль"
label={t('password')}
name="password"
rules={[{ required: true, message: 'Введите пароль' }]}
rules={[{ required: true, message: t('passwordMessage') }]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="E-mail"
label={t('email')}
name="email"
rules={[
{ required: true, message: 'Введите имейл' },
{ type: 'email', message: 'Некорректный имейл' },
{ required: true, message: t('emailMessage') },
{ type: 'email', message: t('emailErrorMessage') },
]}
>
<Input />
</Form.Item>
<Form.Item
label="Привязка"
label={t('tenant')}
name="tenant"
rules={[{ required: true, message: 'Введите привязку' }]}
rules={[{ required: true, message: t('tenantMessage') }]}
>
<Input />
</Form.Item>
<Form.Item
label="Роль"
label={t('role')}
name="role"
rules={[{ required: true, message: 'Выберите роль' }]}
rules={[{ required: true, message: t('roleMessage') }]}
>
<Select placeholder="Выберите роль">
<Select placeholder={t('roleMessage')}>
<Option value="Директор магазина">Директор магазина</Option>
<Option value="Менеджер">Менеджер</Option>
<Option value="Кассир">Кассир</Option>
@ -190,11 +194,11 @@ export default function UserCreate() {
</Form.Item>
<Form.Item
label="Статус"
label={t('status')}
name="status"
rules={[{ required: true, message: 'Выберите статус' }]}
rules={[{ required: true, message: t('statusMessage') }]}
>
<Select placeholder="Выберите статус">
<Select placeholder={t('statusMessage')}>
<Option value="ACTIVE">Активен</Option>
<Option value="DISABLED">Неактивен</Option>
<Option value="BLOCKED">Заблокирован</Option>
@ -216,7 +220,7 @@ export default function UserCreate() {
alt="save"
style={{ height: '18px', width: '18px' }}
/>{' '}
Добавить аккаунт
{t('addAccount')}
</Button>
</Form.Item>
</Form>

View File

@ -1,8 +1,10 @@
import { Button, Form, Input, Select } from 'antd';
import { useTranslation } from 'react-i18next';
const { Option } = Select;
export default function UserEdit() {
const { t } = useTranslation();
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<Form
@ -21,54 +23,54 @@ export default function UserEdit() {
style={{ flex: 1, display: 'flex', flexDirection: 'column' }}
>
<Form.Item
label="Имя"
label={t('name')}
name="name"
rules={[{ required: true, message: 'Введите имя' }]}
rules={[{ required: true, message: t('nameMessage') }]}
>
<Input />
</Form.Item>
<Form.Item
label="Логин"
label={t('login')}
name="login"
rules={[{ required: true, message: 'Введите логин' }]}
rules={[{ required: true, message: t('loginMessage') }]}
>
<Input />
</Form.Item>
<Form.Item
label="Пароль (последний ввод)"
label={t('password')}
name="password"
rules={[{ required: true, message: 'Введите пароль' }]}
rules={[{ required: true, message: t('passwordMessage') }]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="E-mail"
label={t('email')}
name="email"
rules={[
{ required: true, message: 'Введите имейл' },
{ type: 'email', message: 'Некорректный имейл' },
{ required: true, message: t('emailMessage') },
{ type: 'email', message: t('emailErrorMessage') },
]}
>
<Input />
</Form.Item>
<Form.Item
label="Привязка"
label={t('tenant')}
name="tenant"
rules={[{ required: true, message: 'Введите привязку' }]}
rules={[{ required: true, message: t('tenantMessage') }]}
>
<Input />
</Form.Item>
<Form.Item
label="Роль"
label={t('role')}
name="role"
rules={[{ required: true, message: 'Выберите роль' }]}
rules={[{ required: true, message: t('roleMessage') }]}
>
<Select placeholder="Выберите роль">
<Select placeholder={t('roleMessage')}>
<Option value="Директор магазина">Директор магазина</Option>
<Option value="Менеджер">Менеджер</Option>
<Option value="Кассир">Кассир</Option>
@ -76,11 +78,11 @@ export default function UserEdit() {
</Form.Item>
<Form.Item
label="Статус"
label={t('status')}
name="status"
rules={[{ required: true, message: 'Выберите статус' }]}
rules={[{ required: true, message: t('statusMessage') }]}
>
<Select placeholder="Выберите статус">
<Select placeholder={t('statusMessage')}>
<Option value="ACTIVE">Активен</Option>
<Option value="DISABLED">Неактивен</Option>
<Option value="BLOCKED">Заблокирован</Option>
@ -102,7 +104,7 @@ export default function UserEdit() {
alt="save"
style={{ height: '18px', width: '18px' }}
/>{' '}
Сохранить изменения
{t('save')}
</Button>
</Form.Item>
</Form>

View File

@ -0,0 +1,24 @@
import './i18n';
import { ConfigProvider } from 'antd';
import { useTranslation } from 'react-i18next';
import { theme } from './customTheme';
import en from 'antd/locale/en_US';
import ru from 'antd/locale/ru_RU';
const antdLocales = {
en: en,
ru: ru,
};
export default function AppWrapper({ children }: any) {
const { i18n } = useTranslation();
const currentLang = i18n.language.split('-')[0] as 'en' | 'ru';
return (
<ConfigProvider locale={antdLocales[currentLang]} theme={theme}>
{children}
</ConfigProvider>
);
}

74
client/src/config/i18n.ts Normal file
View File

@ -0,0 +1,74 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
supportedLngs: ['en', 'ru'],
interpolation: { escapeValue: false },
resources: {
en: {
translation: {
accounts: 'Accounts',
processDiagrams: 'Process diagrams',
runningProcesses: 'Running processes',
settings: 'Settings',
eventsList: 'Events list',
configuration: 'Configuration',
selectPhoto: 'Select photo',
name: 'Name',
login: 'Login',
password: 'Password',
email: 'Email',
tenant: 'Tenant',
role: 'Role',
status: 'Status',
nameMessage: 'Enter name',
loginMessage: 'Enter login',
passwordMessage: 'Enter password',
emailMessage: 'Enter email',
emailErrorMessage: 'Incorrect email',
tenantMessage: 'Enter tenant',
roleMessage: 'Choose role',
statusMessage: 'Choose status',
addAccount: 'Add account',
save: 'Save changes',
newAccount: 'New account',
},
},
ru: {
translation: {
accounts: 'Учетные записи',
processDiagrams: 'Схемы процессов',
runningProcesses: 'Запущенные процессы',
settings: 'Настройки',
eventsList: 'Справочкин событий',
configuration: 'Конфигурация',
selectPhoto: 'Выбрать фото',
name: 'Имя',
login: 'Логин',
password: 'Пароль',
email: 'Имейл',
tenant: 'Привязка',
role: 'Роль',
status: 'Статус',
nameMessage: 'Введите имя',
loginMessage: 'Введите логин',
passwordMessage: 'Введите пароль',
emailMessage: 'Введите имейл',
emailErrorMessage: 'Некорректный имейл',
tenantMessage: 'Введите привязку',
roleMessage: 'Выберите роль',
statusMessage: 'Выберите статус',
addAccount: 'Добавить аккаунт',
save: 'Сохранить изменения',
newAccount: 'Новая учетная запись',
},
},
},
});
export default i18n;

View File

@ -1,9 +1,11 @@
import { useTranslation } from 'react-i18next';
import Header from '../components/Header';
export default function ConfigurationPage() {
const { t } = useTranslation();
return (
<>
<Header title="Конфигурация" />
<Header title={t('configuration')} />
</>
);
}

View File

@ -1,9 +1,11 @@
import { useTranslation } from 'react-i18next';
import Header from '../components/Header';
export default function EventsListPage() {
const { t } = useTranslation();
return (
<>
<Header title="Справочник событий" />
<Header title={t('eventsList')} />
</>
);
}

View File

@ -1,9 +1,11 @@
import { useTranslation } from 'react-i18next';
import Header from '../components/Header';
export default function ProcessDiagramPage() {
const { t } = useTranslation();
return (
<>
<Header title="Схемы процессов" />
<Header title={t('processDiagrams')} />
</>
);
}

View File

@ -1,9 +1,11 @@
import { useTranslation } from 'react-i18next';
import Header from '../components/Header';
export default function RunningProcessesPage() {
const { t } = useTranslation();
return (
<>
<Header title="Запущенные процессы" />
<Header title={t('runningProcesses')} />
</>
);
}