"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import Link from "next/link"; import { useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { KeyRound, Loader2 } from "lucide-react"; import { z } from "zod"; import { FormField } from "@/components/ui/form-field"; import { TurnstileWidget, type TurnstileWidgetHandle } from "@/components/ui/turnstile-widget"; import { authErrorMessage, useRequestPasswordReset, useSystemStatus } from "@/hooks/use-auth"; const forgotSchema = z.object({ email: z.string().email("Enter a valid email address"), }); type ForgotForm = z.infer; export default function ForgotPasswordPage() { const { data: status } = useSystemStatus(); const resetMutation = useRequestPasswordReset(); const turnstileRef = useRef(null); const [turnstileToken, setTurnstileToken] = useState(null); const [submittedEmail, setSubmittedEmail] = useState(null); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(forgotSchema) }); // Mirrors the backend's turnstile_required(is_localhost, settings) gate // exactly - skipped on loopback regardless of auth mode. const turnstileRequired = status ? !status.is_localhost : false; const onSubmit = handleSubmit(async (values) => { try { await resetMutation.mutateAsync({ email: values.email, turnstile_token: turnstileToken ?? undefined, }); setSubmittedEmail(values.email); } catch { // Surfaced via resetMutation.isError below. } finally { turnstileRef.current?.reset(); setTurnstileToken(null); } }); return (

Reset your password

We'll email you a code to reset it.

{submittedEmail ? (

If an account exists for {submittedEmail}, a reset code is on its way.

I have a code
) : (
{turnstileRequired && ( )} {resetMutation.isError && (

{authErrorMessage(resetMutation.error)}

)} )}

Back to sign in

); }