more password change fixes

This commit is contained in:
makearmy 2025-09-30 22:51:12 -04:00
parent d090ff44f2
commit c3fe52589f
2 changed files with 119 additions and 48 deletions

View file

@ -1,15 +1,44 @@
// components/account/PasswordChange.tsx
"use client";
import { useState } from "react";
import { useEffect, useState } from "react";
type Me = {
id: string;
username?: string | null;
email?: string | null;
};
export default function PasswordChange() {
const [current, setCurrent] = useState("");
const [next, setNext] = useState("");
const [next2, setNext2] = useState("");
const [identifier, setIdentifier] = useState(""); // email OR username (sent to API)
const [needIdentifier, setNeedIdentifier] = useState(false);
const [busy, setBusy] = useState(false);
const [msg, setMsg] = useState<string | null>(null);
// Try to auto-fill identifier from /api/account
useEffect(() => {
(async () => {
try {
const r = await fetch("/api/account", { credentials: "include", cache: "no-store" });
const j = await r.json().catch(() => ({}));
const me: Me | undefined = j?.user ?? j?.data ?? undefined;
const id = (me?.email || me?.username || "").trim();
if (id) {
setIdentifier(id);
setNeedIdentifier(false);
} else {
setNeedIdentifier(true);
}
} catch {
// If it fails, we'll let the user type it
setNeedIdentifier(true);
}
})();
}, []);
const onSave = async () => {
setMsg(null);
if (next !== next2) {
@ -20,26 +49,23 @@ export default function PasswordChange() {
setMsg("Password must be at least 8 characters.");
return;
}
if (!identifier.trim()) {
setNeedIdentifier(true);
setMsg("Please enter your email or username.");
return;
}
setBusy(true);
try {
const r = await fetch("/api/account/password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ current, next }),
body: JSON.stringify({ current, next, identifier: identifier.trim() }),
});
// ⬇️ Parse JSON **then** use debug if present
const j = await r.json().catch(() => ({} as any));
if (!r.ok) {
// ⬇️ This is the "debug block" so you can see the upstream reason
setMsg(
j?.error
? j?.debug
? `${j.error} (${j.debug})`
: j.error
: "Password change failed"
);
setMsg(j?.error ? (j?.debug ? `${j.error} (${j.debug})` : j.error) : "Password change failed");
return;
}
@ -59,6 +85,20 @@ export default function PasswordChange() {
<h3 className="font-semibold">Change Password</h3>
<div className="grid sm:grid-cols-2 gap-3 text-sm">
{needIdentifier && (
<label className="grid gap-1 sm:col-span-2">
<span className="opacity-60">Email or Username</span>
<input
className="rounded-md border px-2 py-1"
type="text"
value={identifier}
onChange={(e) => setIdentifier(e.target.value)}
placeholder="you@example.com or your-handle"
autoComplete="username"
/>
</label>
)}
<label className="grid gap-1 sm:col-span-2">
<span className="opacity-60">Current Password</span>
<input
@ -66,6 +106,7 @@ export default function PasswordChange() {
type="password"
value={current}
onChange={(e) => setCurrent(e.target.value)}
autoComplete="current-password"
/>
</label>
@ -76,6 +117,7 @@ export default function PasswordChange() {
type="password"
value={next}
onChange={(e) => setNext(e.target.value)}
autoComplete="new-password"
/>
</label>
@ -86,6 +128,7 @@ export default function PasswordChange() {
type="password"
value={next2}
onChange={(e) => setNext2(e.target.value)}
autoComplete="new-password"
/>
</label>
</div>