From f63e2918ff5466f6f2ccfde131d5ffce31fae650 Mon Sep 17 00:00:00 2001 From: JCEEE <0xjceee@proton.me> Date: Tue, 25 Aug 2026 07:57:50 +0100 Subject: [PATCH] fix some signup ux issues --- .../src/routes/[fam]/[username]/+page.svelte | 3 + .../[fam]/[username]/settings/+page.svelte | 2 +- .../src/routes/[fam]/join/+page.server.ts | 33 ++++++++++ frontend/src/routes/[fam]/join/+page.svelte | 65 +++++++++++++++++++ .../routes/[fam]/join/[username]/+page.svelte | 13 +++- 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 frontend/src/routes/[fam]/join/+page.server.ts create mode 100644 frontend/src/routes/[fam]/join/+page.svelte diff --git a/frontend/src/routes/[fam]/[username]/+page.svelte b/frontend/src/routes/[fam]/[username]/+page.svelte index bd55d2b..97d4e63 100644 --- a/frontend/src/routes/[fam]/[username]/+page.svelte +++ b/frontend/src/routes/[fam]/[username]/+page.svelte @@ -911,6 +911,9 @@

Loading...

{:else if error}

{error}

+

+ +

{:else} {#if simulateEow}
diff --git a/frontend/src/routes/[fam]/[username]/settings/+page.svelte b/frontend/src/routes/[fam]/[username]/settings/+page.svelte index 7b0d13a..531132f 100644 --- a/frontend/src/routes/[fam]/[username]/settings/+page.svelte +++ b/frontend/src/routes/[fam]/[username]/settings/+page.svelte @@ -82,7 +82,7 @@ let copied = $state(false); let parentInviteEmail = $state(''); - let members = $state(famStore.initialized ? famStore.members : data.members || []); + let members = $derived(famStore.initialized ? famStore.members : (data.members || [])); let deletingSeason = $state(null); let issued = $state<{ otp: string; joinUrl: string; name: string } | null>(null); diff --git a/frontend/src/routes/[fam]/join/+page.server.ts b/frontend/src/routes/[fam]/join/+page.server.ts new file mode 100644 index 0000000..dc5a357 --- /dev/null +++ b/frontend/src/routes/[fam]/join/+page.server.ts @@ -0,0 +1,33 @@ +import { fail, redirect } from '@sveltejs/kit'; +import { redeemOtp } from '$lib/server/member-otp'; +import { handle } from '@shared/slugify'; +import { setSessionCookie, clearLegacyCookies } from '$lib/server/session'; + +export const actions = { + default: async (event) => { + const fam = event.params.fam; + const fd = await event.request.formData(); + const name = (fd.get('name') || '').toString().trim(); + const otp = (fd.get('otp') || '').toString().trim(); + + if (!name) return fail(400, { error: 'Enter your name.', name, otp }); + if (!otp) return fail(400, { error: 'Enter the code shown by your parent.', name, otp }); + + try { + // redeemOtp derives the username from the handle internally; pass the + // raw name so it resolves the same {famSlug}:{handle} identity. + const token = await redeemOtp({ famSlug: fam, username: name, otp }); + clearLegacyCookies(event.cookies); + setSessionCookie(event.cookies, token); + } catch (e) { + return fail(400, { + error: e instanceof Error ? e.message : 'Join failed', + name, + otp + }); + } + + const handleName = handle(name); + throw redirect(303, `/${fam}/${encodeURIComponent(handleName)}`); + } +}; diff --git a/frontend/src/routes/[fam]/join/+page.svelte b/frontend/src/routes/[fam]/join/+page.svelte new file mode 100644 index 0000000..3fac793 --- /dev/null +++ b/frontend/src/routes/[fam]/join/+page.svelte @@ -0,0 +1,65 @@ + + +Join {famSlug} + +
+
+
+ 🏠 +
+

Join {famSlug}

+

+ Enter your name and the code your parent gave you to get started. +

+ +
{ + return async ({ result, update }) => { + if (result.type === 'failure') { + name = (result.data as any)?.name || ''; + otp = (result.data as any)?.otp || ''; + } + await update(); + }; + }} + > + + + {#if form?.error} +

{form.error}

+ {/if} + +
+ +

+ Code is valid for 20 minutes. Ask your parent for a new one if it expires. +

+
+
diff --git a/frontend/src/routes/[fam]/join/[username]/+page.svelte b/frontend/src/routes/[fam]/join/[username]/+page.svelte index 98e4728..db9c25d 100644 --- a/frontend/src/routes/[fam]/join/[username]/+page.svelte +++ b/frontend/src/routes/[fam]/join/[username]/+page.svelte @@ -22,7 +22,18 @@ gave you to get started.

-
({})}> + { + return async ({ result, update }) => { + if (result.type === 'failure') { + otp = (result.data as any)?.otp || ''; + } + await update(); + }; + }} + >