From a50f2c12a848b51bfb997adda1b893a1c7e74d69 Mon Sep 17 00:00:00 2001
From: Bart van der Braak <bartvdbraak@gmail.com>
Date: Wed, 21 Feb 2024 02:09:02 +0100
Subject: [PATCH] feat: working of some

---
 src/routes/(user)/settings/+layout.svelte     |   2 +-
 .../(user)/settings/account/+page.server.ts   |  55 +++++-
 .../(user)/settings/account/+page.svelte      |  10 +-
 .../settings/account/account-form.svelte      | 180 ------------------
 .../(user)/settings/account/email-form.svelte | 134 +++++++++++++
 .../settings/account/password-form.svelte     |  92 +++++++++
 .../settings/account/username-form.svelte     |  76 ++++++++
 .../appearance/appearance-form.svelte         | 157 ++++++++-------
 .../(user)/settings/profile-form.svelte       |  10 +-
 9 files changed, 459 insertions(+), 257 deletions(-)
 delete mode 100644 src/routes/(user)/settings/account/account-form.svelte
 create mode 100644 src/routes/(user)/settings/account/email-form.svelte
 create mode 100644 src/routes/(user)/settings/account/password-form.svelte
 create mode 100644 src/routes/(user)/settings/account/username-form.svelte

diff --git a/src/routes/(user)/settings/+layout.svelte b/src/routes/(user)/settings/+layout.svelte
index 10bc0b3..e3b27fb 100644
--- a/src/routes/(user)/settings/+layout.svelte
+++ b/src/routes/(user)/settings/+layout.svelte
@@ -22,7 +22,7 @@
 	];
 </script>
 
-<div class="hidden space-y-6 p-10 pb-16 md:block">
+<div class="space-y-6 p-10 pb-16">
 	<div class="space-y-0.5">
 		<h2 class="text-2xl font-bold tracking-tight">Settings</h2>
 		<p class="text-muted-foreground">
diff --git a/src/routes/(user)/settings/account/+page.server.ts b/src/routes/(user)/settings/account/+page.server.ts
index 1eaf695..23277d5 100644
--- a/src/routes/(user)/settings/account/+page.server.ts
+++ b/src/routes/(user)/settings/account/+page.server.ts
@@ -1,24 +1,67 @@
+import type { PageServerLoad } from "./$types";
 import { superValidate } from "sveltekit-superforms";
 import { zod } from "sveltekit-superforms/adapters";
-import type { PageServerLoad } from "./$types";
-import { accountFormSchema } from "./account-form.svelte";
+import { usernameFormSchema } from "./username-form.svelte";
+import { emailRequestFormSchema, emailConfirmFormSchema } from "./email-form.svelte";
+import { passwordFormSchema } from "./password-form.svelte";
 import { fail, type Actions } from "@sveltejs/kit";
 
 export const load: PageServerLoad = async () => {
 	return {
-		form: await superValidate(zod(accountFormSchema)),
+		usernameForm: await superValidate(zod(usernameFormSchema)),
+		emailRequestForm: await superValidate(zod(emailRequestFormSchema)),
+		emailConfirmForm: await superValidate(zod(emailConfirmFormSchema)),
+		passwordForm: await superValidate(zod(passwordFormSchema)),
 	};
 };
 
 export const actions: Actions = {
-	default: async (event) => {
-		const form = await superValidate(event, zod(accountFormSchema));
+	username: async ({ request, locals }) => {
+		const form = await superValidate(request, zod(usernameFormSchema));
 		if (!form.valid) {
-			console.log(form);
 			return fail(400, {
 				form,
 			});
 		}
+		await locals.pocketBase.collection('users').update(locals.id, form.data);
+		return {
+			form,
+		};
+	},
+	emailRequest: async ({ request, locals }) => {
+		const form = await superValidate(request, zod(emailRequestFormSchema));
+		if (!form.valid) {
+			return fail(400, {
+				form,
+			});
+		}
+		await locals.pocketBase.collection('users').requestEmailChange(form.data.newEmail);
+		return {
+			form,
+		};
+	},
+	emailConfirm: async ({ request, locals }) => {
+		const form = await superValidate(request, zod(emailConfirmFormSchema));
+		if (!form.valid) {
+			return fail(400, {
+				form,
+			});
+		}
+		await locals.pocketBase
+			.collection('users')
+			.confirmEmailChange(form.data.token, form.data.password);
+		return {
+			form,
+		};
+	},
+	password: async ({ request, locals }) => {
+		const form = await superValidate(request, zod(passwordFormSchema));
+		if (!form.valid) {
+			return fail(400, {
+				form,
+			});
+		}
+		await locals.pocketBase.collection('users').update(locals.id, form.data);
 		return {
 			form,
 		};
diff --git a/src/routes/(user)/settings/account/+page.svelte b/src/routes/(user)/settings/account/+page.svelte
index db3e9b4..6918b98 100644
--- a/src/routes/(user)/settings/account/+page.svelte
+++ b/src/routes/(user)/settings/account/+page.svelte
@@ -1,7 +1,9 @@
 <script lang="ts">
 	import { Separator } from "$lib/components/ui/separator";
-	import AccountForm from "./account-form.svelte";
 	import type { PageData } from "./$types";
+	import UsernameForm from "./username-form.svelte";
+	import EmailForm from "./email-form.svelte";
+	import PasswordForm from "./password-form.svelte";
 
 	export let data: PageData;
 </script>
@@ -10,9 +12,11 @@
 	<div>
 		<h3 class="text-lg font-medium">Account</h3>
 		<p class="text-sm text-muted-foreground">
-			Update your account settings. Set your preferred language and timezone.
+			Update your account settings.
 		</p>
 	</div>
 	<Separator />
-	<AccountForm data={data.form} />
+	<UsernameForm user={data.user} data={data.usernameForm} />
+	<EmailForm user={data.user} requestData={data.emailRequestForm} confirmData={data.emailConfirmForm} />
+	<PasswordForm user={data.user} data={data.passwordForm} />
 </div>
diff --git a/src/routes/(user)/settings/account/account-form.svelte b/src/routes/(user)/settings/account/account-form.svelte
deleted file mode 100644
index eca3eb3..0000000
--- a/src/routes/(user)/settings/account/account-form.svelte
+++ /dev/null
@@ -1,180 +0,0 @@
-<script lang="ts" context="module">
-	import { z } from "zod";
-
-	const languages = [
-		{ label: "English", value: "en" },
-		{ label: "French", value: "fr" },
-		{ label: "German", value: "de" },
-		{ label: "Spanish", value: "es" },
-		{ label: "Portuguese", value: "pt" },
-		{ label: "Russian", value: "ru" },
-		{ label: "Japanese", value: "ja" },
-		{ label: "Korean", value: "ko" },
-		{ label: "Chinese", value: "zh" },
-	] as const;
-
-	type Language = (typeof languages)[number]["value"];
-
-	export const accountFormSchema = z.object({
-		name: z
-			.string({
-				required_error: "Required.",
-			})
-			.min(2, "Name must be at least 2 characters.")
-			.max(30, "Name must not be longer than 30 characters"),
-		// Hack: https://github.com/colinhacks/zod/issues/2280
-		language: z.enum(languages.map((lang) => lang.value) as [Language, ...Language[]]),
-		dob: z
-			.string()
-			.datetime()
-			// we're setting it optional so the user can clear the date and we don't run into
-			// type issues, but we refine it to make sure it's not undefined
-			.optional()
-			.refine((date) => (date === undefined ? false : true), "Please select a valid date."),
-	});
-
-	export type AccountFormSchema = typeof accountFormSchema;
-</script>
-
-<script lang="ts">
-	import { Calendar as CalendarIcon, CaretSort, Check } from "radix-icons-svelte";
-	import SuperDebug, { type SuperValidated, type Infer, superForm } from "sveltekit-superforms";
-	import { zodClient } from "sveltekit-superforms/adapters";
-	import * as Form from "$lib/components/ui/form";
-	import * as Popover from "$lib/components/ui/popover";
-	import * as Command from "$lib/components/ui/command";
-	import { Calendar } from "$lib/components/ui/calendar";
-	import { Input } from "$lib/components/ui/input";
-	import { buttonVariants } from "$lib/components/ui/button";
-	import { cn } from "$lib/utils";
-	import { browser, dev } from "$app/environment";
-	import { PUBLIC_DEBUG_FORMS } from "$env/static/public";
-	import {
-		DateFormatter,
-		getLocalTimeZone,
-		type DateValue,
-		parseDate,
-	} from "@internationalized/date";
-
-	export let data: SuperValidated<Infer<AccountFormSchema>>;
-
-	const form = superForm(data, {
-		validators: zodClient(accountFormSchema),
-	});
-	const { form: formData, enhance, validate } = form;
-
-	const df = new DateFormatter("en-US", {
-		dateStyle: "long",
-	});
-
-	let dobValue: DateValue | undefined = $formData.dob ? parseDate($formData.dob) : undefined;
-</script>
-
-<form method="POST" class="space-y-8" use:enhance>
-	<Form.Field name="name" {form}>
-		<Form.Control let:attrs>
-			<Form.Label>Name</Form.Label>
-			<Input {...attrs} bind:value={$formData.name} />
-		</Form.Control>
-		<Form.FieldErrors />
-	</Form.Field>
-	<Form.Field {form} name="dob" class="flex flex-col">
-		<Form.Control let:attrs>
-			<Form.Label>Date of Birth</Form.Label>
-			<Popover.Root>
-				<Popover.Trigger
-					class={cn(
-						buttonVariants({ variant: "outline" }),
-						"w-[240px] justify-start text-left font-normal",
-						!dobValue && "text-muted-foreground"
-					)}
-					{...attrs}
-				>
-					<CalendarIcon class="mr-2 h-4 w-4" />
-					{dobValue ? df.format(dobValue.toDate(getLocalTimeZone())) : "Pick a date"}
-				</Popover.Trigger>
-				<Popover.Content class="w-auto p-0" align="start">
-					<Calendar
-						bind:value={dobValue}
-						isDateDisabled={(currDate) => {
-							const currDateObj = currDate.toDate(getLocalTimeZone());
-							const today = new Date();
-							today.setHours(0, 0, 0, 0);
-
-							if (currDateObj > today || currDate.year < 1900) return true;
-
-							return false;
-						}}
-						onValueChange={(value) => {
-							if (value === undefined) {
-								$formData.dob = undefined;
-								validate("dob");
-								return;
-							}
-							$formData.dob = value.toDate(getLocalTimeZone()).toISOString();
-							validate("dob");
-						}}
-					/>
-				</Popover.Content>
-				<input hidden bind:value={$formData.dob} name={attrs.name} />
-			</Popover.Root>
-		</Form.Control>
-		<Form.FieldErrors />
-	</Form.Field>
-
-	<Form.Field {form} name="language" class="flex flex-col">
-		<Popover.Root>
-			<Form.Control let:attrs>
-				<Form.Label>Language</Form.Label>
-				<Popover.Trigger
-					role="combobox"
-					class={cn(
-						buttonVariants({ variant: "outline" }),
-						"w-[200px] justify-between",
-						!$formData.language && "text-muted-foreground"
-					)}
-					{...attrs}
-				>
-					{languages.find((lang) => lang.value === $formData.language)?.label ||
-						"Select a language"}
-					<CaretSort class="ml-2 size-4 shrink-0 opacity-50" />
-				</Popover.Trigger>
-				<input hidden bind:value={$formData.language} name={attrs.name} />
-			</Form.Control>
-			<Popover.Content class="w-[200px] p-0">
-				<Command.Root>
-					<Command.Input placeholder="Search language..." />
-					<Command.Empty>No language found.</Command.Empty>
-					<Command.List>
-						{#each languages as language}
-							<Command.Item
-								{...form}
-								value={language.label}
-								onSelect={() => {
-									$formData.language = language.value;
-									validate("language");
-								}}
-							>
-								<Check
-									class={cn(
-										"mr-2 size-4",
-										language.value === $formData.language
-											? "opacity-100"
-											: "opacity-0"
-									)}
-								/>
-								{language.label}
-							</Command.Item>
-						{/each}
-					</Command.List>
-				</Command.Root>
-			</Popover.Content>
-		</Popover.Root>
-	</Form.Field>
-
-	<Form.Button>Update account</Form.Button>
-</form>
-
-{#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}
-	<SuperDebug data={$formData} />
-{/if}
diff --git a/src/routes/(user)/settings/account/email-form.svelte b/src/routes/(user)/settings/account/email-form.svelte
new file mode 100644
index 0000000..caec4d5
--- /dev/null
+++ b/src/routes/(user)/settings/account/email-form.svelte
@@ -0,0 +1,134 @@
+<script lang="ts" context="module">
+	import { z } from 'zod';
+	export const emailRequestFormSchema = z.object({
+		newEmail: z.string().email()
+	});
+	export const emailConfirmFormSchema = z.object({
+		token: z.string(),
+		password: z.string()
+	});
+	export type EmailRequestFormSchema = typeof emailRequestFormSchema;
+	export type EmailConfirmFormSchema = typeof emailConfirmFormSchema;
+</script>
+
+<script lang="ts">
+	import * as Card from '$lib/components/ui/card';
+	import * as Form from '$lib/components/ui/form';
+	import { Input } from '$lib/components/ui/input';
+	import { type SuperValidated, type Infer, superForm } from 'sveltekit-superforms';
+	import SuperDebug from 'sveltekit-superforms';
+	import { zodClient } from 'sveltekit-superforms/adapters';
+	import { browser, dev } from '$app/environment';
+	import { PUBLIC_DEBUG_FORMS } from '$env/static/public';
+	import type { LayoutData } from '../$types';
+	import { toast } from 'svelte-sonner';
+	import { Separator } from '$lib/components/ui/separator';
+	import { Icons } from '$lib/components/site';
+
+	export let user: LayoutData['user'];
+	export let requestData: SuperValidated<Infer<EmailRequestFormSchema>>;
+	export let confirmData: SuperValidated<Infer<EmailConfirmFormSchema>>;
+	let isLoading = false;
+
+	const requestForm = superForm(requestData, {
+		validators: zodClient(emailRequestFormSchema),
+		onSubmit: () => {
+			isLoading = true;
+			toast.success('Sending verification token...');
+		},
+		onUpdated: ({ form: f }) => {
+			isLoading = false;
+			if (f.valid) {
+				toast.success('Verification token has been sent.');
+			} else {
+				toast.error('Please fix the errors in the form.');
+			}
+		}
+	});
+
+	const confirmForm = superForm(confirmData, {
+		validators: zodClient(emailConfirmFormSchema),
+		onSubmit: () => {
+			isLoading = true;
+			toast.loading('Updating email...');
+		},
+		onUpdated: ({ form: f }) => {
+			isLoading = false;
+			if (f.valid) {
+				toast.success('Your email has been updated.');
+			} else {
+				toast.error('Please fix the errors in the form.');
+			}
+		}
+	});
+
+	const { form: requestFormData, enhance: requestEnhance } = requestForm;
+	const { form: confirmFormData, enhance: confirmEnhance } = confirmForm;
+</script>
+
+<Card.Root>
+	<Card.Header>
+		<Card.Title>Request an email change</Card.Title>
+		<Card.Description
+			>Receive a verification token on this email, which you can enter in the next section.</Card.Description
+		>
+	</Card.Header>
+	<Card.Content>
+		<form method="POST" action="?/emailRequest" class="space-y-8" use:requestEnhance>
+			<Form.Field form={requestForm} name="newEmail">
+				<Form.Control let:attrs>
+					<Form.Label>New email</Form.Label>
+					<div class="flex space-x-2">
+						<Input placeholder={user?.email} {...attrs} bind:value={$requestFormData.newEmail} />
+						<Form.Button variant="secondary" disabled={isLoading}>Request token</Form.Button>
+					</div>
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+		</form>
+		{#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}
+			<div class="pt-4">
+				<SuperDebug data={$requestFormData} />
+			</div>
+		{/if}
+	</Card.Content>
+
+	<Separator />
+
+	<Card.Header>
+		<Card.Title>Confirm email change</Card.Title>
+		<Card.Description
+			>Enter your verification token below to confirm the email change.</Card.Description
+		>
+	</Card.Header>
+	<Card.Content>
+		<form method="POST" action="?/emailConfirm" class="space-y-2" use:confirmEnhance>
+			<Form.Field form={confirmForm} name="token">
+				<Form.Control let:attrs>
+					<Form.Label>Token</Form.Label>
+					<Input {...attrs} bind:value={$confirmFormData.token} />
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+			<Form.Field form={confirmForm} name="password">
+				<Form.Control let:attrs>
+					<Form.Label>Password</Form.Label>
+					<Input {...attrs} bind:value={$confirmFormData.password} type="password" />
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+			<Form.Button disabled={isLoading}>
+				{#if isLoading}
+					<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
+				{/if}
+				Update password
+			</Form.Button>
+		</form>
+
+		{#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}
+			<div class="pt-4">
+				<SuperDebug data={$confirmFormData} />
+			</div>
+		{/if}
+	</Card.Content>
+</Card.Root>
diff --git a/src/routes/(user)/settings/account/password-form.svelte b/src/routes/(user)/settings/account/password-form.svelte
new file mode 100644
index 0000000..a14e412
--- /dev/null
+++ b/src/routes/(user)/settings/account/password-form.svelte
@@ -0,0 +1,92 @@
+<script lang="ts" context="module">
+	import { z } from 'zod';
+	export const passwordFormSchema = z.object({
+		oldPassword: z.string(),
+		password: z.string().min(8),
+		passwordConfirm: z.string().min(8)
+	});
+	export type PasswordFormSchema = typeof passwordFormSchema;
+</script>
+
+<script lang="ts">
+	import * as Card from '$lib/components/ui/card';
+	import * as Form from '$lib/components/ui/form';
+	import { Input } from '$lib/components/ui/input';
+	import { type SuperValidated, type Infer, superForm } from 'sveltekit-superforms';
+	import SuperDebug from 'sveltekit-superforms';
+	import { zodClient } from 'sveltekit-superforms/adapters';
+	import { browser, dev } from '$app/environment';
+	import { PUBLIC_DEBUG_FORMS } from '$env/static/public';
+	import { toast } from 'svelte-sonner';
+	import { Icons } from '$lib/components/site';
+
+	export let data: SuperValidated<Infer<PasswordFormSchema>>;
+	let isLoading = false;
+
+	const form = superForm(data, {
+		validators: zodClient(passwordFormSchema),
+		onSubmit: () => {
+			isLoading = true;
+			toast.loading('Updating password...');
+		},
+		onUpdated: ({ form: f }) => {
+			if (f.valid) {
+				toast.success('Your password has been updated.');
+			} else {
+				toast.error('Please fix the errors in the form.');
+			}
+			isLoading = false;
+		},
+		onError: (e) => {
+			toast.error(e.result.error.message);
+			isLoading = false;
+		}
+	});
+
+	const { form: formData, enhance } = form;
+</script>
+
+<Card.Root>
+	<Card.Header>
+		<Card.Title>Change your password</Card.Title>
+		<Card.Description>You can change your password here.</Card.Description>
+	</Card.Header>
+	<Card.Content>
+		<form method="POST" action="?/password" class="space-y-2" use:enhance>
+			<Form.Field {form} name="oldPassword">
+				<Form.Control let:attrs>
+					<Form.Label>Current password</Form.Label>
+					<Input {...attrs} bind:value={$formData.oldPassword} type="password" />
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+			<Form.Field {form} name="password">
+				<Form.Control let:attrs>
+					<Form.Label>New password</Form.Label>
+					<Input {...attrs} bind:value={$formData.password} type="password" />
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+			<Form.Field {form} name="passwordConfirm">
+				<Form.Control let:attrs>
+					<Form.Label>Confirm new password</Form.Label>
+					<Input {...attrs} bind:value={$formData.passwordConfirm} type="password" />
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+
+			<Form.Button disabled={isLoading}>
+				{#if isLoading}
+					<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
+				{/if}
+				Update password
+			</Form.Button>
+		</form>
+
+		{#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}
+			<div class="pt-4">
+				<SuperDebug data={$formData} />
+			</div>
+		{/if}
+	</Card.Content>
+</Card.Root>
diff --git a/src/routes/(user)/settings/account/username-form.svelte b/src/routes/(user)/settings/account/username-form.svelte
new file mode 100644
index 0000000..12ff920
--- /dev/null
+++ b/src/routes/(user)/settings/account/username-form.svelte
@@ -0,0 +1,76 @@
+<script lang="ts" context="module">
+	import { z } from 'zod';
+	export const usernameFormSchema = z.object({
+		username: z.string().min(2).max(16)
+	});
+	export type UsernameFormSchema = typeof usernameFormSchema;
+</script>
+
+<script lang="ts">
+	import * as Card from '$lib/components/ui/card';
+	import * as Form from '$lib/components/ui/form';
+	import { Input } from '$lib/components/ui/input';
+	import { type SuperValidated, type Infer, superForm } from 'sveltekit-superforms';
+	import SuperDebug from 'sveltekit-superforms';
+	import { zodClient } from 'sveltekit-superforms/adapters';
+	import { browser, dev } from '$app/environment';
+	import { PUBLIC_DEBUG_FORMS } from '$env/static/public';
+	import type { LayoutData } from '../$types';
+	import { toast } from 'svelte-sonner';
+	import { Icons } from '$lib/components/site';
+
+	export let user: LayoutData['user'];
+	export let data: SuperValidated<Infer<UsernameFormSchema>>;
+	let isLoading = false;
+
+	const form = superForm(data, {
+		validators: zodClient(usernameFormSchema),
+		onSubmit: () => {
+			isLoading = true;
+			toast.loading('Updating username...');
+		},
+		onUpdated: ({ form: f }) => {
+			isLoading = false;
+			if (f.valid) {
+				toast.success('Your username has been updated.');
+			} else {
+				toast.error('Please fix the errors in the form.');
+			}
+		}
+	});
+
+	const { form: formData, enhance } = form;
+</script>
+
+<Card.Root>
+	<Card.Header>
+		<Card.Title>Change your username</Card.Title>
+		<Card.Description>
+			You can modify the username used for logging in and as your handle.
+		</Card.Description>
+	</Card.Header>
+	<Card.Content>
+		<form method="POST" action="?/username" class="space-y-8" use:enhance>
+			<Form.Field {form} name="username">
+				<Form.Control let:attrs>
+					<Form.Label>Username</Form.Label>
+					<Input placeholder={user?.username} {...attrs} bind:value={$formData.username} />
+				</Form.Control>
+				<Form.FieldErrors />
+			</Form.Field>
+
+			<Form.Button disabled={isLoading}>
+				{#if isLoading}
+					<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
+				{/if}
+				Update password
+			</Form.Button>
+		</form>
+
+		{#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}
+			<div class="pt-4">
+				<SuperDebug data={$formData} />
+			</div>
+		{/if}
+	</Card.Content>
+</Card.Root>
diff --git a/src/routes/(user)/settings/appearance/appearance-form.svelte b/src/routes/(user)/settings/appearance/appearance-form.svelte
index a369093..43f71d8 100644
--- a/src/routes/(user)/settings/appearance/appearance-form.svelte
+++ b/src/routes/(user)/settings/appearance/appearance-form.svelte
@@ -1,93 +1,104 @@
 <script lang="ts" context="module">
-	import { z } from "zod";
+	import { z } from 'zod';
 
 	export const appearanceFormSchema = z.object({
-		theme: z.enum(["light", "dark"], {
-			required_error: "Please select a theme.",
-		}),
-		font: z.enum(["inter", "manrope", "system"], {
-			invalid_type_error: "Select a font",
-			required_error: "Please select a font.",
-		}),
+		theme: z.enum(['system', 'light', 'dark'], {
+			required_error: 'Please select a theme.'
+		})
 	});
 
 	export type AppearanceFormSchema = typeof appearanceFormSchema;
 </script>
 
 <script lang="ts">
-	import { ChevronDown } from "radix-icons-svelte";
-	import { browser, dev } from "$app/environment";
-	import { PUBLIC_DEBUG_FORMS } from "$env/static/public";
-	import SuperDebug, { type SuperValidated, type Infer, superForm } from "sveltekit-superforms";
-	import * as Form from "$lib/components/ui/form";
-	import * as RadioGroup from "$lib/components/ui/radio-group";
-	import Label from "$lib/components/ui/label/label.svelte";
-	import { zodClient } from "sveltekit-superforms/adapters";
-	import { cn } from "$lib/utils";
-	import { buttonVariants } from "$lib/components/ui/button";
+	import { browser, dev } from '$app/environment';
+	import { PUBLIC_DEBUG_FORMS } from '$env/static/public';
+	import SuperDebug, { type SuperValidated, type Infer, superForm } from 'sveltekit-superforms';
+	import * as Form from '$lib/components/ui/form';
+	import * as RadioGroup from '$lib/components/ui/radio-group';
+	import Label from '$lib/components/ui/label/label.svelte';
+	import { zodClient } from 'sveltekit-superforms/adapters';
 	export let data: SuperValidated<Infer<AppearanceFormSchema>>;
 
 	const form = superForm(data, {
-		validators: zodClient(appearanceFormSchema),
+		validators: zodClient(appearanceFormSchema)
 	});
 
 	const { form: formData, enhance } = form;
 </script>
 
 <form method="POST" use:enhance class="space-y-8">
-	<Form.Field {form} name="font">
-		<Form.Control let:attrs>
-			<Form.Label>Font</Form.Label>
-			<div class="relative w-max">
-				<select
-					{...attrs}
-					class={cn(
-						buttonVariants({ variant: "outline" }),
-						"w-[200px] appearance-none font-normal"
-					)}
-					bind:value={$formData.font}
-				>
-					<option value="inter">Inter</option>
-					<option value="manrope">Manrope</option>
-					<option value="system">System</option>
-				</select>
-				<ChevronDown class="absolute right-3 top-2.5 size-4 opacity-50" />
-			</div>
-		</Form.Control>
-		<Form.Description>Set the font you want to use in the dashboard.</Form.Description>
-		<Form.FieldErrors />
-	</Form.Field>
 	<Form.Fieldset {form} name="theme">
 		<Form.Legend>Theme</Form.Legend>
 		<Form.Description>Select the theme for the dashboard.</Form.Description>
 		<Form.FieldErrors />
 		<RadioGroup.Root
-			class="grid max-w-md grid-cols-2 gap-8 pt-2"
+			class="grid grid-cols-3 gap-8 pt-2"
 			orientation="horizontal"
 			bind:value={$formData.theme}
 		>
+			<Form.Control let:attrs>
+				<Label class="[&:has([data-state=checked])>div]:border-primary">
+					<RadioGroup.Item {...attrs} value="system" class="sr-only" />
+					<!-- <div class="container">
+						<div class="div1">
+							<div class="items-center rounded-md border-2 border-muted p-1 hover:border-accent">
+								<div class="space-y-2 rounded-sm bg-[#ecedef] p-2">
+									<div class="space-y-2 rounded-md bg-white p-2 shadow-sm">
+										<div class="h-2 w-4 rounded-lg bg-[#ecedef]" />
+										<div class="h-2 w-full rounded-lg bg-[#ecedef]" />
+									</div>
+									<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
+										<div class="h-4 w-4 rounded-full bg-[#ecedef]" />
+										<div class="h-2 w-full rounded-lg bg-[#ecedef]" />
+									</div>
+									<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
+										<div class="h-4 w-4 rounded-full bg-[#ecedef]" />
+										<div class="h-2 w-full rounded-lg bg-[#ecedef]" />
+									</div>
+								</div>
+							</div>
+						</div>
+						<div class="div2"> -->
+							<div
+								class="items-center rounded-md border-2 border-muted bg-popover p-1 hover:bg-accent hover:text-accent-foreground"
+							>
+								<div class="space-y-2 rounded-sm bg-slate-950 p-2">
+									<div class="space-y-2 rounded-md bg-slate-800 p-2 shadow-sm">
+										<div class="h-2 w-4 rounded-lg bg-slate-400" />
+										<div class="h-2 w-full rounded-lg bg-slate-400" />
+									</div>
+									<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
+										<div class="h-4 w-4 rounded-full bg-slate-400" />
+										<div class="h-2 w-full rounded-lg bg-slate-400" />
+									</div>
+									<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
+										<div class="h-4 w-4 rounded-full bg-slate-400" />
+										<div class="h-2 w-full rounded-lg bg-slate-400" />
+									</div>
+								</div>
+							</div>
+						<!-- </div>
+					</div> -->
+					<span class="block w-full p-2 text-center font-normal"> System </span>
+				</Label>
+			</Form.Control>
 			<Form.Control let:attrs>
 				<Label class="[&:has([data-state=checked])>div]:border-primary">
 					<RadioGroup.Item {...attrs} value="light" class="sr-only" />
-					<div
-						class="items-center rounded-md border-2 border-muted p-1 hover:border-accent"
-					>
+					<div class="items-center rounded-md border-2 border-muted p-1 hover:border-accent">
 						<div class="space-y-2 rounded-sm bg-[#ecedef] p-2">
 							<div class="space-y-2 rounded-md bg-white p-2 shadow-sm">
-								<div class="h-2 w-[80px] rounded-lg bg-[#ecedef]" />
-								<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
+								<div class="h-2 w-4 rounded-lg bg-[#ecedef]" />
+								<div class="h-2 w-full rounded-lg bg-[#ecedef]" />
 							</div>
-							<div
-								class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm"
-							>
+							<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
 								<div class="h-4 w-4 rounded-full bg-[#ecedef]" />
-								<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
+								<div class="h-2 w-full rounded-lg bg-[#ecedef]" />
 							</div>
-							<div
-								class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm"
-							>
+							<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
 								<div class="h-4 w-4 rounded-full bg-[#ecedef]" />
-								<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
+								<div class="h-2 w-full rounded-lg bg-[#ecedef]" />
 							</div>
 						</div>
 					</div>
@@ -102,20 +113,16 @@
 					>
 						<div class="space-y-2 rounded-sm bg-slate-950 p-2">
 							<div class="space-y-2 rounded-md bg-slate-800 p-2 shadow-sm">
-								<div class="h-2 w-[80px] rounded-lg bg-slate-400" />
-								<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
+								<div class="h-2 w-4 rounded-lg bg-slate-400" />
+								<div class="h-2 w-full rounded-lg bg-slate-400" />
 							</div>
-							<div
-								class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm"
-							>
+							<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
 								<div class="h-4 w-4 rounded-full bg-slate-400" />
-								<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
+								<div class="h-2 w-full rounded-lg bg-slate-400" />
 							</div>
-							<div
-								class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm"
-							>
+							<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
 								<div class="h-4 w-4 rounded-full bg-slate-400" />
-								<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
+								<div class="h-2 w-full rounded-lg bg-slate-400" />
 							</div>
 						</div>
 					</div>
@@ -131,3 +138,23 @@
 {#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}
 	<SuperDebug data={$formData} />
 {/if}
+
+<style>
+	.container {
+		position: relative;
+		width: 100%;
+		height: 100%;
+	}
+
+	.div1,
+	.div2 {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+	}
+
+	.div2 {
+		clip-path: polygon(0 0, 100% 0, 0 100%);
+	}
+</style>
diff --git a/src/routes/(user)/settings/profile-form.svelte b/src/routes/(user)/settings/profile-form.svelte
index 1af763d..f77fd3e 100644
--- a/src/routes/(user)/settings/profile-form.svelte
+++ b/src/routes/(user)/settings/profile-form.svelte
@@ -17,6 +17,7 @@
 	import { PUBLIC_DEBUG_FORMS } from '$env/static/public';
 	import type { LayoutData } from '../$types';
 	import { toast } from 'svelte-sonner';
+	import { Icons } from '$lib/components/site';
 
 	export let user: LayoutData['user'];
 	export let data: SuperValidated<Infer<ProfileFormSchema>>;
@@ -26,7 +27,7 @@
 		validators: zodClient(profileFormSchema),
 		onSubmit: () => {
 			isLoading = true;
-			toast.success('Updating your name...');
+			toast.loading('Updating your name...');
 		},
 		onUpdated: ({ form: f }) => {
 			isLoading = false;
@@ -59,7 +60,12 @@
 				<Form.FieldErrors />
 			</Form.Field>
 
-			<Form.Button disabled={isLoading}>Update name</Form.Button>
+			<Form.Button disabled={isLoading}>
+				{#if isLoading}
+					<Icons.spinner class="mr-2 h-4 w-4 animate-spin" />
+				{/if}
+				Update password
+			</Form.Button>
 		</form>
 
 		{#if dev && PUBLIC_DEBUG_FORMS == 'true' && browser}