fix(auth): i18n и react-hook-form на странице логина
Добавлены i18next, схема zod и react-hook-form для формы входа. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,51 +1,67 @@
|
||||
import React from 'react';
|
||||
import { Form, Input, Button, Card, message } from 'antd';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { isAxiosError } from 'axios';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuthStore } from '../../store/authStore';
|
||||
|
||||
const LOGIN_ERROR_MESSAGES: Record<string, string> = {
|
||||
invalid_credentials: 'Неверный email или пароль',
|
||||
insufficient_permissions: 'Недостаточно прав для входа',
|
||||
};
|
||||
|
||||
const getLoginErrorMessage = (error: unknown): string => {
|
||||
if (isAxiosError(error)) {
|
||||
const apiError = error.response?.data?.error;
|
||||
if (typeof apiError === 'string') {
|
||||
return LOGIN_ERROR_MESSAGES[apiError] ?? apiError;
|
||||
}
|
||||
}
|
||||
return 'Ошибка входа';
|
||||
};
|
||||
import { loginSchema, LoginFormValues } from '../../schemas/loginSchema';
|
||||
|
||||
const LoginPage: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const login = useAuthStore((s) => s.login);
|
||||
const [form] = Form.useForm();
|
||||
const { t } = useTranslation();
|
||||
const { control, handleSubmit, formState: { errors, isSubmitting } } = useForm<LoginFormValues>({
|
||||
resolver: zodResolver(loginSchema),
|
||||
defaultValues: { email: '', password: '' },
|
||||
});
|
||||
|
||||
const onFinish = async (values: { email: string; password: string }) => {
|
||||
const onFinish = async (values: LoginFormValues) => {
|
||||
try {
|
||||
await login(values.email, values.password);
|
||||
navigate('/dashboard');
|
||||
} catch (error) {
|
||||
message.error(getLoginErrorMessage(error));
|
||||
if (isAxiosError(error)) {
|
||||
const apiError = error.response?.data?.error;
|
||||
if (typeof apiError === 'string') {
|
||||
message.error(t(`login.${apiError}`, { defaultValue: apiError }));
|
||||
return;
|
||||
}
|
||||
}
|
||||
message.error(t('login.error'));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
|
||||
<Card title="Вход" style={{ width: 400 }}>
|
||||
<Form form={form} onFinish={onFinish} layout="vertical">
|
||||
<Form.Item name="email" label="Email" rules={[{ required: true }]}>
|
||||
<Input autoComplete="username" />
|
||||
<Card title={t('login.title')} style={{ width: 400 }}>
|
||||
<Form layout="vertical" onFinish={handleSubmit(onFinish)}>
|
||||
<Form.Item
|
||||
label={t('login.email')}
|
||||
validateStatus={errors.email ? 'error' : ''}
|
||||
help={errors.email?.message}
|
||||
>
|
||||
<Controller
|
||||
name="email"
|
||||
control={control}
|
||||
render={({ field }) => <Input {...field} autoComplete="username" />}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item name="password" label="Пароль" rules={[{ required: true }]}>
|
||||
<Input.Password autoComplete="current-password" />
|
||||
<Form.Item
|
||||
label={t('login.password')}
|
||||
validateStatus={errors.password ? 'error' : ''}
|
||||
help={errors.password?.message}
|
||||
>
|
||||
<Controller
|
||||
name="password"
|
||||
control={control}
|
||||
render={({ field }) => <Input.Password {...field} autoComplete="current-password" />}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" block>
|
||||
Войти
|
||||
<Button type="primary" htmlType="submit" block loading={isSubmitting}>
|
||||
{t('login.submit')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
Reference in New Issue
Block a user