From 1de4cbcaa9fcd75418e7d76c6573ed0408d92e4e Mon Sep 17 00:00:00 2001 From: Aleksandr Soloshenko Date: Tue, 21 Jul 2026 07:50:47 +0700 Subject: [PATCH 1/2] [frontend] Move password change from profile to security settings --- frontend/src/lib/pages/profile.svelte | 170 +++++------------- .../src/lib/pages/settings/security.svelte | 82 +++++++++ 2 files changed, 125 insertions(+), 127 deletions(-) diff --git a/frontend/src/lib/pages/profile.svelte b/frontend/src/lib/pages/profile.svelte index 298f983..170b517 100644 --- a/frontend/src/lib/pages/profile.svelte +++ b/frontend/src/lib/pages/profile.svelte @@ -1,26 +1,11 @@
@@ -67,102 +35,50 @@
-
- - - Account Info - Your account details - - - {#if user} -
-
-
ID
-
{user.id}
-
-
-
Name
-
{user.name}
-
-
-
Email
-
{user.email}
-
-
-
Role
-
- - {user.role} - -
-
-
-
Status
-
- - {user.status} - -
-
-
-
Member since
-
{formatDate(user.created_at)}
-
-
- {:else} -

Not available

- {/if} -
-
- - - - Change Password - Update your account password - - -
{ e.preventDefault(); handleSubmit(); }} class="flex flex-col gap-4"> -
- - + + + Account Info + Your account details + + + {#if user} +
+
+
ID
+
{user.id}
-
- - - {#if newPassword && !passwordValid} -

Password must be at least 8 characters

- {/if} +
+
Name
+
{user.name}
-
- - - {#if confirmPassword && !passwordsMatch} -

Passwords do not match

- {/if} +
+
Email
+
{user.email}
- - - - -
+
+
Role
+
+ + {user.role} + +
+
+
+
Status
+
+ + {user.status} + +
+
+
+
Member since
+
{formatDate(user.created_at)}
+
+
+ {:else} +

Not available

+ {/if} +
+
diff --git a/frontend/src/lib/pages/settings/security.svelte b/frontend/src/lib/pages/settings/security.svelte index 3cd6e7e..52d9506 100644 --- a/frontend/src/lib/pages/settings/security.svelte +++ b/frontend/src/lib/pages/settings/security.svelte @@ -2,6 +2,7 @@ import { Button } from "$lib/components/ui/button"; import * as Card from "$lib/components/ui/card"; import { Input } from "$lib/components/ui/input"; + import { Label } from "$lib/components/ui/label"; import { passkeyRegisterBegin, passkeyRegisterComplete, @@ -9,6 +10,7 @@ renamePasskey, deletePasskey, } from "$lib/api/passkey"; + import { changePasswordApi } from "$lib/api/auth"; import { toast } from "$lib/toast"; import type { PasskeyCredential } from "$lib/types/api"; import KeyIcon from "@lucide/svelte/icons/key"; @@ -25,6 +27,16 @@ let editName = $state(""); let passkeySupported = $state(false); + let oldPassword = $state(""); + let newPassword = $state(""); + let confirmPassword = $state(""); + let saving = $state(false); + let error = $state(""); + + let passwordsMatch = $derived(newPassword === confirmPassword); + let passwordValid = $derived(newPassword.length >= 8); + let canSubmit = $derived(!!oldPassword && !!newPassword && !!confirmPassword && passwordValid && passwordsMatch); + $effect(() => { passkeySupported = typeof navigator !== "undefined" && @@ -105,6 +117,24 @@ function formatDate(dateStr: string): string { return new Date(dateStr).toLocaleDateString(); } + + async function handleSubmit() { + if (!canSubmit || saving) return; + saving = true; + error = ""; + try { + await changePasswordApi({ old_password: oldPassword, new_password: newPassword }); + toast.success("Password changed successfully"); + oldPassword = ""; + newPassword = ""; + confirmPassword = ""; + } catch (e: any) { + error = e?.message || "Failed to change password"; + toast.error(error); + } finally { + saving = false; + } + }
@@ -123,6 +153,57 @@ {/if}
+
+ + + Change Password + Update your account password + + +
{ e.preventDefault(); handleSubmit(); }} class="flex flex-col gap-4"> +
+ + +
+
+ + + {#if newPassword && !passwordValid} +

Password must be at least 8 characters

+ {/if} +
+
+ + + {#if confirmPassword && !passwordsMatch} +

Passwords do not match

+ {/if} +
+ +
+
+
+ Passkeys @@ -213,4 +294,5 @@ {/if} +
From 041e0c440e15c27cdcfb29952d27bc69824c2a3c Mon Sep 17 00:00:00 2001 From: Aleksandr Soloshenko Date: Fri, 24 Jul 2026 06:40:38 +0700 Subject: [PATCH 2/2] [frontend] improve autocomplete --- .../src/lib/pages/settings/security.svelte | 300 ++++++++++-------- 1 file changed, 160 insertions(+), 140 deletions(-) diff --git a/frontend/src/lib/pages/settings/security.svelte b/frontend/src/lib/pages/settings/security.svelte index 52d9506..0d1f7eb 100644 --- a/frontend/src/lib/pages/settings/security.svelte +++ b/frontend/src/lib/pages/settings/security.svelte @@ -35,7 +35,13 @@ let passwordsMatch = $derived(newPassword === confirmPassword); let passwordValid = $derived(newPassword.length >= 8); - let canSubmit = $derived(!!oldPassword && !!newPassword && !!confirmPassword && passwordValid && passwordsMatch); + let canSubmit = $derived( + !!oldPassword && + !!newPassword && + !!confirmPassword && + passwordValid && + passwordsMatch, + ); $effect(() => { passkeySupported = @@ -123,7 +129,10 @@ saving = true; error = ""; try { - await changePasswordApi({ old_password: oldPassword, new_password: newPassword }); + await changePasswordApi({ + old_password: oldPassword, + new_password: newPassword, + }); toast.success("Password changed successfully"); oldPassword = ""; newPassword = ""; @@ -154,145 +163,156 @@
- - - Change Password - Update your account password - - -
{ e.preventDefault(); handleSubmit(); }} class="flex flex-col gap-4"> -
- - -
-
- - - {#if newPassword && !passwordValid} -

Password must be at least 8 characters

- {/if} -
-
- - - {#if confirmPassword && !passwordsMatch} -

Passwords do not match

- {/if} -
- -
-
-
+ + + Change Password + Update your account password + + +
{ + e.preventDefault(); + handleSubmit(); + }} + class="flex flex-col gap-4" + > +
+ + +
+
+ + + {#if newPassword && !passwordValid} +

+ Password must be at least 8 characters +

+ {/if} +
+
+ + + {#if confirmPassword && !passwordsMatch} +

Passwords do not match

+ {/if} +
+ +
+
+
- - - Passkeys - - Passkeys let you sign in without a password using biometrics, PIN, or - security keys. - - - - {#if loading} -

Loading...

- {:else if credentials.length === 0} -
- -

- {passkeySupported - ? "No passkeys registered yet." - : "Passkeys are not supported in this browser."} -

-
- {:else} -
    - {#each credentials as cred (cred.id)} -
  • - {#if editingId === cred.id} -
    - { - if (e.key === "Enter") saveEdit(cred); - if (e.key === "Escape") cancelEdit(); - }} - /> - - -
    - {:else} -
    - -
    -

    {cred.name}

    -

    - Registered {formatDate(cred.created_at)} -

    + + + Passkeys + + Passkeys let you sign in without a password using biometrics, PIN, or + security keys. + + + + {#if loading} +

    Loading...

    + {:else if credentials.length === 0} +
    + +

    + {passkeySupported + ? "No passkeys registered yet." + : "Passkeys are not supported in this browser."} +

    +
    + {:else} +
      + {#each credentials as cred (cred.id)} +
    • + {#if editingId === cred.id} +
      + { + if (e.key === "Enter") saveEdit(cred); + if (e.key === "Escape") cancelEdit(); + }} + /> + + +
      + {:else} +
      + +
      +

      {cred.name}

      +

      + Registered {formatDate(cred.created_at)} +

      +
      +
      +
      + +
      -
    -
    - - -
    - {/if} -
  • - {/each} -
- {/if} -
-
+ {/if} + + {/each} + + {/if} + +