mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-19 09:01:22 +02:00
✨ 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:
parent
2ccd063628
commit
09b8d7b384
12 changed files with 162 additions and 2 deletions
|
|
@ -29,6 +29,7 @@
|
|||
googleSignInFailed: string;
|
||||
signInSuccess: string;
|
||||
googleSignInSuccess: string;
|
||||
emailVerified?: string;
|
||||
}
|
||||
|
||||
const defaultTranslations: LoginTranslations = {
|
||||
|
|
@ -54,6 +55,7 @@
|
|||
googleSignInFailed: 'Google sign in failed',
|
||||
signInSuccess: 'Successfully signed in. Redirecting...',
|
||||
googleSignInSuccess: 'Successfully signed in with Google. Redirecting...',
|
||||
emailVerified: 'Email successfully verified! Please sign in.',
|
||||
};
|
||||
|
||||
interface Props {
|
||||
|
|
@ -74,6 +76,10 @@
|
|||
appSlider?: Snippet;
|
||||
headerControls?: Snippet;
|
||||
translations?: Partial<LoginTranslations>;
|
||||
/** Show email verified success banner */
|
||||
verified?: boolean;
|
||||
/** Pre-fill email field (e.g., after email verification) */
|
||||
initialEmail?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
|
|
@ -94,6 +100,8 @@
|
|||
appSlider,
|
||||
headerControls,
|
||||
translations = {},
|
||||
verified = false,
|
||||
initialEmail = '',
|
||||
}: Props = $props();
|
||||
|
||||
const t = $derived({ ...defaultTranslations, ...translations });
|
||||
|
|
@ -101,7 +109,7 @@
|
|||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let errorField = $state<'email' | 'password' | 'general' | null>(null);
|
||||
let email = $state('');
|
||||
let email = $state(initialEmail);
|
||||
let password = $state('');
|
||||
let showPassword = $state(false);
|
||||
let rememberMe = $state(false);
|
||||
|
|
@ -110,6 +118,7 @@
|
|||
let emailInput: HTMLInputElement;
|
||||
let passwordInput: HTMLInputElement;
|
||||
let successAnnouncement = $state('');
|
||||
let showVerifiedBanner = $state(verified);
|
||||
|
||||
// Theme state - can be toggled manually, defaults to system preference
|
||||
let userThemePreference = $state<'light' | 'dark' | null>(null);
|
||||
|
|
@ -145,7 +154,12 @@
|
|||
}
|
||||
|
||||
$effect(() => {
|
||||
if (emailInput) emailInput.focus();
|
||||
// Focus password field if email is pre-filled, otherwise focus email
|
||||
if (initialEmail && passwordInput) {
|
||||
passwordInput.focus();
|
||||
} else if (emailInput) {
|
||||
emailInput.focus();
|
||||
}
|
||||
});
|
||||
|
||||
function isValidEmail(email: string): boolean {
|
||||
|
|
@ -296,6 +310,21 @@
|
|||
<!-- Form Section -->
|
||||
<div class="form-section">
|
||||
<div class="form-card" class:shake={shakeError}>
|
||||
{#if showVerifiedBanner}
|
||||
<div class="verified-banner" role="status" aria-live="polite">
|
||||
<Check size={18} class="text-green-500 shrink-0" />
|
||||
<p>{t.emailVerified}</p>
|
||||
<button
|
||||
type="button"
|
||||
class="verified-banner-close"
|
||||
onclick={() => (showVerifiedBanner = false)}
|
||||
aria-label="Close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="form-header">
|
||||
<h2 class="form-title">{t.title}</h2>
|
||||
<p class="form-subtitle">{t.subtitle}</p>
|
||||
|
|
@ -612,6 +641,39 @@
|
|||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.verified-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 0.75rem;
|
||||
background: rgba(34, 197, 94, 0.15);
|
||||
border: 1px solid rgba(34, 197, 94, 0.3);
|
||||
color: #22c55e;
|
||||
font-size: 0.875rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.verified-banner-close {
|
||||
position: absolute;
|
||||
right: 0.5rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
color: #22c55e;
|
||||
font-size: 1.25rem;
|
||||
cursor: pointer;
|
||||
padding: 0.25rem;
|
||||
line-height: 1;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.verified-banner-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue