import { useState } from "react"; import { Link, useNavigate, useSearchParams } from "react-router"; import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { API_URL, VALIDATION } from "../config/api.ts"; import { useDocumentTitle } from "../hooks/useDocumentTitle.ts"; import { PageShell } from "../components/PageShell.tsx"; import { expectOk, FormError, FormProvider, SubmitButton, TextField, useApiForm, } from "../components/form/index.ts"; interface Values { newPassword: string; confirm: string; } export function ResetPassword() { useDocumentTitle(t`Reset password`); const [params] = useSearchParams(); const navigate = useNavigate(); const token = params.get("token") ?? ""; const [done, setDone] = useState(false); const form = useApiForm({ mode: "onChange", defaultValues: { newPassword: "", confirm: "" }, }); const onSubmit = form.submit(async ({ newPassword }) => { await expectOk( await fetch(`${API_URL}/api/users/reset-password`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token, newPassword }), }), ); setDone(true); }); if (!token) { return (

Invalid link

This reset link is missing or malformed.

Back to login
); } if (done) { return (

Password updated

Your password has been changed. You can now log in.

); } return (

Set new password

name="newPassword" type="password" placeholder={t`New password`} autoComplete="new-password" autoFocus maxLength={VALIDATION.PASSWORD_MAX} rules={{ required: true, minLength: { value: VALIDATION.PASSWORD_MIN, message: t`At least ${VALIDATION.PASSWORD_MIN} characters`, }, }} /> name="confirm" type="password" placeholder={t`Confirm new password`} autoComplete="new-password" rules={{ required: true, validate: (value, values) => value === values.newPassword || t`Passwords do not match`, }} /> Saving…}> Set new password

Back to login

); }