From 60ac4a8f79682f7160f738e9dba05a6322531792 Mon Sep 17 00:00:00 2001 From: eewing Date: Thu, 26 Feb 2026 15:11:24 -0600 Subject: [PATCH] Refactor login page to support user registration. Enhanced form handling by adding name and password confirmation fields, improved error messaging, and updated button labels for better user experience. Adjusted internal server options to reflect changes in form data structure. --- .svelte-kit/generated/server/internal.js | 2 +- .../src/routes/login/proxy+page.server.ts | 94 +++++++++++++++---- src/routes/login/+page.server.ts | 94 +++++++++++++++---- src/routes/login/+page.svelte | 55 +++++++++-- 4 files changed, 204 insertions(+), 41 deletions(-) diff --git a/.svelte-kit/generated/server/internal.js b/.svelte-kit/generated/server/internal.js index 8e26641d..a6d60d75 100644 --- a/.svelte-kit/generated/server/internal.js +++ b/.svelte-kit/generated/server/internal.js @@ -24,7 +24,7 @@ export const options = { app: ({ head, body, assets, nonce, env }) => "\n\n \n \n \n \n \n " + head + "\n \n \n
" + body + "
\n \n\n", error: ({ status, message }) => "\n\n\t\n\t\t\n\t\t" + message + "\n\n\t\t\n\t\n\t\n\t\t
\n\t\t\t" + status + "\n\t\t\t
\n\t\t\t\t

" + message + "

\n\t\t\t
\n\t\t
\n\t\n\n" }, - version_hash: "1pywl2x" + version_hash: "3lzvrw" }; export async function get_hooks() { diff --git a/.svelte-kit/types/src/routes/login/proxy+page.server.ts b/.svelte-kit/types/src/routes/login/proxy+page.server.ts index eb1aff83..e95082d4 100644 --- a/.svelte-kit/types/src/routes/login/proxy+page.server.ts +++ b/.svelte-kit/types/src/routes/login/proxy+page.server.ts @@ -8,37 +8,97 @@ export const load = async ({ url, locals }: Parameters[0]) => { } return { redirectTo: url.searchParams.get('redirectTo') ?? '', - error: null + error: null, + form: null as { error?: string; redirectTo?: string } | null }; }; -export const actions = { - default: async ({ request, locals, url }: import('./$types').RequestEvent) => { - const formData = await request.formData(); - const email = String(formData.get('email') ?? '').trim(); - const password = String(formData.get('password') ?? ''); - const redirectTo = String(formData.get('redirectTo') ?? '').trim() || '/'; +const loginAction = async ({ + request, + locals +}: { + request: Request; + locals: App.Locals; +}) => { + const formData = await request.formData(); + const intent = String(formData.get('intent') ?? 'login').trim(); + const name = String(formData.get('name') ?? '').trim(); + const email = String(formData.get('email') ?? '').trim(); + const password = String(formData.get('password') ?? ''); + const passwordConfirm = String(formData.get('passwordConfirm') ?? ''); + const redirectTo = String(formData.get('redirectTo') ?? '').trim() || '/'; + if (intent === 'register') { + if (!name) { + return { + redirectTo, + form: { error: 'Name is required.', redirectTo } + }; + } if (!email || !password) { return { redirectTo, - error: 'Email and password are required.' + form: { error: 'Email and password are required.', redirectTo } }; } - - try { - await locals.pb.collection('users').authWithPassword(email, password); - } catch (err) { - const message = err && typeof err === 'object' && 'message' in err - ? String((err as { message: string }).message) - : 'Invalid email or password.'; + if (password.length < 8) { return { redirectTo, - error: message + form: { error: 'Password must be at least 8 characters.', redirectTo } + }; + } + if (password !== passwordConfirm) { + return { + redirectTo, + form: { error: 'Passwords do not match.', redirectTo } + }; + } + try { + await locals.pb.collection('users').create({ + name, + email, + password, + passwordConfirm: password, + Stackq: true + }); + await locals.pb.collection('users').authWithPassword(email, password); + } catch (err) { + const message = + err && typeof err === 'object' && 'message' in err + ? String((err as { message: string }).message) + : 'Could not create account. Email may already be in use.'; + return { + redirectTo, + form: { error: message, redirectTo } }; } - throw redirect(303, redirectTo); } + + if (!email || !password) { + return { + redirectTo, + form: { error: 'Email and password are required.', redirectTo } + }; + } + + try { + await locals.pb.collection('users').authWithPassword(email, password); + } catch (err) { + const message = + err && typeof err === 'object' && 'message' in err + ? String((err as { message: string }).message) + : 'Invalid email or password.'; + return { + redirectTo, + form: { error: message, redirectTo } + }; + } + + throw redirect(303, redirectTo); +}; + +export const actions = { + default: loginAction }; ;null as any as Actions; \ No newline at end of file diff --git a/src/routes/login/+page.server.ts b/src/routes/login/+page.server.ts index 6fa3f5ec..61cabab5 100644 --- a/src/routes/login/+page.server.ts +++ b/src/routes/login/+page.server.ts @@ -7,36 +7,96 @@ export const load: PageServerLoad = async ({ url, locals }) => { } return { redirectTo: url.searchParams.get('redirectTo') ?? '', - error: null + error: null, + form: null as { error?: string; redirectTo?: string } | null }; }; -export const actions: Actions = { - default: async ({ request, locals, url }) => { - const formData = await request.formData(); - const email = String(formData.get('email') ?? '').trim(); - const password = String(formData.get('password') ?? ''); - const redirectTo = String(formData.get('redirectTo') ?? '').trim() || '/'; +const loginAction = async ({ + request, + locals +}: { + request: Request; + locals: App.Locals; +}) => { + const formData = await request.formData(); + const intent = String(formData.get('intent') ?? 'login').trim(); + const name = String(formData.get('name') ?? '').trim(); + const email = String(formData.get('email') ?? '').trim(); + const password = String(formData.get('password') ?? ''); + const passwordConfirm = String(formData.get('passwordConfirm') ?? ''); + const redirectTo = String(formData.get('redirectTo') ?? '').trim() || '/'; + if (intent === 'register') { + if (!name) { + return { + redirectTo, + form: { error: 'Name is required.', redirectTo } + }; + } if (!email || !password) { return { redirectTo, - error: 'Email and password are required.' + form: { error: 'Email and password are required.', redirectTo } }; } - - try { - await locals.pb.collection('users').authWithPassword(email, password); - } catch (err) { - const message = err && typeof err === 'object' && 'message' in err - ? String((err as { message: string }).message) - : 'Invalid email or password.'; + if (password.length < 8) { return { redirectTo, - error: message + form: { error: 'Password must be at least 8 characters.', redirectTo } + }; + } + if (password !== passwordConfirm) { + return { + redirectTo, + form: { error: 'Passwords do not match.', redirectTo } + }; + } + try { + await locals.pb.collection('users').create({ + name, + email, + password, + passwordConfirm: password, + Stackq: true + }); + await locals.pb.collection('users').authWithPassword(email, password); + } catch (err) { + const message = + err && typeof err === 'object' && 'message' in err + ? String((err as { message: string }).message) + : 'Could not create account. Email may already be in use.'; + return { + redirectTo, + form: { error: message, redirectTo } }; } - throw redirect(303, redirectTo); } + + if (!email || !password) { + return { + redirectTo, + form: { error: 'Email and password are required.', redirectTo } + }; + } + + try { + await locals.pb.collection('users').authWithPassword(email, password); + } catch (err) { + const message = + err && typeof err === 'object' && 'message' in err + ? String((err as { message: string }).message) + : 'Invalid email or password.'; + return { + redirectTo, + form: { error: message, redirectTo } + }; + } + + throw redirect(303, redirectTo); +}; + +export const actions: Actions = { + default: loginAction }; diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte index 3b5d7149..300bb690 100644 --- a/src/routes/login/+page.svelte +++ b/src/routes/login/+page.svelte @@ -10,6 +10,8 @@ formAction: string; } = $props(); + let isRegister = $state(false); + const redirectTo = $derived(data.form?.redirectTo ?? data.redirectTo ?? ''); const error = $derived(data.form?.error); @@ -17,17 +19,35 @@
- Sign in - Enter your email and password. + {isRegister ? 'Create account' : 'Sign in'} + + {isRegister + ? 'Enter your email and a password (min 8 characters).' + : 'Enter your email and password.'} + - +
+ + {#if isRegister} +
+ + +
+ {/if}
@@ -46,14 +66,37 @@ name="password" type="password" required - autocomplete="current-password" + minlength={isRegister ? 8 : undefined} + autocomplete={isRegister ? 'new-password' : 'current-password'} />
+ {#if isRegister} +
+ + +
+ {/if} {#if error}

{error}

{/if} - +
+