Files
gitlab-instance-0a899031_no…/app/vip/components/landing/AuthForm.tsx
2026-03-12 04:25:12 -05:00

149 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState, type FormEvent } from "react";
import { pbLogin, pbRegister, pbSaveAuth } from "@/app/lib/pocketbase";
import styles from "../vip.module.css";
type AuthFormProps = {
onSuccess: () => void;
autoFocus?: boolean;
};
export function AuthForm({ onSuccess, autoFocus }: AuthFormProps) {
const [mode, setMode] = useState<"login" | "register">("login");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirm, setPasswordConfirm] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
setError(null);
setLoading(true);
try {
let result;
if (mode === "register") {
if (password !== passwordConfirm) {
setError("两次密码不一致");
setLoading(false);
return;
}
if (password.length < 8) {
setError("密码至少 8 位");
setLoading(false);
return;
}
result = await pbRegister(email, password, passwordConfirm);
} else {
result = await pbLogin(email, password);
}
pbSaveAuth(result.token, result.record);
await fetch("/api/auth/sync-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: result.token, record: result.record }),
credentials: "include",
});
onSuccess();
} catch (err) {
setError(err instanceof Error ? err.message : "操作失败");
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="your@email.com"
required
autoFocus={autoFocus}
disabled={loading}
style={{
width: "100%",
padding: "0.75rem 1rem",
fontSize: "1rem",
border: "1px solid var(--border)",
borderRadius: "8px",
background: "var(--background)",
color: "var(--foreground)",
marginBottom: "0.75rem",
}}
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder={mode === "register" ? "至少 8 位" : "••••••••"}
required
minLength={mode === "register" ? 8 : 1}
disabled={loading}
style={{
width: "100%",
padding: "0.75rem 1rem",
fontSize: "1rem",
border: "1px solid var(--border)",
borderRadius: "8px",
background: "var(--background)",
color: "var(--foreground)",
marginBottom: mode === "register" ? "0.75rem" : 0,
}}
/>
{mode === "register" && (
<input
type="password"
value={passwordConfirm}
onChange={(e) => setPasswordConfirm(e.target.value)}
placeholder="再次输入密码"
required
disabled={loading}
style={{
width: "100%",
padding: "0.75rem 1rem",
fontSize: "1rem",
border: "1px solid var(--border)",
borderRadius: "8px",
background: "var(--background)",
color: "var(--foreground)",
marginBottom: "0.75rem",
}}
/>
)}
{error && (
<p style={{ fontSize: "0.85rem", color: "#ef4444", marginBottom: "0.75rem" }}>
{error}
</p>
)}
<button
type="submit"
disabled={loading}
className={`${styles.btnPrimary} ${styles.btnLarge}`}
style={{ width: "100%", marginBottom: "0.75rem" }}
>
{loading ? "处理中…" : mode === "login" ? "登录" : "注册"}
</button>
<p style={{ fontSize: "0.85rem", color: "var(--muted-foreground)", textAlign: "center" }}>
{mode === "login" ? (
<>
{" "}
<button type="button" onClick={() => { setMode("register"); setError(null); }} className="text-[var(--primary)]">
</button>
</>
) : (
<>
{" "}
<button type="button" onClick={() => { setMode("login"); setError(null); }} className="text-[var(--primary)]">
</button>
</>
)}
</p>
</form>
);
}