import React, { useState } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { Button } from './ui/button.js'; import { validatePassword, passwordHelp } from '../utils/passwordRules.ts'; export default function ResetPassword() { const { token } = useParams(); const navigate = useNavigate(); const [pw, setPw] = useState(''); const [pw2, setPw2] = useState(''); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(''); const [ok, setOk] = useState(false); async function onSubmit(e) { e.preventDefault(); setError(''); const pwErr = validatePassword(pw); if (pwErr) { setError(pwErr); return; } if (pw !== pw2) { setError('Passwords do not match.'); return; } setSubmitting(true); try { const r = await fetch('/api/auth/password-reset/confirm', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, password: pw }) }); if (!r.ok) { if (r.status === 429) throw new Error('Too many attempts. Please wait ~30 seconds and try again.'); const j = await r.json().catch(() => ({})); throw new Error(j.error || 'Reset failed'); } setOk(true); } catch (err) { setError(err.message || 'Reset failed'); } finally { setSubmitting(false); } } if (ok) { return (

Password updated

You can now sign in with your new password.

); } if (!token) { return (

Invalid link

This reset link is missing or malformed.

Request a new link
); } return (

Set a new password

setPw(e.target.value)} autoComplete="new-password" required minLength={8} />

{passwordHelp}

setPw2(e.target.value)} autoComplete="new-password" required minLength={8} />
{error &&

{error}

}
Need a new link?
); }