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} - +
+