import { type FormEvent, useMemo, useState } from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import { confirmForgotPassword } from "../api/auth"; function useQueryParams() { const location = useLocation(); return useMemo(() => new URLSearchParams(location.search), [location.search]); } const GENERIC_RESET_ERROR = "Invalid or expired reset link."; export default function ResetPasswordPage() { const navigate = useNavigate(); const params = useQueryParams(); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const [pending, setPending] = useState(false); const [success, setSuccess] = useState(null); const [error, setError] = useState(null); const uid = params.get("uid") || ""; const token = params.get("token") || ""; const passwordError = !newPassword ? "New password is required." : newPassword.length < 12 ? "Password must be at least 12 characters." : ""; const confirmError = !confirmPassword ? "Please confirm your password." : confirmPassword !== newPassword ? "Passwords do not match." : ""; async function handleSubmit(e: FormEvent) { e.preventDefault(); setError(null); if (!uid || !token) { setError(GENERIC_RESET_ERROR); return; } if (passwordError || confirmError) { setError(passwordError || confirmError); return; } setPending(true); try { await confirmForgotPassword({ uid, token, newPassword, }); setSuccess("Password reset successful. You can sign in now."); setTimeout(() => navigate("/login", { replace: true }), 1000); } catch (err: any) { if (err?.code === "INVALID_OR_EXPIRED_RESET_LINK" || err?.status === 400) { setError(GENERIC_RESET_ERROR); } else { setError(err?.message || "Unable to reset password."); } } finally { setPending(false); } } return (

Reset Password

Set a new password for your account.

{!uid || !token ?
{GENERIC_RESET_ERROR}
: null} {error ?
{error}
: null} {success ?
{success}
: null}

Request a new reset link

); }