fix: handle duplicate email sign-up and null user in protected layout
- Register action now returns success instead of redirecting to /account/setup so users without a session (duplicate email with requireEmailVerification) see a 'check your email' message instead of crashing - Protected layout guards against null/undefined locals.user before querying Prisma (was passing id: undefined) - Updated register page to show success banner with verification instructions - Updated test to match new action response
This commit is contained in:
@@ -3,8 +3,12 @@ import { error, redirect } from '@sveltejs/kit';
|
||||
import { prisma } from '$lib/db';
|
||||
|
||||
export const load: LayoutServerLoad = async ({ locals }) => {
|
||||
if (!locals.user?.id) {
|
||||
throw error(403, 'not authorized');
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: locals.user?.id },
|
||||
where: { id: locals.user.id },
|
||||
select: { id: true, roleId: true, profile: { select: { id: true } } }
|
||||
});
|
||||
if (!user) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Actions } from './$types';
|
||||
import { auth } from '$lib/auth';
|
||||
import { fail, isRedirect, redirect } from '@sveltejs/kit';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
|
||||
export const actions: Actions = {
|
||||
default: async ({ request }) => {
|
||||
@@ -17,7 +17,7 @@ export const actions: Actions = {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await auth.api.signUpEmail({
|
||||
await auth.api.signUpEmail({
|
||||
body: {
|
||||
name: `${firstName} ${lastName}`,
|
||||
email: email,
|
||||
@@ -25,11 +25,8 @@ export const actions: Actions = {
|
||||
}
|
||||
});
|
||||
|
||||
if (response.user) {
|
||||
throw redirect(303, '/account/setup');
|
||||
}
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
if (isRedirect(err)) throw err;
|
||||
const message = err instanceof Error ? err.message : 'An unexpected error occurred';
|
||||
return fail(400, { error: message });
|
||||
}
|
||||
|
||||
@@ -8,7 +8,17 @@
|
||||
|
||||
<Window>
|
||||
<div class="flex flex-col items-start justify-center">
|
||||
{#if form?.error}
|
||||
{#if form?.success}
|
||||
<div
|
||||
class="mb-4 w-full rounded-lg border border-green-200 bg-green-50 p-4 text-green-700"
|
||||
>
|
||||
<p class="font-medium">Account created!</p>
|
||||
<p class="mt-1 text-sm">
|
||||
We've sent a verification email. Check your inbox and click the link to verify your
|
||||
email address, then log in.
|
||||
</p>
|
||||
</div>
|
||||
{:else if form?.error}
|
||||
<div class="mb-4 w-full rounded-lg border border-red-200 bg-red-50 p-3 text-red-700">
|
||||
{form.error}
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('register page server action', () => {
|
||||
expect(signUpEmail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to /account/setup on successful signup', async () => {
|
||||
it('returns success on successful signup', async () => {
|
||||
signUpEmail.mockResolvedValue({ user: { id: 'user-1' } });
|
||||
|
||||
const request = createFormRequest({
|
||||
@@ -52,9 +52,8 @@ describe('register page server action', () => {
|
||||
password2: 'secret123'
|
||||
});
|
||||
|
||||
await expect(actions.default({ request } as any)).rejects.toMatchObject({
|
||||
status: 303
|
||||
});
|
||||
const result = await invokeDefault(request);
|
||||
expect(result).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('returns fail(400) when signUpEmail throws', async () => {
|
||||
|
||||
Reference in New Issue
Block a user