| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- "use client";
- import { useTranslations } from "next-intl";
- import { Link } from "@/i18n/navigation";
- import { useState } from "react";
- import { ApiError } from "@/lib/api";
- import { sendForgotPasswordEmail } from "@/lib/auth-api";
- import { KeyRound, CheckCircle2 } from "lucide-react";
- import {
- AuthCard,
- AuthCloseButton,
- AuthHeader,
- AuthIconBadge,
- AuthPageScene,
- authErrorCls,
- authFooterLinkCls,
- authInputCls,
- authLabelCls,
- authPrimaryBtnCls,
- } from "@/components/auth/auth-ui";
- type Props = {
- layout: "fullscreen" | "embedded";
- onDismiss?: () => void;
- onBackToLogin?: () => void;
- };
- export function ForgotPasswordFormPanel({ layout, onDismiss, onBackToLogin }: Props) {
- const t = useTranslations("auth");
- const [email, setEmail] = useState("");
- const [done, setDone] = useState(false);
- const [submitting, setSubmitting] = useState(false);
- const [err, setErr] = useState<string | null>(null);
- const embedded = layout === "embedded";
- async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
- e.preventDefault();
- if (submitting) return;
- setErr(null);
- try {
- setSubmitting(true);
- await sendForgotPasswordEmail(email.trim());
- setDone(true);
- } catch (error) {
- if (error instanceof ApiError && error.message.trim()) {
- setErr(error.message);
- } else {
- setErr(t("errorApi"));
- }
- } finally {
- setSubmitting(false);
- }
- }
- return (
- <AuthPageScene layout={layout}>
- <AuthCard layout={layout}>
- {embedded && onDismiss ? <AuthCloseButton onClick={onDismiss} /> : null}
- <AuthIconBadge icon={KeyRound} layout={layout} />
- <AuthHeader title={t("forgotTitle")} subtitle={t("forgotHint")} layout={layout} />
- {!done ? (
- <form onSubmit={onSubmit} className="space-y-5">
- <div>
- <label className={authLabelCls}>{t("email")}</label>
- <input
- type="email"
- required
- value={email}
- onChange={(e) => setEmail(e.target.value)}
- className={authInputCls}
- placeholder="admin@example.com"
- />
- </div>
- {err ? (
- <div className={authErrorCls} role="alert">
- {err}
- </div>
- ) : null}
- <button type="submit" disabled={submitting} className={authPrimaryBtnCls}>
- {submitting ? "发送中..." : t("resetBtn")}
- </button>
- </form>
- ) : (
- <div className="rounded-2xl border border-emerald-400/30 bg-emerald-500/10 p-6 text-center shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]">
- <CheckCircle2 size={40} className="mx-auto mb-4 text-emerald-400" />
- <p className="text-base font-bold text-emerald-300">邮件已发送</p>
- <p className="mt-2 text-sm text-emerald-400/80">请前往您的邮箱查收密码重置链接。</p>
- </div>
- )}
- <p className="mt-8 text-center text-sm text-slate-400/90">
- 想起密码了?{" "}
- {embedded && onBackToLogin ? (
- <button type="button" onClick={onBackToLogin} className={authFooterLinkCls}>
- {t("toLogin")}
- </button>
- ) : (
- <Link href="/auth/login" className={authFooterLinkCls}>
- {t("toLogin")}
- </Link>
- )}
- </p>
- </AuthCard>
- </AuthPageScene>
- );
- }
|