Fix: Deduplicate toast and add session dismissal

This commit is contained in:
gpt-engineer-app[bot]
2025-10-14 16:47:49 +00:00
parent 69c16c2b1e
commit 3c70579ac9
2 changed files with 42 additions and 2 deletions

View File

@@ -34,6 +34,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
// Refs for lifecycle and cleanup management // Refs for lifecycle and cleanup management
const novuUpdateTimeoutRef = useRef<NodeJS.Timeout | null>(null); const novuUpdateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const previousEmailRef = useRef<string | null>(null); const previousEmailRef = useRef<string | null>(null);
const orphanedPasswordToastShownRef = useRef(false);
// Verify session is still valid - simplified // Verify session is still valid - simplified
const verifySession = async () => { const verifySession = async () => {
@@ -98,6 +99,7 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
setUser(null); setUser(null);
setAal(null); setAal(null);
setLoading(false); setLoading(false);
orphanedPasswordToastShownRef.current = false;
return; return;
} }
@@ -115,6 +117,16 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
// Check for orphaned password on SIGNED_IN events // Check for orphaned password on SIGNED_IN events
if (event === 'SIGNED_IN' && session?.user) { if (event === 'SIGNED_IN' && session?.user) {
try { try {
// Import sessionFlags
const { isOrphanedPasswordDismissed, setOrphanedPasswordDismissed } =
await import('@/lib/sessionFlags');
// Skip if already shown in this auth cycle or dismissed this session
if (orphanedPasswordToastShownRef.current || isOrphanedPasswordDismissed()) {
authLog('[Auth] Skipping orphaned password toast - already shown or dismissed');
return;
}
// Import identityService functions // Import identityService functions
const { getUserIdentities, hasOrphanedPassword, triggerOrphanedPasswordConfirmation } = const { getUserIdentities, hasOrphanedPassword, triggerOrphanedPasswordConfirmation } =
await import('@/lib/identityService'); await import('@/lib/identityService');
@@ -128,12 +140,15 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
const isOrphaned = await hasOrphanedPassword(); const isOrphaned = await hasOrphanedPassword();
if (isOrphaned) { if (isOrphaned) {
// Mark as shown to prevent duplicates
orphanedPasswordToastShownRef.current = true;
// Show persistent toast with Resend button // Show persistent toast with Resend button
const { toast: sonnerToast } = await import('sonner'); const { toast: sonnerToast } = await import('sonner');
sonnerToast.warning("Password Activation Pending", { sonnerToast.warning("Password Activation Pending", {
description: "Your password needs email confirmation to be fully activated.", description: "Your password needs email confirmation to be fully activated.",
duration: Infinity, // Persistent until dismissed duration: Infinity,
action: { action: {
label: "Resend Email", label: "Resend Email",
onClick: async () => { onClick: async () => {
@@ -154,7 +169,10 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
}, },
cancel: { cancel: {
label: "Dismiss", label: "Dismiss",
onClick: () => {} // Allow dismissal onClick: () => {
setOrphanedPasswordDismissed();
authLog('[Auth] User dismissed orphaned password warning');
}
} }
}); });
} }

View File

@@ -7,6 +7,7 @@ export const SessionFlags = {
MFA_INTENDED_PATH: 'mfa_intended_path', MFA_INTENDED_PATH: 'mfa_intended_path',
MFA_CHALLENGE_ID: 'mfa_challenge_id', MFA_CHALLENGE_ID: 'mfa_challenge_id',
AUTH_METHOD: 'auth_method', AUTH_METHOD: 'auth_method',
ORPHANED_PASSWORD_DISMISSED: 'orphaned_password_dismissed',
} as const; } as const;
export type SessionFlagKey = typeof SessionFlags[keyof typeof SessionFlags]; export type SessionFlagKey = typeof SessionFlags[keyof typeof SessionFlags];
@@ -73,6 +74,27 @@ export function clearAuthMethod(): void {
sessionStorage.removeItem(SessionFlags.AUTH_METHOD); sessionStorage.removeItem(SessionFlags.AUTH_METHOD);
} }
/**
* Set the orphaned password dismissed flag
*/
export function setOrphanedPasswordDismissed(): void {
sessionStorage.setItem(SessionFlags.ORPHANED_PASSWORD_DISMISSED, 'true');
}
/**
* Check if orphaned password warning has been dismissed this session
*/
export function isOrphanedPasswordDismissed(): boolean {
return sessionStorage.getItem(SessionFlags.ORPHANED_PASSWORD_DISMISSED) === 'true';
}
/**
* Clear the orphaned password dismissed flag
*/
export function clearOrphanedPasswordDismissed(): void {
sessionStorage.removeItem(SessionFlags.ORPHANED_PASSWORD_DISMISSED);
}
/** /**
* Clear all authentication-related session flags * Clear all authentication-related session flags
*/ */