mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 13:31:12 -05:00
Fix: Deduplicate toast and add session dismissal
This commit is contained in:
@@ -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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user