From 0e050a89bccb2f7f11abb2b9ba51fdfbde4de884 Mon Sep 17 00:00:00 2001 From: CodeMaster4711 Date: Sun, 9 Aug 2026 12:59:58 +0200 Subject: [PATCH] feat: unify user and admin settings into single dialog --- app/src/lib/auth/api.ts | 50 ++++ .../settings/account-settings.svelte | 227 ++++++++++++++++++ .../settings/general-settings.svelte | 1 + .../settings/settings-dialog.svelte | 55 +++++ .../settings/settings-store.svelte.ts | 16 ++ .../settings/update-settings.svelte | 22 +- .../lib/components/sidebar/nav-user.svelte | 3 +- .../ui/dialog/dialog-content.svelte | 48 ++++ .../ui/dialog/dialog-description.svelte | 17 ++ .../ui/dialog/dialog-overlay.svelte | 20 ++ .../components/ui/dialog/dialog-portal.svelte | 7 + .../components/ui/dialog/dialog-title.svelte | 17 ++ .../ui/dialog/dialog-trigger.svelte | 7 + .../lib/components/ui/dialog/dialog.svelte | 7 + app/src/lib/components/ui/dialog/index.ts | 25 ++ app/src/lib/components/ui/switch/index.ts | 3 + .../lib/components/ui/switch/switch.svelte | 27 +++ app/src/routes/(app)/+layout.svelte | 2 + .../routes/(app)/admin/settings/+page.svelte | 61 +---- 19 files changed, 551 insertions(+), 64 deletions(-) create mode 100644 app/src/lib/components/settings/account-settings.svelte create mode 100644 app/src/lib/components/settings/general-settings.svelte create mode 100644 app/src/lib/components/settings/settings-dialog.svelte create mode 100644 app/src/lib/components/settings/settings-store.svelte.ts create mode 100644 app/src/lib/components/ui/dialog/dialog-content.svelte create mode 100644 app/src/lib/components/ui/dialog/dialog-description.svelte create mode 100644 app/src/lib/components/ui/dialog/dialog-overlay.svelte create mode 100644 app/src/lib/components/ui/dialog/dialog-portal.svelte create mode 100644 app/src/lib/components/ui/dialog/dialog-title.svelte create mode 100644 app/src/lib/components/ui/dialog/dialog-trigger.svelte create mode 100644 app/src/lib/components/ui/dialog/dialog.svelte create mode 100644 app/src/lib/components/ui/dialog/index.ts create mode 100644 app/src/lib/components/ui/switch/index.ts create mode 100644 app/src/lib/components/ui/switch/switch.svelte diff --git a/app/src/lib/auth/api.ts b/app/src/lib/auth/api.ts index 6554eb23..ccfaebd5 100644 --- a/app/src/lib/auth/api.ts +++ b/app/src/lib/auth/api.ts @@ -151,6 +151,56 @@ export async function validateSession(token: string): Promise { return res.json(); } +export async function changeEmail(token: string, newEmail: string): Promise { + const res = await fetch(`${API_BASE}/change-email`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ new_email: newEmail }), + }); + if (!res.ok) throw new Error(`change-email failed: ${res.status}`); +} + +export interface Setup2FAResponse { + secret: string; + qr_code: string; +} + +export async function setup2FA(token: string): Promise { + const res = await fetch(`${API_BASE}/2fa/setup`, { + method: 'POST', + headers: { Authorization: `Bearer ${token}` }, + }); + if (!res.ok) throw new Error(`2fa setup failed: ${res.status}`); + return res.json(); +} + +export async function enable2FA(token: string, code: string): Promise { + const res = await fetch(`${API_BASE}/2fa/enable`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ code }), + }); + if (!res.ok) throw new Error(`2fa enable failed: ${res.status}`); +} + +export async function disable2FA(token: string, code: string): Promise { + const res = await fetch(`${API_BASE}/2fa/disable`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ code }), + }); + if (!res.ok) throw new Error(`2fa disable failed: ${res.status}`); +} + export class TwoFactorRequiredError extends Error { constructor( public readonly username: string, diff --git a/app/src/lib/components/settings/account-settings.svelte b/app/src/lib/components/settings/account-settings.svelte new file mode 100644 index 00000000..affb2e4d --- /dev/null +++ b/app/src/lib/components/settings/account-settings.svelte @@ -0,0 +1,227 @@ + + +
+
+

Profile

+
+ + +
+
+ +
+ + +
+
+
+ +
+

Password

+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Two-factor authentication

+

Require an authenticator code at login

+
+ +
+ + {#if twoFactorStep === "enrolling"} +
+

Scan with your authenticator app, then enter the code

+ {#if qrCode} + 2FA QR code + {/if} + + {#snippet children({ cells })} + + {#each cells.slice(0, 3) as cell (cell)} + + {/each} + + + + {#each cells.slice(3, 6) as cell (cell)} + + {/each} + + {/snippet} + +
+ + +
+
+ {:else if twoFactorStep === "disabling"} +
+

Enter your current code to disable 2FA

+ + {#snippet children({ cells })} + + {#each cells.slice(0, 3) as cell (cell)} + + {/each} + + + + {#each cells.slice(3, 6) as cell (cell)} + + {/each} + + {/snippet} + +
+ + +
+
+ {/if} +
+
diff --git a/app/src/lib/components/settings/general-settings.svelte b/app/src/lib/components/settings/general-settings.svelte new file mode 100644 index 00000000..bbe69da5 --- /dev/null +++ b/app/src/lib/components/settings/general-settings.svelte @@ -0,0 +1 @@ +

No general settings configured.

diff --git a/app/src/lib/components/settings/settings-dialog.svelte b/app/src/lib/components/settings/settings-dialog.svelte new file mode 100644 index 00000000..a39c9f9b --- /dev/null +++ b/app/src/lib/components/settings/settings-dialog.svelte @@ -0,0 +1,55 @@ + + + settingsDialog.set(value)}> + +
+ +
+ {#if activeSection === "account"} + + {:else if activeSection === "general"} + + {:else if activeSection === "update"} + + {:else if activeSection === "logs"} + + {/if} +
+
+
+
diff --git a/app/src/lib/components/settings/settings-store.svelte.ts b/app/src/lib/components/settings/settings-store.svelte.ts new file mode 100644 index 00000000..807f8169 --- /dev/null +++ b/app/src/lib/components/settings/settings-store.svelte.ts @@ -0,0 +1,16 @@ +let open = $state(false); + +export const settingsDialog = { + get open() { + return open; + }, + show() { + open = true; + }, + hide() { + open = false; + }, + set(value: boolean) { + open = value; + }, +}; diff --git a/app/src/lib/components/settings/update-settings.svelte b/app/src/lib/components/settings/update-settings.svelte index c4df2faf..2301a0e5 100644 --- a/app/src/lib/components/settings/update-settings.svelte +++ b/app/src/lib/components/settings/update-settings.svelte @@ -2,6 +2,7 @@ import { onMount, onDestroy } from "svelte"; import * as Card from "$lib/components/ui/card/index.js"; import { Button } from "$lib/components/ui/button/index.js"; + import { Switch } from "$lib/components/ui/switch/index.js"; import { auth } from "$lib/auth/store.svelte"; import { getUpdateStatus, @@ -216,18 +217,15 @@ Available releases Select a version to update or downgrade -