"use client"; import { useRouter } from "next/navigation"; import { startTransition, useState } from "react"; type AccountAuthFormProps = { redirectTo: string; }; type AuthMode = "login" | "register"; export function AccountAuthForm({ redirectTo }: AccountAuthFormProps) { const router = useRouter(); const [mode, setMode] = useState("login"); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [submitting, setSubmitting] = useState(false); const [notice, setNotice] = useState(null); async function handleSubmit(event: React.FormEvent) { event.preventDefault(); if (!username.trim()) { setNotice("请先输入用户名。"); return; } if (!password) { setNotice("请先输入密码。"); return; } if (mode === "register" && password !== confirmPassword) { setNotice("两次输入的密码还不一致,请再检查一次。"); return; } setSubmitting(true); setNotice(mode === "login" ? "正在登录账号……" : "正在创建账号……"); try { const response = await fetch( mode === "login" ? "/api/account/login" : "/api/account/register", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username: username.trim(), password, redirectTo, }), }, ); const payload = (await response.json().catch(() => null)) as | { error?: string; redirectTo?: string } | null; if (!response.ok) { throw new Error( payload?.error || (mode === "login" ? "登录失败,请稍后再试。" : "创建账号失败,请稍后再试。"), ); } setNotice(mode === "login" ? "登录成功,正在进入……" : "账号已创建,正在进入……"); startTransition(() => { router.replace(payload?.redirectTo || redirectTo); router.refresh(); }); } catch (error) { setNotice( error instanceof Error ? error.message : "操作失败,请稍后再试。", ); } finally { setSubmitting(false); } } return (
{[ { id: "login", label: "已有账号,直接登录" }, { id: "register", label: "第一次使用,创建账号" }, ].map((item) => { const active = mode === item.id; return ( ); })}
setUsername(event.target.value)} autoComplete="username" placeholder="例如:family_guardian" className="mt-2 h-13 w-full rounded-[22px] border border-[var(--line)] bg-[var(--paper-soft)] px-4 text-sm text-[var(--ink)] outline-none transition focus:border-[var(--copper)] focus:bg-white" />

建议使用 3 到 24 位字母、数字、下划线或横线,方便全家统一登录。

setPassword(event.target.value)} autoComplete={mode === "login" ? "current-password" : "new-password"} placeholder="请输入密码" className="mt-2 h-13 w-full rounded-[22px] border border-[var(--line)] bg-[var(--paper-soft)] px-4 text-sm text-[var(--ink)] outline-none transition focus:border-[var(--copper)] focus:bg-white" />

密码至少 8 位。同一账号可以在多台家属设备登录,消息提醒会同步到所有已登录设备。

{mode === "register" ? (
setConfirmPassword(event.target.value)} autoComplete="new-password" placeholder="再次输入密码" className="mt-2 h-13 w-full rounded-[22px] border border-[var(--line)] bg-[var(--paper-soft)] px-4 text-sm text-[var(--ink)] outline-none transition focus:border-[var(--copper)] focus:bg-white" />
) : null}
{notice ? (

{notice}

) : null}
); }