spb/autoscholar
Public
1"use client";2import { useRouter } from "next/navigation";3import { type FormEvent, useState } from "react";4import { type ApiError, api, setCsrf } from "@/lib/client/api";56export default function ChangePasswordPage() {7 const router = useRouter();8 const [err, setErr] = useState<string | null>(null);9 const [busy, setBusy] = useState(false);10 async function submit(e: FormEvent<HTMLFormElement>) {11 e.preventDefault();12 setBusy(true);13 setErr(null);14 const fd = new FormData(e.currentTarget);15 try {16 const r = await api<{ csrfToken: string }>("/api/admin/auth/change-password", {17 json: {18 currentPassword: fd.get("currentPassword"),19 newPassword: fd.get("newPassword"),20 confirm: fd.get("confirm"),21 },22 });23 setCsrf(r.csrfToken);24 router.replace("/admin");25 router.refresh();26 } catch (e2) {27 const ae = e2 as ApiError;28 setErr(29 Array.isArray(ae.details) && typeof ae.details[0] === "string"30 ? `${ae.message}`31 : (ae.message ?? "Failed"),32 );33 } finally {34 setBusy(false);35 }36 }37 return (38 <main className="mx-auto flex min-h-dvh max-w-sm flex-col justify-center px-4">39 <p className="eyebrow">Security</p>40 <h1 className="title-2 mt-1">Set a new password</h1>41 <p className="muted mt-1 text-sm">42 The bootstrap password only works once. Choose at least 12 characters with three character classes; it43 must not be a well-known password or contain your username.44 </p>45 <form onSubmit={submit} className="mt-6 space-y-4">46 <div>47 <label htmlFor="currentPassword" className="label mb-1">48 Current password49 </label>50 <input51 id="currentPassword"52 name="currentPassword"53 type="password"54 autoComplete="current-password"55 required56 className="input"57 />58 </div>59 <div>60 <label htmlFor="newPassword" className="label mb-1">61 New password62 </label>63 <input64 id="newPassword"65 name="newPassword"66 type="password"67 autoComplete="new-password"68 minLength={12}69 required70 className="input"71 />72 </div>73 <div>74 <label htmlFor="confirm" className="label mb-1">75 Confirm new password76 </label>77 <input78 id="confirm"79 name="confirm"80 type="password"81 autoComplete="new-password"82 minLength={12}83 required84 className="input"85 />86 </div>87 {err && (88 <p role="alert" className="text-sm" style={{ color: "var(--color-danger-500)" }}>89 {err}90 </p>91 )}92 <button type="submit" className="btn btn-primary w-full" disabled={busy}>93 {busy ? "Saving…" : "Change password"}94 </button>95 </form>96 </main>97 );98}99