feat(auth-ui): show email verified banner on login pages

Add verified banner and email pre-fill to LoginPage component when
users are redirected after email verification. Updates all app login
pages to pass verification params from URL query string.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2026-01-27 01:31:55 +01:00
parent 2ccd063628
commit 09b8d7b384
12 changed files with 162 additions and 2 deletions

View file

@ -32,6 +32,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -55,6 +59,8 @@
lightBackground="#e0f2fe"
darkBackground="#0c1929"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -32,6 +32,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -55,6 +59,8 @@
lightBackground="#e0f2fe"
darkBackground="#0c1929"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -9,6 +9,10 @@
let error = $state('');
let loading = $state(false);
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
// Get redirect URL from query params or sessionStorage (set by AuthGateModal in guest mode)
const redirectTo = $derived.by(() => {
const queryRedirect = $page.url.searchParams.get('redirectTo');
@ -51,4 +55,6 @@
onSubmit={handleLogin}
registerHref="/register"
forgotPasswordHref="/forgot-password"
{verified}
{initialEmail}
/>

View file

@ -29,6 +29,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -52,6 +56,8 @@
lightBackground="#eff6ff"
darkBackground="#1e293b"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { locale } from 'svelte-i18n';
import { LoginPage } from '@manacore/shared-auth-ui';
import { ManaCoreLogo } from '@manacore/shared-branding';
@ -11,6 +12,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -30,6 +35,8 @@
lightBackground="#f3f4f6"
darkBackground="#121212"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { locale } from 'svelte-i18n';
import { LoginPage } from '@manacore/shared-auth-ui';
import { ManaDeckLogo } from '@manacore/shared-branding';
@ -11,6 +12,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -30,6 +35,8 @@
lightBackground="#faf5ff"
darkBackground="#1a1625"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -26,6 +26,10 @@
// German translations (NutriPhi is German-focused)
const translations = $derived(getLoginTranslations('de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -49,4 +53,6 @@
lightBackground="#dcfce7"
darkBackground="#052e16"
{translations}
{verified}
{initialEmail}
/>

View file

@ -1,5 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { locale } from 'svelte-i18n';
import { LoginPage, setGoogleClientId } from '@manacore/shared-auth-ui';
import { getLoginTranslations } from '@manacore/shared-i18n';
@ -32,6 +33,10 @@
// TODO: Implement OAuth with Mana Core Auth when ready
return { success: false, error: 'Apple Sign-In not yet implemented' };
}
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
</script>
<svelte:head>
@ -54,6 +59,8 @@
lightBackground="#f0f9ff"
darkBackground="#0c1929"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -1,11 +1,27 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { authStore } from '$lib/stores/auth.svelte';
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmailFromUrl = $derived($page.url.searchParams.get('email') || '');
let email = $state('');
let password = $state('');
let error = $state('');
let loading = $state(false);
let showVerifiedBanner = $state(false);
// Initialize email from URL if provided
$effect(() => {
if (initialEmailFromUrl && !email) {
email = initialEmailFromUrl;
}
if (verified) {
showVerifiedBanner = true;
}
});
async function handleSubmit(e: Event) {
e.preventDefault();
@ -22,9 +38,28 @@
loading = false;
}
function dismissBanner() {
showVerifiedBanner = false;
}
</script>
<form onsubmit={handleSubmit} class="space-y-4">
{#if showVerifiedBanner}
<div
class="relative rounded-md bg-green-100 p-3 text-sm text-green-800 dark:bg-green-900/30 dark:text-green-200"
>
<button
type="button"
onclick={dismissBanner}
class="absolute right-2 top-2 text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-200"
>
×
</button>
E-Mail erfolgreich bestätigt! Du kannst dich jetzt anmelden.
</div>
{/if}
{#if error}
<div class="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
{error}

View file

@ -16,6 +16,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return auth.login(email, password);
}
@ -39,6 +43,8 @@
lightBackground="#fff7ed"
darkBackground="#1c1210"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />

View file

@ -31,6 +31,10 @@
// Get translations based on current locale
const translations = $derived(getLoginTranslations($locale || 'de'));
// Read verification status from query params (set after email verification)
const verified = $derived($page.url.searchParams.get('verified') === 'true');
const initialEmail = $derived($page.url.searchParams.get('email') || '');
async function handleSignIn(email: string, password: string) {
return authStore.signIn(email, password);
}
@ -54,6 +58,8 @@
lightBackground="#f3e8ff"
darkBackground="#1e1b4b"
{translations}
{verified}
{initialEmail}
>
{#snippet headerControls()}
<LanguageSelector />