Matteo Trupia
Matteo Trupia

Reputation: 55

Flash Message Not Showing Up Sveltekit

I am experiencing problems showing flash messages in my application, the problem is that, following a form submit, after the server has handled the request, wanting to do a redirect with a flash message this is not shown. Currently the only flash that works is the login & registration flash, while other actions flash does not show up, here are some code snippets to clarify:

src\routes+layout.svelte

<script lang="ts">
    import '../app.css';
    import { setupViewTransition } from 'sveltekit-view-transition';
    import { Navbar, Footer } from '$lib/components/layout/';
    import { getFlash } from 'sveltekit-flash-message';
    import { Toaster, toast } from 'svelte-sonner';
    import { MetaTags } from 'svelte-meta-tags';
    import { page } from '$app/stores';
    import extend from 'just-extend';

    export let data;

    const flash = getFlash(page);
    const toastTypes = {
        error: toast.error,
        success: toast.success,
        info: toast.info,
        warning: toast.warning
    };

    $: if ($flash && toastTypes[$flash.type]) {
        toastTypes[$flash.type]($flash.message);
    }

    setupViewTransition();

    $: metaTags = extend(true, {}, data.baseMetaTags, $page.data.pageMetaTags);
</script>

<MetaTags {...metaTags} />

<Toaster richColors closeButton position={'top-center'} />

<div class="flex flex-col h-screen">
    <Navbar />
    <div class="grow">
        <slot />
    </div>
    <Footer />
</div>

src\routes\auth\login+page.svelte

<script lang="ts">
    import type { PageData } from './$types';
    import { UserLoginZodSchema } from '$validations/UserLoginZodSchema';
    import { InputField, SubmitButton } from '$components/form/';
    import { superForm } from 'sveltekit-superforms/client';
    import { toast } from 'svelte-sonner';
    import { route } from '$lib/ROUTES';

    export let data: PageData;

    let isLoading: boolean;

    const { enhance, form, errors, message } = superForm(data.userLoginFormData, {
        resetForm: true,
        taintedMessage: null,
        validators: UserLoginZodSchema,

        onUpdate: () => {
            isLoading = false;
            if (!$message) return;

            const { alertType, alertText } = $message;

            if (alertType === 'error') {
                toast.error(alertText);
            }
        }
    });
</script>


    <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
        <form
            class="space-y-6"
            method="post"
            on:submit={() => (isLoading = true)}
            use:enhance
            action={route('logInUser /auth/login')}
        >
            <InputField
                type="email"
                name="email"
                label="E-mail"
                placeholder="Endereço de e-mail"
                bind:value={$form.email}
                errorMessage={$errors.email}
            />

            <InputField
                type="password"
                name="password"
                label="Senha"
                placeholder="Criar senha"
                bind:value={$form.password}
                errorMessage={$errors.password}
            />

            <SubmitButton showSpinner={isLoading}>Fazer Login</SubmitButton>
        </form>
    </div>

src\routes\auth\login+page.server.ts

import type { Actions, PageServerLoad } from './$types';
import type { AlertMessageType } from '$lib/types';
import { message, setError, superValidate } from 'sveltekit-superforms/server';
import { UserLoginZodSchema } from '$validations/UserLoginZodSchema';
import { setFlash } from 'sveltekit-flash-message/server';
import { getUserByEmail } from '$lib/server/data/users';
import { DASHBOARD_ROUTE } from '$lib/appRoutes';
import { Argon2id } from 'oslo/password';
import { lucia } from '$lib/server/auth';
import { redirect } from '@sveltejs/kit';
import {
    EMAIL_NOT_REGISTERED_ERROR,
    INACTIVE_ACCOUNT_ERROR,
    INVALID_PASSWORD_ERROR,
    SUCCESSFUL_LOGIN,
    VALIDATION_ERROR
} from '$validations/validationConstants';

export const load = (async () => {
    return {
        userLoginFormData: await superValidate(UserLoginZodSchema)
    };
}) satisfies PageServerLoad;

export const actions: Actions = {
    logInUser: async ({ request, cookies }) => {
        // Validate the form
        const userLoginFormData = await superValidate<typeof UserLoginZodSchema, AlertMessageType>(
            request,
            UserLoginZodSchema
        );
        // IF the form isn't valid send error message
        if (userLoginFormData.valid === false) {
            return message(userLoginFormData, {
                alertType: 'error',
                alertText: VALIDATION_ERROR
            });
        }
        // Get if the user does exist in the db
        const existingUser = await getUserByEmail(userLoginFormData.data.email);

        if (existingUser === undefined) {
            return setError(userLoginFormData, 'email', EMAIL_NOT_REGISTERED_ERROR);
        }

        const validPassword = await new Argon2id().verify(
            existingUser.password,
            userLoginFormData.data.password
        );

        if (!existingUser.isActive) {
            return setError(userLoginFormData, 'email', INACTIVE_ACCOUNT_ERROR);
        }

        if (!validPassword) {
            return setError(userLoginFormData, 'password', INVALID_PASSWORD_ERROR);
        }

        const session = await lucia.createSession(existingUser.id, {});
        const sessionCookie = lucia.createSessionCookie(session.id);

        cookies.set(sessionCookie.name, sessionCookie.value, {
            path: '.',
            ...sessionCookie.attributes
        });

        // Show a success toast
        setFlash({ type: 'success', message: SUCCESSFUL_LOGIN }, cookies);

        throw redirect(303, DASHBOARD_ROUTE);
    }
};

While this action, for example, does not show the flash after the redirect, the load redirect does not show it either, despite the fact that it was supposed to show an error toast:

src\routes\dashboard+page.server.ts

import type { Actions, PageServerLoad } from './$types';
import { redirect, setFlash } from 'sveltekit-flash-message/server';
import { getAllUsers } from '$lib/server/data/users';
import { LOGIN_ROUTE } from '$lib/appRoutes';
import { lucia } from '$lib/server/auth';
import { error } from '@sveltejs/kit';
import {
    NOT_LOGGED_DASHBOARD_ERROR_MESSAGE,
    NO_ACCOUNT_LOGOUT_ERROR,
    SUCCESSFUL_LOGOUT
} from '$validations/validationConstants';

export const load = (async ({ locals: { user }, cookies }) => {
    if (!user) {
        throw redirect(
            LOGIN_ROUTE,
            {
                type: 'error',
                message: NOT_LOGGED_DASHBOARD_ERROR_MESSAGE
            },
            cookies
        );
    }

    ...
}) satisfies PageServerLoad;

export const actions: Actions = {
    logout: async ({ cookies, locals }) => {
        if (!locals.session?.id) throw error(403, NO_ACCOUNT_LOGOUT_ERROR);

        await lucia.invalidateSession(locals.session.id);

        const sessionCookie = lucia.createBlankSessionCookie();

        cookies.set(sessionCookie.name, sessionCookie.value, {
            path: '.',
            ...sessionCookie.attributes
        });

        // Show a info toast
        setFlash({ type: 'error', message: SUCCESSFUL_LOGOUT }, cookies);

        throw redirect(303, LOGIN_ROUTE);
    }
};

Upvotes: 0

Views: 366

Answers (0)

Related Questions