mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 16:31:13 -05:00
Fix: Correct provider hierarchy and simplify auth
This commit is contained in:
@@ -31,13 +31,8 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
||||
// Refs for lifecycle and cleanup management
|
||||
const isMountedRef = useRef(true);
|
||||
const profileFetchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const profileRetryCountRef = useRef(0);
|
||||
const sessionVerifiedRef = useRef(false);
|
||||
const novuUpdateTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const previousEmailRef = useRef<string | null>(null);
|
||||
const loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const loadingStateRef = useRef(loading);
|
||||
const lastVisibilityVerificationRef = useRef<number>(Date.now());
|
||||
|
||||
const fetchProfile = async (userId: string) => {
|
||||
try {
|
||||
@@ -78,60 +73,37 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
};
|
||||
|
||||
// Verify session is still valid
|
||||
// Verify session is still valid - simplified
|
||||
const verifySession = async (updateLoadingState = false) => {
|
||||
if (updateLoadingState && isMountedRef.current) {
|
||||
setLoading(true);
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: { session }, error } = await supabase.auth.getSession();
|
||||
|
||||
if (error) {
|
||||
authError('[Auth] Session verification failed:', error);
|
||||
setSessionError(error.message);
|
||||
if (updateLoadingState && isMountedRef.current) {
|
||||
setLoading(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
authLog('[Auth] No active session found');
|
||||
if (updateLoadingState && isMountedRef.current) {
|
||||
setLoading(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
authLog('[Auth] Session verified:', session.user.email);
|
||||
sessionVerifiedRef.current = true;
|
||||
|
||||
// Update state if session was found but not set
|
||||
if (!user && isMountedRef.current) {
|
||||
setSession(session);
|
||||
setUser(session.user);
|
||||
sessionVerifiedRef.current = true;
|
||||
} else if (updateLoadingState && isMountedRef.current) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
authError('[Auth] Session verification error:', error);
|
||||
if (updateLoadingState && isMountedRef.current) {
|
||||
setLoading(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Keep loading state ref in sync
|
||||
useEffect(() => {
|
||||
loadingStateRef.current = loading;
|
||||
authLog('[Auth] Loading state changed:', loading);
|
||||
}, [loading]);
|
||||
|
||||
useEffect(() => {
|
||||
authLog('[Auth] Initializing auth provider');
|
||||
|
||||
@@ -153,35 +125,31 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
||||
|
||||
// Update session and user state based on event
|
||||
if (event === 'SIGNED_IN' && session) {
|
||||
authLog('[Auth] SIGNED_IN detected, setting session and user');
|
||||
authLog('[Auth] SIGNED_IN - user authenticated');
|
||||
setSession(session);
|
||||
setUser(session.user);
|
||||
sessionVerifiedRef.current = true;
|
||||
setLoading(false); // Resolved - user exists
|
||||
setLoading(false);
|
||||
} else if (event === 'INITIAL_SESSION') {
|
||||
if (session?.user) {
|
||||
authLog('[Auth] INITIAL_SESSION with user, setting session');
|
||||
authLog('[Auth] INITIAL_SESSION - user exists');
|
||||
setSession(session);
|
||||
setUser(session.user);
|
||||
sessionVerifiedRef.current = true;
|
||||
setLoading(false); // Resolved - user exists
|
||||
setLoading(false);
|
||||
} else {
|
||||
authLog('[Auth] INITIAL_SESSION with no user - setting loading to false');
|
||||
authLog('[Auth] INITIAL_SESSION - no user');
|
||||
setSession(null);
|
||||
setUser(null);
|
||||
setProfile(null);
|
||||
sessionVerifiedRef.current = false;
|
||||
setLoading(false); // Resolved - no user
|
||||
return; // Exit early, no need to fetch profile
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
} else if (event === 'SIGNED_OUT') {
|
||||
authLog('[Auth] SIGNED_OUT detected, clearing all state');
|
||||
authLog('[Auth] SIGNED_OUT - clearing state');
|
||||
setSession(null);
|
||||
setUser(null);
|
||||
setProfile(null);
|
||||
sessionVerifiedRef.current = false;
|
||||
setLoading(false);
|
||||
return; // Exit early, no need to fetch profile
|
||||
return;
|
||||
} else {
|
||||
setSession(session);
|
||||
setUser(session?.user ?? null);
|
||||
@@ -279,57 +247,10 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
||||
authLog('[Auth] getSession completed, session exists:', !!session);
|
||||
});
|
||||
|
||||
// Add a STRONG safety timeout to force loading to resolve
|
||||
loadingTimeoutRef.current = setTimeout(() => {
|
||||
if (loadingStateRef.current) {
|
||||
authWarn('[Auth] ⚠️ SAFETY TIMEOUT: Forcing loading to false after 3 seconds');
|
||||
setLoading(false);
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// Session verification fallback
|
||||
const verificationTimeout = setTimeout(() => {
|
||||
if (!sessionVerifiedRef.current) {
|
||||
authLog('[Auth] Session not verified after 2s, attempting manual verification');
|
||||
verifySession();
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
// Handle page visibility changes - only verify if inactive for >5 minutes
|
||||
const handleVisibilityChange = () => {
|
||||
const timeSinceLastCheck = Date.now() - lastVisibilityVerificationRef.current;
|
||||
const FIVE_MINUTES = 5 * 60 * 1000;
|
||||
|
||||
console.log('🔐 [AUTH] Visibility changed', {
|
||||
state: document.visibilityState,
|
||||
timeSinceLastCheck: Math.round(timeSinceLastCheck / 1000) + 's',
|
||||
willVerifySession: document.visibilityState === 'visible' && timeSinceLastCheck > FIVE_MINUTES
|
||||
});
|
||||
|
||||
if (document.visibilityState === 'visible') {
|
||||
if (timeSinceLastCheck > FIVE_MINUTES) {
|
||||
authLog('[Auth] Tab visible after 5+ minutes, verifying session');
|
||||
console.log(' ⚠️ Verifying session - this may cause component re-renders');
|
||||
lastVisibilityVerificationRef.current = Date.now();
|
||||
verifySession();
|
||||
} else {
|
||||
authLog('[Auth] Tab visible, session recently verified, skipping');
|
||||
console.log(' ✅ Session recently verified, skipping verification');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
return () => {
|
||||
authLog('[Auth] Cleaning up auth provider');
|
||||
isMountedRef.current = false;
|
||||
subscription.unsubscribe();
|
||||
clearTimeout(verificationTimeout);
|
||||
if (loadingTimeoutRef.current) {
|
||||
clearTimeout(loadingTimeoutRef.current);
|
||||
}
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
||||
|
||||
// Clear any pending timeouts
|
||||
if (profileFetchTimeoutRef.current) {
|
||||
|
||||
Reference in New Issue
Block a user