add login page with contained inputs
This commit is contained in:
parent
762d5c0fc0
commit
fd10dcfb15
2 changed files with 128 additions and 0 deletions
34
src/routes/auth/login/+page.server.ts
Normal file
34
src/routes/auth/login/+page.server.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import type { Actions, PageServerLoad } from './$types'
|
||||||
|
import { fail, redirect } from '@sveltejs/kit'
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ locals, url }) => {
|
||||||
|
if (locals.session.isAuthenticated) {
|
||||||
|
redirect(302, url.searchParams.get('next') ?? '/me')
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
default: async ({ request, fetch, url }) => {
|
||||||
|
const form = await request.formData()
|
||||||
|
const email = String(form.get('email') ?? '')
|
||||||
|
const password = String(form.get('password') ?? '')
|
||||||
|
|
||||||
|
if (!email || !password) {
|
||||||
|
return fail(400, { error: 'Email and password are required', email })
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch('/auth/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ email, password, grant_type: 'password' })
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
redirect(303, url.searchParams.get('next') ?? '/me')
|
||||||
|
}
|
||||||
|
|
||||||
|
const j = await res.json().catch(() => ({}))
|
||||||
|
return fail(res.status, { error: j.error ?? 'Login failed', email })
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/routes/auth/login/+page.svelte
Normal file
94
src/routes/auth/login/+page.svelte
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms'
|
||||||
|
import AuthCard from '$lib/components/auth/AuthCard.svelte'
|
||||||
|
import Input from '$lib/components/ui/Input.svelte'
|
||||||
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
import * as m from '$lib/paraglide/messages'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
form: { error?: string; email?: string } | null
|
||||||
|
}
|
||||||
|
|
||||||
|
let { form }: Props = $props()
|
||||||
|
|
||||||
|
let email = $state(form?.email ?? '')
|
||||||
|
let password = $state('')
|
||||||
|
let isSubmitting = $state(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{m.auth_login_title()} | Granblue Party</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<AuthCard title={m.auth_login_title()}>
|
||||||
|
<form
|
||||||
|
method="post"
|
||||||
|
use:enhance={() => {
|
||||||
|
isSubmitting = true
|
||||||
|
return async ({ update }) => {
|
||||||
|
isSubmitting = false
|
||||||
|
await update()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
label={m.auth_login_email()}
|
||||||
|
bind:value={email}
|
||||||
|
autocomplete="email"
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
contained
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
label={m.auth_login_password()}
|
||||||
|
bind:value={password}
|
||||||
|
autocomplete="current-password"
|
||||||
|
minlength={8}
|
||||||
|
required
|
||||||
|
fullWidth
|
||||||
|
contained
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if form?.error}
|
||||||
|
<p class="error">{form.error}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<Button type="submit" variant="primary" fullWidth disabled={isSubmitting}>
|
||||||
|
{isSubmitting ? m.auth_login_submitting() : m.auth_login_submit()}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{#snippet footer()}
|
||||||
|
<p>
|
||||||
|
{m.auth_login_noAccount()}
|
||||||
|
<a href="/auth/register">{m.auth_login_register()}</a>
|
||||||
|
</p>
|
||||||
|
{/snippet}
|
||||||
|
</AuthCard>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use '$src/themes/spacing' as *;
|
||||||
|
@use '$src/themes/colors' as *;
|
||||||
|
@use '$src/themes/typography' as *;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $unit-2x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: $error;
|
||||||
|
font-size: $font-small;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: $unit $unit-2x;
|
||||||
|
background: var(--danger-bg);
|
||||||
|
border-radius: $unit;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue