Compare commits
No commits in common. "d7ff30dca0da6e1ea88d05060752e89e3fc9032e" and "168409d3c05bdaddb5a06f34fb50e482fa446d7d" have entirely different histories.
d7ff30dca0
...
168409d3c0
@ -9,15 +9,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-full sm:px-6 px-3 py-4 max-w-xl mx-auto mb-12">
|
<div class="w-full sm:px-6 px-3 py-4 max-w-xl mx-auto mb-12">
|
||||||
<form
|
<form method="POST" action="?/update" use:enhance>
|
||||||
method="POST"
|
|
||||||
action="?/update"
|
|
||||||
use:enhance={() => {
|
|
||||||
return async ({ update }) => {
|
|
||||||
update({ reset: false });
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{@render children()}
|
{@render children()}
|
||||||
|
|
||||||
<div class="flex gap-2 justify-between sm:text-base text-sm">
|
<div class="flex gap-2 justify-between sm:text-base text-sm">
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
import IconDeviceDesktopPin from '~icons/tabler/device-desktop-pin';
|
import IconDeviceDesktopPin from '~icons/tabler/device-desktop-pin';
|
||||||
import IconHome from '~icons/tabler/home';
|
import IconHome from '~icons/tabler/home';
|
||||||
import IconLogout from '~icons/tabler/logout';
|
import IconLogout from '~icons/tabler/logout';
|
||||||
import IconUserCircle from '~icons/tabler/user-circle';
|
|
||||||
import IconUsers from '~icons/tabler/users';
|
import IconUsers from '~icons/tabler/users';
|
||||||
import IconUsersGroup from '~icons/tabler/users-group';
|
import IconUsersGroup from '~icons/tabler/users-group';
|
||||||
|
|
||||||
@ -85,7 +84,6 @@
|
|||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{@render DropDownLink(IconUserCircle, 'Account', '/dash/account')}
|
|
||||||
{@render DropDownLink(IconDeviceDesktopPin, 'Sessions', '/dash/account/sessions')}
|
{@render DropDownLink(IconDeviceDesktopPin, 'Sessions', '/dash/account/sessions')}
|
||||||
{@render DropDownLink(IconLogout, 'Sign out', '/logout', false)}
|
{@render DropDownLink(IconLogout, 'Sign out', '/logout', false)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
import { FORBIDDEN, PARSE_ERROR, SUCCESS } from '$lib/server/commonResponses';
|
|
||||||
import { users } from '$lib/server/db';
|
|
||||||
import type { Updated } from '$lib/server/db/types';
|
|
||||||
import { toPublicUser, type User } from '$lib/server/db/types/user.js';
|
|
||||||
import { type Actions, type ServerLoad } from '@sveltejs/kit';
|
|
||||||
import bcrypt from 'bcryptjs';
|
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
export const load: ServerLoad = async ({ locals: { guard }, params }) => {
|
|
||||||
const user = guard.requiresAuth().orRedirects().getUser();
|
|
||||||
|
|
||||||
return {
|
|
||||||
user: toPublicUser(user),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const actions = {
|
|
||||||
update: async ({ request, locals: { guard } }) => {
|
|
||||||
const auth = guard.requiresAuth();
|
|
||||||
if (auth.isFailed()) return FORBIDDEN;
|
|
||||||
|
|
||||||
const user = guard.getUser();
|
|
||||||
|
|
||||||
const schema = z.object({
|
|
||||||
name: z
|
|
||||||
.string({ message: 'Name is required.' })
|
|
||||||
.min(3, { message: 'Name must be at least 3 characters.' })
|
|
||||||
.max(24, { message: 'Name must be at most 24 characters.' }),
|
|
||||||
password: z.string().refine((v) => (v.length > 0 ? v.length >= 8 : true), {
|
|
||||||
message: 'Password must be at least 8 characters.',
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const parsed = schema.safeParse(Object.fromEntries(await request.formData()));
|
|
||||||
if (!parsed.success) return PARSE_ERROR(parsed.error);
|
|
||||||
|
|
||||||
let updatedUser: Updated<User> = { id: user.id, ...parsed.data };
|
|
||||||
|
|
||||||
if (parsed.data.password.length > 0) {
|
|
||||||
updatedUser.password = bcrypt.hashSync(parsed.data.password, 10);
|
|
||||||
} else {
|
|
||||||
// avoid saving empty passwpord
|
|
||||||
delete updatedUser.password;
|
|
||||||
}
|
|
||||||
|
|
||||||
const err = await users.update(updatedUser);
|
|
||||||
return err ? err.toFail() : SUCCESS;
|
|
||||||
},
|
|
||||||
} satisfies Actions;
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import InputText from '$lib/v2/forms/InputText.svelte';
|
|
||||||
import { pageTitle } from '$lib/v2/globalStores';
|
|
||||||
import EditPage from '$lib/v2/snippets/EditPage.svelte';
|
|
||||||
|
|
||||||
let { data, form } = $props();
|
|
||||||
|
|
||||||
$pageTitle = 'Account details';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<p class="text-white">{form?.error}</p>
|
|
||||||
<EditPage createOnly>
|
|
||||||
<InputText
|
|
||||||
name="name"
|
|
||||||
label="Name"
|
|
||||||
description="Name you will use to sign in to the dashboard"
|
|
||||||
value={data.user.name}
|
|
||||||
class="w-full"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<InputText
|
|
||||||
name="password"
|
|
||||||
label="Password"
|
|
||||||
description="Leave blank to keep your current password"
|
|
||||||
type="password"
|
|
||||||
class="w-full"
|
|
||||||
/>
|
|
||||||
</EditPage>
|
|
||||||
Loading…
x
Reference in New Issue
Block a user