diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 37ead8d..29461b0 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -51,6 +51,11 @@ href: '/gallery', label: 'Gallery', icon: 'M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z' + }, + { + href: '/settings', + label: 'Settings', + icon: 'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z M15 12a3 3 0 11-6 0 3 3 0 016 0z' } ]); diff --git a/src/routes/(app)/settings/+page.server.ts b/src/routes/(app)/settings/+page.server.ts new file mode 100644 index 0000000..775cbb3 --- /dev/null +++ b/src/routes/(app)/settings/+page.server.ts @@ -0,0 +1,51 @@ +import type { PageServerLoad, Actions } from './$types'; +import { db } from '$lib/server/db/index.js'; +import { users } from '$lib/server/db/schema.js'; +import { eq } from 'drizzle-orm'; +import { fail } from '@sveltejs/kit'; +import { verifyPassword, hashPassword } from '$lib/server/auth/password.js'; + +export const load: PageServerLoad = async ({ locals }) => { + return { user: locals.user! }; +}; + +export const actions: Actions = { + changePassword: async ({ request, locals }) => { + const formData = await request.formData(); + const currentPassword = formData.get('currentPassword') as string; + const newPassword = formData.get('newPassword') as string; + const confirmPassword = formData.get('confirmPassword') as string; + + if (!currentPassword || !newPassword || !confirmPassword) { + return fail(400, { error: 'All fields are required' }); + } + + if (newPassword.length < 8) { + return fail(400, { error: 'New password must be at least 8 characters' }); + } + + if (newPassword !== confirmPassword) { + return fail(400, { error: 'New passwords do not match' }); + } + + const [user] = await db + .select({ passwordHash: users.passwordHash }) + .from(users) + .where(eq(users.id, locals.user!.id)); + + if (!user) return fail(400, { error: 'User not found' }); + + const valid = await verifyPassword(user.passwordHash, currentPassword); + if (!valid) { + return fail(400, { error: 'Current password is incorrect' }); + } + + const newHash = await hashPassword(newPassword); + await db + .update(users) + .set({ passwordHash: newHash, updatedAt: new Date() }) + .where(eq(users.id, locals.user!.id)); + + return { success: true }; + } +}; diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte new file mode 100644 index 0000000..65e888a --- /dev/null +++ b/src/routes/(app)/settings/+page.svelte @@ -0,0 +1,68 @@ + + + + Settings - B4L Repair + + +
+

Settings

+ + +
+

Account

+
+
+
Email
+
{data.user.email}
+
+ {#if data.user.displayName} +
+
Display Name
+
{data.user.displayName}
+
+ {/if} +
+
+ + +
+

Change Password

+ + {#if form?.error} +
+ {form.error} +
+ {/if} + + {#if form?.success} +
+ Password changed successfully. +
+ {/if} + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+