update login page to use superform

pull/3/head
TZGyn 2 years ago
parent 68af735f09
commit 1b6a257e65
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -0,0 +1,55 @@
<script lang="ts">
import * as Form from '$lib/components/ui/form'
import { Input } from '$lib/components/ui/input'
import { formSchema, type FormSchema } from '../schema'
import {
type SuperValidated,
type Infer,
superForm,
} from 'sveltekit-superforms'
import { zodClient } from 'sveltekit-superforms/adapters'
import { toast } from 'svelte-sonner'
export let data: SuperValidated<Infer<FormSchema>>
const form = superForm(data, {
validators: zodClient(formSchema),
invalidateAll: 'force',
resetForm: true,
onResult: ({ result }) => {
if (result.status === 200) {
toast.success('Login success')
}
},
onError: ({ result }) => {
toast.error('Error Logging In')
},
})
const { form: formData, enhance } = form
</script>
<form method="POST" use:enhance class="flex flex-col gap-4">
<Form.Field {form} name="email" class="flex flex-col gap-2">
<Form.Control let:attrs>
<Form.Label>Email</Form.Label>
<Input
{...attrs}
bind:value={$formData.email}
placeholder="name@example.com" />
</Form.Control>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="password" class="flex flex-col gap-2">
<Form.Control let:attrs>
<Form.Label>Password</Form.Label>
<Input
{...attrs}
type="password"
bind:value={$formData.password}
placeholder="••••••••" />
</Form.Control>
<Form.FieldErrors />
</Form.Field>
<Form.Button>Login</Form.Button>
</form>

@ -0,0 +1,54 @@
import type { PageServerLoad, Actions } from './$types'
import { fail } from '@sveltejs/kit'
import { setError, superValidate } from 'sveltekit-superforms'
import { formSchema } from './schema'
import { zod } from 'sveltekit-superforms/adapters'
import { db } from '$lib/db'
import { user as userSchema } from '$lib/db/schema'
import { eq } from 'drizzle-orm'
import { lucia } from '$lib/server/auth'
export const load = (async (event) => {
return {
form: await superValidate(zod(formSchema)),
}
}) satisfies PageServerLoad
export const actions: Actions = {
default: async (event) => {
const form = await superValidate(event, zod(formSchema))
if (!form.valid) {
return fail(400, {
form,
})
}
const users = await db
.select()
.from(userSchema)
.where(eq(userSchema.email, form.data.email))
const user = users[0]
const matchPassword =
user &&
(await Bun.password.verify(form.data.password, user.password))
if (!user || !matchPassword) {
return setError(form, 'email', 'Invalid credentials')
}
const session = await lucia.createSession(user.id, {})
const sessionCookie = lucia.createSessionCookie(session.id)
event.cookies.set(sessionCookie.name, sessionCookie.value, {
...sessionCookie.attributes,
path: '/',
secure: Bun.env.APP_ENV === 'prod',
})
return {
form,
}
},
}

@ -1,69 +1,27 @@
<script lang="ts"> <script lang="ts">
import ThemeToggle from '$lib/components/theme-toggle.svelte' import ThemeToggle from '$lib/components/theme-toggle.svelte'
import { Button } from '$lib/components/ui/button' import Form from './(components)/form.svelte'
import Input from '$lib/components/ui/input/input.svelte'
import Label from '$lib/components/ui/label/label.svelte'
import { goto } from '$app/navigation'
import { Loader2 } from 'lucide-svelte'
import { toast } from 'svelte-sonner'
let isLoading = false import type { PageData } from './$types'
const guestLogin = async () => { export let data: PageData
isLoading = true
const response = await fetch('/api/login', {
method: 'post',
body: JSON.stringify({
email: 'test@example.com',
password: 'password',
}),
})
const data = await response.json()
isLoading = false
if (data.success) {
toast.success('Successfully Logged In')
goto('/')
}
}
let email = ''
let password = ''
const userLogin = async () => {
isLoading = true
const response = await fetch('/api/login', {
method: 'post',
body: JSON.stringify({
email,
password,
}),
})
const data = await response.json()
isLoading = false
if (data.success) {
toast.success('Successfully Logged In')
goto('/')
}
}
</script> </script>
<div <div
class="container relative h-screen flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0"> class="container relative flex-col justify-center items-center h-screen md:grid lg:grid-cols-2 lg:px-0 lg:max-w-none">
<div class="absolute right-4 top-4 md:right-8 md:top-8"> <div class="absolute top-4 right-4 md:top-8 md:right-8">
<ThemeToggle /> <ThemeToggle />
</div> </div>
<div <div
class="relative hidden h-full flex-col bg-primary-foreground p-10 text-white dark:border-r lg:flex"> class="hidden relative flex-col p-10 h-full text-white lg:flex dark:border-r bg-primary-foreground">
<div <div
class="relative z-20 flex items-center text-lg font-medium text-primary"> class="flex relative z-20 items-center text-lg font-medium text-primary">
Shortener Shortener
</div> </div>
</div> </div>
<div class="p-8"> <div class="p-8">
<div <div
class="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]"> class="flex flex-col justify-center mx-auto space-y-6 w-full sm:w-[350px]">
<div class="flex flex-col space-y-2 text-center"> <div class="flex flex-col space-y-2 text-center">
<h1 class="text-2xl font-semibold tracking-tight"> <h1 class="text-2xl font-semibold tracking-tight">
Login to your account Login to your account
@ -72,34 +30,8 @@
Enter your email below to login to your account Enter your email below to login to your account
</p> </p>
</div> </div>
<div class="flex flex-col gap-4"> <Form data={data.form} />
<div class="flex w-full max-w-sm flex-col gap-2"> <p class="px-8 text-sm text-center text-muted-foreground">
<Label for="email">Email</Label>
<Input
type="email"
id="email"
placeholder="name@example.com"
bind:value={email} />
</div>
<div class="flex w-full max-w-sm flex-col gap-2">
<Label for="password">Password</Label>
<Input
type="password"
id="password"
placeholder="••••••••"
bind:value={password} />
</div>
<Button
disabled={isLoading}
on:click={userLogin}
class="flex items-center gap-2">
{#if isLoading}
<Loader2 class="animate-spin" />
{/if}
Login
</Button>
</div>
<p class="px-8 text-center text-sm text-muted-foreground">
Don't Have An Account? Signup{' '} Don't Have An Account? Signup{' '}
<a <a
href="/signup" href="/signup"
@ -107,15 +39,6 @@
Here Here
</a> </a>
</p> </p>
<Button
disabled={isLoading}
on:click={guestLogin}
class="flex gap-2">
{#if isLoading}
<Loader2 class="animate-spin" />
{/if}
Login As Guest
</Button>
</div> </div>
</div> </div>
</div> </div>

@ -1,8 +1,8 @@
import { z } from 'zod' import { z } from 'zod'
export const formSchema = z.object({ export const formSchema = z.object({
email: z.string().email(), email: z.string(),
password: z.string().min(8), password: z.string(),
}) })
export type FormSchema = typeof formSchema export type FormSchema = typeof formSchema

@ -1,52 +0,0 @@
import type { RequestHandler } from './$types'
import { user as userSchema } from '$lib/db/schema'
import { db } from '$lib/db'
import { eq } from 'drizzle-orm'
import { userLoginSchema } from '$lib/server/types'
import { lucia } from '$lib/server/auth'
export const GET: RequestHandler = async () => {
return new Response()
}
export const POST: RequestHandler = async (event) => {
const body = await event.request.json()
const userLogin = userLoginSchema.safeParse(body)
if (!userLogin.success) {
return new Response(
JSON.stringify({
success: false,
}),
)
}
const users = await db
.select()
.from(userSchema)
.where(eq(userSchema.email, userLogin.data.email))
const user = users[0]
const matchPassword =
user &&
(await Bun.password.verify(
userLogin.data.password,
user.password,
))
if (user && matchPassword) {
const session = await lucia.createSession(user.id, {})
const sessionCookie = lucia.createSessionCookie(session.id)
event.cookies.set(sessionCookie.name, sessionCookie.value, {
...sessionCookie.attributes,
path: '/',
secure: Bun.env.APP_ENV === 'prod',
})
return new Response(JSON.stringify({ success: true }))
} else {
return new Response(JSON.stringify({ success: false }))
}
}
Loading…
Cancel
Save