Test / components /studio /LoginDialog.tsx
TrikozikGames's picture
Add source files
eddc354
Raw
History Blame Contribute Delete
5.84 kB
import { useState, type FormEvent } from "react";
import { KeyRound, ShieldCheck } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { login, setPermanentPassword, type StoredUser } from "@/lib/auth-service";
export default function LoginDialog({ onSignedIn }: { onSignedIn: (user: StoredUser) => void }) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [remember, setRemember] = useState(true);
const [error, setError] = useState<string | null>(null);
/** Пользователь вошёл по временному паролю — требуется постоянный. */
const [pending, setPending] = useState<StoredUser | null>(null);
const [next, setNext] = useState("");
const [confirm, setConfirm] = useState("");
const submitLogin = (e: FormEvent) => {
e.preventDefault();
const result = login(username, password, remember);
if (!result.ok) {
setError(result.error);
return;
}
setError(null);
if (result.mustChangePassword) {
setPending(result.user);
return;
}
onSignedIn(result.user);
};
const submitNewPassword = (e: FormEvent) => {
e.preventDefault();
if (!pending) return;
if (next !== confirm) {
setError("Пароли не совпадают.");
return;
}
const result = setPermanentPassword(pending.id, next);
if (!result.ok) {
setError(result.error ?? "Не удалось сохранить пароль.");
return;
}
onSignedIn({ ...pending, temporary: false, status: "active" });
};
if (pending) {
return (
<Dialog open>
<DialogContent className="max-w-sm [&>button]:hidden">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 font-display text-2xl">
<ShieldCheck className="h-6 w-6 text-accent" /> Новый пароль
</DialogTitle>
<DialogDescription>
Вы вошли по временному паролю. Задайте постоянный пароль, чтобы продолжить работу.
</DialogDescription>
</DialogHeader>
<form onSubmit={submitNewPassword} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="new-password">Новый пароль</Label>
<Input
id="new-password"
autoFocus
type="password"
value={next}
onChange={(e) => {
setNext(e.target.value);
setError(null);
}}
className="h-12"
/>
</div>
<div className="space-y-2">
<Label htmlFor="confirm-password">Повторите пароль</Label>
<Input
id="confirm-password"
type="password"
value={confirm}
onChange={(e) => {
setConfirm(e.target.value);
setError(null);
}}
className="h-12"
/>
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
<Button type="submit" size="lg" className="h-12 w-full">
Сохранить и войти
</Button>
</form>
</DialogContent>
</Dialog>
);
}
return (
<Dialog open>
<DialogContent className="max-w-sm [&>button]:hidden">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 font-display text-2xl">
<KeyRound className="h-6 w-6 text-accent" /> RealKnot Studio
</DialogTitle>
<DialogDescription>Войдите в аккаунт, чтобы открыть студию и свои проекты.</DialogDescription>
</DialogHeader>
<form onSubmit={submitLogin} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="login">Логин</Label>
<Input
id="login"
autoFocus
autoComplete="username"
placeholder="admin"
value={username}
onChange={(e) => {
setUsername(e.target.value);
setError(null);
}}
className="h-12"
/>
</div>
<div className="space-y-2">
<Label htmlFor="password">Пароль</Label>
<Input
id="password"
type="password"
autoComplete="current-password"
value={password}
onChange={(e) => {
setPassword(e.target.value);
setError(null);
}}
className="h-12"
/>
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
<label className="flex cursor-pointer items-center gap-2 text-sm">
<Checkbox checked={remember} onCheckedChange={(v) => setRemember(v === true)} />
Запомнить меня
</label>
<Button type="submit" size="lg" className="h-12 w-full">
Войти в студию
</Button>
<p className="text-center text-xs text-muted-foreground">
Аккаунт создаёт администратор в «Панели админа».
</p>
</form>
</DialogContent>
</Dialog>
);
}