added setting page

pull/3/head
TZGyn 2 years ago
parent 3eaf90ee5b
commit 8a39b9b1df
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -36,10 +36,10 @@
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item <DropdownMenu.Item
on:click={() => { on:click={() => {
goto('/profile') goto('/settings')
onClick() onClick()
}}> }}>
Profile Settings
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Separator /> <DropdownMenu.Separator />
<DropdownMenu.Item <DropdownMenu.Item

@ -0,0 +1,5 @@
import { z } from 'zod'
export const userUpdateSchema = z.object({
username: z.string(),
})

@ -4,7 +4,8 @@ export const load = (async (event) => {
const user = event.locals.userObject const user = event.locals.userObject
return { return {
shortener_url: process.env.PUBLIC_SHORTENER_URL ?? 's.tzgyn.com', shortener_url:
process.env.PUBLIC_SHORTENER_URL ?? '3000.tzgyn.com',
user: user, user: user,
} }
}) satisfies LayoutServerLoad }) satisfies LayoutServerLoad

@ -0,0 +1,28 @@
<script lang="ts">
import { cn } from '$lib/utils'
import { page } from '$app/stores'
import { Button } from '$lib/components/ui/button'
let className: string | undefined | null = undefined
export let items: { href: string; title: string }[]
export { className as class }
</script>
<nav
class={cn(
'flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1',
className,
)}>
{#each items as item}
<Button
href={item.href}
variant="ghost"
class={cn(
$page.url.pathname === item.href
? 'bg-muted hover:bg-muted'
: 'hover:bg-transparent hover:underline',
'justify-start',
)}>
{item.title}
</Button>
{/each}
</nav>

@ -0,0 +1,34 @@
<script lang="ts">
import { Separator } from '$lib/components/ui/separator'
import SidebarNav from './(components)/sidebar-nav.svelte'
const sidebarNavItems = [
{
title: 'Profile',
href: '/settings',
},
{
title: 'Account',
href: '/settings/account',
},
]
</script>
<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">
Manage your account settings and set e-mail preferences.
</p>
</div>
<Separator class="my-6" />
<div
class="flex flex-col space-y-8 lg:flex-row lg:space-x-12 lg:space-y-0">
<aside class="-mx-4 lg:w-1/5">
<SidebarNav items={sidebarNavItems} />
</aside>
<div class="flex-1 lg:max-w-2xl">
<slot />
</div>
</div>
</div>

@ -0,0 +1,15 @@
<script lang="ts">
import type { PageData } from './$types'
import { Separator } from '$lib/components/ui/separator'
export let data: PageData
</script>
<div class="space-y-6">
<div>
<h3 class="text-lg font-medium">Profile</h3>
<p class="text-muted-foreground text-sm">
This is how others will see you on the site.
</p>
</div>
<Separator />
</div>

@ -0,0 +1,94 @@
<script lang="ts">
import { Separator } from '$lib/components/ui/separator'
import { Input } from '$lib/components/ui/input'
import { Label } from '$lib/components/ui/label'
import type { PageData } from './$types'
import Button from '$lib/components/ui/button/button.svelte'
import { Loader2 } from 'lucide-svelte'
import { invalidateAll } from '$app/navigation'
export let data: PageData
let account_data = {
username: data.user.username,
email: data.user.email,
old_password: '',
new_password: '',
}
let isLoading = false
const submit = async () => {
isLoading = true
const response = await fetch('/api/account', {
method: 'PUT',
body: JSON.stringify(account_data),
})
const body = await response.json()
if (body.success) {
await invalidateAll()
}
isLoading = false
}
</script>
<div class="space-y-6">
<div>
<h3 class="text-lg font-medium">Account</h3>
<p class="text-muted-foreground text-sm">
Update your account settings.
</p>
</div>
<Separator />
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="username">Username</Label>
<Input
type="text"
id="username"
bind:value={account_data.username} />
<p class="text-muted-foreground text-sm">Change your username.</p>
</div>
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="email">Email</Label>
<Input
disabled
type="email"
id="email"
bind:value={account_data.email} />
<p class="text-muted-foreground text-sm">Change your email.</p>
</div>
<Separator />
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="old_password">Old Password</Label>
<Input
type="password"
id="old_password"
bind:value={account_data.old_password} />
<p class="text-muted-foreground text-sm">
Enter your old password in order to change it.
</p>
</div>
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="old_password">New Password</Label>
<Input
type="password"
id="new_password"
bind:value={account_data.new_password} />
<p class="text-muted-foreground text-sm">Change your password.</p>
</div>
<Button disabled={isLoading} on:click={submit} class="flex gap-2">
{#if isLoading}
<Loader2 class="animate-spin" />
{/if}
Save</Button>
</div>

@ -0,0 +1,29 @@
import { db } from '$lib/db'
import { user } from '$lib/db/schema'
import { userUpdateSchema } from '$lib/server/types'
import { eq } from 'drizzle-orm'
import type { RequestHandler } from './$types'
export const GET: RequestHandler = async () => {
return new Response()
}
export const PUT: RequestHandler = async (event) => {
const body = await event.request.json()
const userId = event.locals.userObject.id
const userUpdateData = userUpdateSchema.safeParse(body)
if (!userUpdateData.success) {
return new Response(JSON.stringify({ success: false }))
}
await db
.update(user)
.set({
username: userUpdateData.data.username,
})
.where(eq(user.id, userId))
return new Response(JSON.stringify({ success: true }))
}
Loading…
Cancel
Save