frontend: working profile settings with sticky save + real account deletion

- ToggleRow supports controlled checked/onCheckedChange; CopyField copy works
- ProfilePanel loads/saves preferences via /api/settings, name via updateUser
- dirty tracking with a sticky save bar that follows the scroll
- Delete account: password-confirmed dialog wired to authClient.deleteUser
- clinician ID / handle now show the real session user

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-10 20:09:41 +03:00
parent 50fbb6cd40
commit 470230591c
5 changed files with 330 additions and 22 deletions
@@ -695,6 +695,7 @@
},
"empty": "Nothing here yet.",
"copy": "Copy",
"copied": "Copied",
"records": {
"description": "How patient records are sourced, stored, and displayed"
},
@@ -729,6 +730,23 @@
"deleteAccount": "Delete account",
"deleteAccountDescription": "Permanently delete your temetro account and any locally stored signing keys. This action cannot be undone.",
"delete": "Delete",
"unsavedChanges": "You have unsaved changes",
"saveChanges": "Save changes",
"saving": "Saving…",
"savedTitle": "Settings saved",
"savedBody": "Your preferences are up to date.",
"saveFailedTitle": "Couldn't save settings",
"saveFailedBody": "Please try again.",
"deleteDialog": {
"title": "Delete your account?",
"description": "This permanently deletes your account, removes you from your clinics, and cannot be undone.",
"passwordLabel": "Confirm your password",
"passwordPlaceholder": "Your password",
"cancel": "Cancel",
"confirm": "Delete account",
"deleting": "Deleting…",
"failed": "Couldn't delete the account. Check your password and try again."
},
"notif": {
"newLab": "New lab result",
"newLabDesc": "Sent when a new lab result is available on a patient's chart",
+24
View File
@@ -0,0 +1,24 @@
import { apiFetch } from "@/lib/api-client";
// Per-user preferences persisted by the backend (`user_settings` table) as a
// flat key → boolean/string map. Unknown keys are preserved, so features can
// add settings without coordinating with this file.
export type UserPreferences = Record<string, boolean | string>;
export async function getSettings(): Promise<UserPreferences> {
const res = await apiFetch<{ preferences: UserPreferences }>("/api/settings");
return res.preferences ?? {};
}
export async function saveSettings(
preferences: UserPreferences,
): Promise<UserPreferences> {
const res = await apiFetch<{ preferences: UserPreferences }>(
"/api/settings",
{
method: "PUT",
body: JSON.stringify({ preferences }),
},
);
return res.preferences ?? {};
}