add new routes
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
|
import { redeemOtp } from '$lib/server/member-otp';
|
||||||
|
import { setSessionCookie } from '$lib/server/session';
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
default: async (event) => {
|
||||||
|
const famSlug = event.params.famSlug;
|
||||||
|
const username = event.params.username;
|
||||||
|
const fd = await event.request.formData();
|
||||||
|
const otp = (fd.get('otp') || '').toString().trim();
|
||||||
|
|
||||||
|
if (!otp) return fail(400, { error: 'Enter the code shown by your parent.' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const token = await redeemOtp({ famSlug, username, otp });
|
||||||
|
event.cookies.delete('device_token', { path: '/' });
|
||||||
|
setSessionCookie(event.cookies, token);
|
||||||
|
} catch (e) {
|
||||||
|
return fail(400, { error: e instanceof Error ? e.message : 'Join failed' });
|
||||||
|
}
|
||||||
|
|
||||||
|
throw redirect(303, `/${famSlug}/${encodeURIComponent(username)}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { page } from '$app/state';
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
import { Button } from '$lib/components';
|
||||||
|
|
||||||
|
const famSlug = page.params.famSlug;
|
||||||
|
const username = page.params.username;
|
||||||
|
let otp = $state(page.url.searchParams.get('code') || '');
|
||||||
|
let { form } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head><title>Join {famSlug}</title></svelte:head>
|
||||||
|
|
||||||
|
<main class="mx-auto flex min-h-screen max-w-md flex-col items-center justify-center px-6">
|
||||||
|
<section class="w-full rounded-2xl border border-slate-200 bg-white p-8 text-center shadow-sm">
|
||||||
|
<div class="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-indigo-100 text-2xl">
|
||||||
|
🏠
|
||||||
|
</div>
|
||||||
|
<h1 class="text-xl font-bold text-slate-900">Welcome to {famSlug}!</h1>
|
||||||
|
<p class="mt-1 text-sm text-slate-500">
|
||||||
|
Hi <span class="font-semibold text-slate-700">{username}</span> — enter the code your parent
|
||||||
|
gave you to get started.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form class="mt-6 flex flex-col gap-3" method="POST" use:enhance={() => ({})}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="otp"
|
||||||
|
bind:value={otp}
|
||||||
|
inputmode="numeric"
|
||||||
|
maxlength="6"
|
||||||
|
placeholder="6-digit code"
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
class="w-full rounded-lg border border-slate-300 px-4 py-3 text-center text-2xl tracking-[0.5em] text-slate-900 outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200"
|
||||||
|
/>
|
||||||
|
{#if form?.error}
|
||||||
|
<p class="text-sm font-medium text-rose-600">{form.error}</p>
|
||||||
|
{/if}
|
||||||
|
<Button type="submit" variant="primary" size="lg">Join</Button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p class="mt-6 text-xs text-slate-400">
|
||||||
|
Code is valid for 20 minutes. Ask your parent for a new one if it expires.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
Reference in New Issue
Block a user