feat: Login and Register pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+61
-1
@@ -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
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user