119 lines
3.7 KiB
TypeScript
119 lines
3.7 KiB
TypeScript
"use client";
|
||
|
||
import { FormEvent, useState } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { Loader2, UserPlus } from "lucide-react";
|
||
import { Button } from "@/components/ui/button";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogDescription,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/components/ui/dialog";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Label } from "@/components/ui/label";
|
||
import { notify } from "@/lib/notifications/store";
|
||
|
||
interface SecretRegisterDialogProps {
|
||
open: boolean;
|
||
onOpenChange: (open: boolean) => void;
|
||
}
|
||
|
||
export function SecretRegisterDialog({ open, onOpenChange }: SecretRegisterDialogProps) {
|
||
const router = useRouter();
|
||
const [email, setEmail] = useState("");
|
||
const [password, setPassword] = useState("");
|
||
const [name, setName] = useState("");
|
||
const [loading, setLoading] = useState(false);
|
||
|
||
async function handleSubmit(event: FormEvent) {
|
||
event.preventDefault();
|
||
setLoading(true);
|
||
|
||
try {
|
||
const res = await fetch("/api/auth/register", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({
|
||
email,
|
||
password,
|
||
name: name.trim() || undefined,
|
||
}),
|
||
});
|
||
const data = await res.json();
|
||
|
||
if (!res.ok) {
|
||
notify({ type: "error", title: data.error ?? "註冊失敗" });
|
||
setLoading(false);
|
||
return;
|
||
}
|
||
|
||
notify({ type: "success", title: "新帳號已建立", message: "已切換至新帳號" });
|
||
onOpenChange(false);
|
||
setEmail("");
|
||
setPassword("");
|
||
setName("");
|
||
|
||
if (data.needsThreadsBind) {
|
||
router.replace("/matrix?bind_threads=1");
|
||
return;
|
||
}
|
||
router.replace("/matrix");
|
||
} catch {
|
||
notify({ type: "error", title: "連線失敗,請稍後再試" });
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>註冊新帳號</DialogTitle>
|
||
<DialogDescription>建立新的巡樓使用者帳號(建立後會自動切換登入)。</DialogDescription>
|
||
</DialogHeader>
|
||
<form className="space-y-4" onSubmit={handleSubmit}>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="secret-register-name">名稱(選填)</Label>
|
||
<Input
|
||
id="secret-register-name"
|
||
value={name}
|
||
onChange={(event) => setName(event.target.value)}
|
||
placeholder="你的名字"
|
||
autoComplete="name"
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="secret-register-email">Email</Label>
|
||
<Input
|
||
id="secret-register-email"
|
||
type="email"
|
||
value={email}
|
||
onChange={(event) => setEmail(event.target.value)}
|
||
placeholder="you@example.com"
|
||
autoComplete="email"
|
||
required
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="secret-register-password">密碼</Label>
|
||
<Input
|
||
id="secret-register-password"
|
||
type="password"
|
||
value={password}
|
||
onChange={(event) => setPassword(event.target.value)}
|
||
placeholder="至少 6 個字元"
|
||
autoComplete="new-password"
|
||
required
|
||
/>
|
||
</div>
|
||
<Button className="w-full" type="submit" disabled={loading}>
|
||
{loading ? <Loader2 className="h-4 w-4 animate-spin" /> : <UserPlus className="h-4 w-4" />}
|
||
註冊
|
||
</Button>
|
||
</form>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
} |