mirror of https://github.com/TZGyn/shortener
added setting page
parent
3eaf90ee5b
commit
8a39b9b1df
@ -0,0 +1,5 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export const userUpdateSchema = z.object({
|
||||
username: z.string(),
|
||||
})
|
||||
@ -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…
Reference in New Issue