This commit is contained in:
2025-12-14 02:38:35 +07:00
commit 5343a8f2c3
84 changed files with 7406 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
import { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { useAuthStore } from '@/store/auth'
import { Button, Input, Card, CardHeader, CardTitle, CardContent } from '@/components/ui'
const loginSchema = z.object({
login: z.string().min(3, 'Логин должен быть не менее 3 символов'),
password: z.string().min(6, 'Пароль должен быть не менее 6 символов'),
})
type LoginForm = z.infer<typeof loginSchema>
export function LoginPage() {
const navigate = useNavigate()
const { login, isLoading, error, clearError } = useAuthStore()
const [submitError, setSubmitError] = useState<string | null>(null)
const {
register,
handleSubmit,
formState: { errors },
} = useForm<LoginForm>({
resolver: zodResolver(loginSchema),
})
const onSubmit = async (data: LoginForm) => {
setSubmitError(null)
clearError()
try {
await login(data)
navigate('/marathons')
} catch {
setSubmitError(error || 'Ошибка входа')
}
}
return (
<div className="max-w-md mx-auto">
<Card>
<CardHeader>
<CardTitle className="text-center">Вход</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
{(submitError || error) && (
<div className="p-3 bg-red-500/20 border border-red-500 rounded-lg text-red-500 text-sm">
{submitError || error}
</div>
)}
<Input
label="Логин"
placeholder="Введите логин"
error={errors.login?.message}
{...register('login')}
/>
<Input
label="Пароль"
type="password"
placeholder="Введите пароль"
error={errors.password?.message}
{...register('password')}
/>
<Button type="submit" className="w-full" isLoading={isLoading}>
Войти
</Button>
<p className="text-center text-gray-400 text-sm">
Нет аккаунта?{' '}
<Link to="/register" className="link">
Зарегистрироваться
</Link>
</p>
</form>
</CardContent>
</Card>
</div>
)
}