'use client'; import { FormEvent, useState } from 'react'; import Link from 'next/link'; import { SegmentedOtpInput } from './segmented-otp-input'; export function RecoveryForm({ initialToken = '' }: { initialToken?: string }) { const [step, setStep] = useState<'request' | 'reset'>(initialToken ? 'reset' : 'request'); const [email, setEmail] = useState(''); const [token, setToken] = useState(initialToken); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [message, setMessage] = useState(''); const [isSuccess, setIsSuccess] = useState(false); const [busy, setBusy] = useState(false); const [isLongToken, setIsLongToken] = useState(initialToken.length > 6); const [showPassword, setShowPassword] = useState(false); async function submitRequest(event: FormEvent) { event.preventDefault(); if (!email.trim()) return; setBusy(true); setMessage(''); setIsSuccess(false); try { const response = await fetch('/api/auth/password-reset-request', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email: email.trim() }), }); const body = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(body.detail ?? 'Unable to request password recovery.'); } setIsSuccess(true); setMessage('Encrypted recovery code dispatched to your registered email address.'); setStep('reset'); } catch (error) { setIsSuccess(false); setMessage(error instanceof Error ? error.message : 'Unable to request reset.'); } finally { setBusy(false); } } async function submitReset(event: FormEvent) { event.preventDefault(); if (!token.trim()) { setMessage('Please enter your 6-digit verification code or token.'); return; } if (password.length < 12) { setMessage('Password must be at least 12 characters long.'); return; } if (password !== confirmPassword) { setMessage('Passwords do not match.'); return; } setBusy(true); setMessage(''); setIsSuccess(false); try { const response = await fetch('/api/auth/password-reset', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ token: token.trim(), password }), }); const body = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(body.detail ?? 'Unable to reset password.'); } setIsSuccess(true); setMessage('Password reset complete. Your credentials have been re-encrypted. You can now sign in.'); setToken(''); setPassword(''); setConfirmPassword(''); } catch (error) { setIsSuccess(false); setMessage(error instanceof Error ? error.message : 'Unable to reset password.'); } finally { setBusy(false); } } return (
{/* Header section matching Stitch specification */}

Recover Account Access

{step === 'request' ? 'Enter your registered email address to receive an encrypted 6-digit cryptographic verification code.' : 'Enter your 6-digit verification code and specify a new secure master password.'}

{step === 'request' ? ( /* STEP 1: Enter Email */
setEmail(e.target.value)} className="w-full pl-11 pr-4 py-3 bg-[#070a0f] border border-[#262a33] rounded-xl text-white font-mono text-sm focus:border-[#00f2fe] focus:ring-1 focus:ring-[#00f2fe] outline-none transition-all" />
{message && (
{message}
)}
) : ( /* STEP 2: Enter Code & New Password */
{isLongToken ? (
setToken(e.target.value)} className="w-full px-4 py-3 bg-[#070a0f] border border-[#262a33] rounded-xl text-white font-mono text-sm focus:border-[#00f2fe] outline-none" />
) : (
{ setToken(val); setMessage(''); }} disabled={busy || isSuccess} />
)}
Min. 12 characters
setPassword(e.target.value)} className="w-full px-4 py-3 bg-[#070a0f] border border-[#262a33] rounded-xl text-white font-mono text-sm focus:border-[#00f2fe] focus:ring-1 focus:ring-[#00f2fe] outline-none transition-all pr-12" />
setConfirmPassword(e.target.value)} className="w-full px-4 py-3 bg-[#070a0f] border border-[#262a33] rounded-xl text-white font-mono text-sm focus:border-[#00f2fe] focus:ring-1 focus:ring-[#00f2fe] outline-none transition-all" />
{message && (
{message}
)}
)} {/* Bottom Back Link */}
← Return to Sign In
); }