feat: Login and Register pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 12:26:15 +03:00
parent 0be6b30713
commit 5f1e06a793
2 changed files with 119 additions and 2 deletions
+61 -1
View File
@@ -1 +1,61 @@
export default function Login() { return <div>Login</div>; }
import { useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { Shield } from "lucide-react";
import { api } from "../api/client";
import { useAuthStore } from "../store/auth";
import { Button } from "../components/ui/Button";
import { Input } from "../components/ui/Input";
import { GlassCard } from "../components/ui/GlassCard";
export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const { setAuth } = useAuthStore();
const navigate = useNavigate();
async function handleLogin(e: React.FormEvent) {
e.preventDefault();
setError("");
setLoading(true);
const res = await api.login(email, password);
setLoading(false);
if (!res.ok) { setError(res.error || "Ошибка входа"); return; }
setAuth(res.access_token, res.refresh_token, res.user);
navigate("/dashboard");
}
return (
<div className="min-h-screen flex items-center justify-center px-4">
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 rounded-full bg-accent/10 blur-[100px]" />
</div>
<GlassCard className="w-full max-w-md relative z-10" animate={false}>
<div className="text-center mb-8">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-accent to-accent2 flex items-center justify-center mx-auto mb-3">
<Shield size={24} />
</div>
<h1 className="text-2xl font-bold">Войти в Aura Store</h1>
<p className="text-sm text-white/40 mt-1">Доступ к личному кабинету</p>
</div>
<div className="flex items-center gap-3 mb-6">
<div className="flex-1 h-px bg-white/10" />
<span className="text-xs text-white/30">email</span>
<div className="flex-1 h-px bg-white/10" />
</div>
<form onSubmit={handleLogin} className="space-y-4">
<Input label="Email" type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@example.com" required />
<Input label="Пароль" type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="••••••••" required error={error} />
<Button type="submit" loading={loading} className="w-full text-base py-3">Войти</Button>
</form>
<p className="text-center text-sm text-white/40 mt-5">
Нет аккаунта? <Link to="/register" className="text-accent hover:underline">Зарегистрироваться</Link>
</p>
</GlassCard>
</div>
);
}
+58 -1
View File
@@ -1 +1,58 @@
export default function Register() { return <div>Register</div>; }
import { useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { Shield } from "lucide-react";
import { api } from "../api/client";
import { useAuthStore } from "../store/auth";
import { Button } from "../components/ui/Button";
import { Input } from "../components/ui/Input";
import { GlassCard } from "../components/ui/GlassCard";
export default function Register() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const { setAuth } = useAuthStore();
const navigate = useNavigate();
async function handleRegister(e: React.FormEvent) {
e.preventDefault();
setError("");
if (password.length < 6) { setError("Пароль минимум 6 символов"); return; }
setLoading(true);
const res = await api.register(email, password, name);
setLoading(false);
if (!res.ok) { setError(res.error || "Ошибка регистрации"); return; }
setAuth(res.access_token, res.refresh_token, res.user);
navigate("/dashboard");
}
return (
<div className="min-h-screen flex items-center justify-center px-4">
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 rounded-full bg-accent/10 blur-[100px]" />
</div>
<GlassCard className="w-full max-w-md relative z-10" animate={false}>
<div className="text-center mb-8">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-accent to-accent2 flex items-center justify-center mx-auto mb-3">
<Shield size={24} />
</div>
<h1 className="text-2xl font-bold">Создать аккаунт</h1>
<p className="text-sm text-white/40 mt-1">Регистрация в Aura Store</p>
</div>
<form onSubmit={handleRegister} className="space-y-4">
<Input label="Имя" value={name} onChange={(e) => setName(e.target.value)} placeholder="Ваше имя" />
<Input label="Email" type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@example.com" required />
<Input label="Пароль" type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Минимум 6 символов" required error={error} />
<Button type="submit" loading={loading} className="w-full text-base py-3">Зарегистрироваться</Button>
</form>
<p className="text-center text-sm text-white/40 mt-5">
Уже есть аккаунт? <Link to="/login" className="text-accent hover:underline">Войти</Link>
</p>
</GlassCard>
</div>
);
}