All checks were successful
PostgreSQL Compatibility Matrix / PG14 smoke (push) Successful in 9s
PostgreSQL Compatibility Matrix / PG15 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG16 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG17 smoke (push) Successful in 7s
PostgreSQL Compatibility Matrix / PG18 smoke (push) Successful in 7s
Introduced a backend API endpoint for changing user passwords with validation. Added a new "User Settings" page in the frontend to allow users to update their passwords, including a matching UI update for navigation and styles.
101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
import React, { useState } from "react";
|
|
import { apiFetch } from "../api";
|
|
import { useAuth } from "../state";
|
|
|
|
export function UserSettingsPage() {
|
|
const { tokens, refresh } = useAuth();
|
|
const [form, setForm] = useState({
|
|
current_password: "",
|
|
new_password: "",
|
|
confirm_password: "",
|
|
});
|
|
const [message, setMessage] = useState("");
|
|
const [error, setError] = useState("");
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const submit = async (e) => {
|
|
e.preventDefault();
|
|
setMessage("");
|
|
setError("");
|
|
if (form.new_password.length < 8) {
|
|
setError("New password must be at least 8 characters.");
|
|
return;
|
|
}
|
|
if (form.new_password !== form.confirm_password) {
|
|
setError("Password confirmation does not match.");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setBusy(true);
|
|
await apiFetch(
|
|
"/me/password",
|
|
{
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
current_password: form.current_password,
|
|
new_password: form.new_password,
|
|
}),
|
|
},
|
|
tokens,
|
|
refresh
|
|
);
|
|
setForm({ current_password: "", new_password: "", confirm_password: "" });
|
|
setMessage("Password changed successfully.");
|
|
} catch (e) {
|
|
setError(String(e.message || e));
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="user-settings-page">
|
|
<h2>User Settings</h2>
|
|
<p className="muted">Manage your personal account security settings.</p>
|
|
{error && <div className="card error">{error}</div>}
|
|
{message && <div className="test-connection-result ok">{message}</div>}
|
|
|
|
<div className="card user-settings-card">
|
|
<h3>Change Password</h3>
|
|
<form className="grid two" onSubmit={submit}>
|
|
<div className="admin-field field-full">
|
|
<label>Current password</label>
|
|
<input
|
|
type="password"
|
|
value={form.current_password}
|
|
onChange={(e) => setForm({ ...form, current_password: e.target.value })}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="admin-field">
|
|
<label>New password</label>
|
|
<input
|
|
type="password"
|
|
value={form.new_password}
|
|
onChange={(e) => setForm({ ...form, new_password: e.target.value })}
|
|
minLength={8}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="admin-field">
|
|
<label>Confirm new password</label>
|
|
<input
|
|
type="password"
|
|
value={form.confirm_password}
|
|
onChange={(e) => setForm({ ...form, confirm_password: e.target.value })}
|
|
minLength={8}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="form-actions field-full">
|
|
<button className="primary-btn" type="submit" disabled={busy}>
|
|
{busy ? "Saving..." : "Update Password"}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|