mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 15:11:13 -05:00
Fix: Correct provider hierarchy and simplify auth
This commit is contained in:
@@ -61,8 +61,8 @@ const queryClient = new QueryClient({
|
|||||||
function AppContent() {
|
function AppContent() {
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<LocationAutoDetectProvider />
|
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<LocationAutoDetectProvider />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<Sonner />
|
<Sonner />
|
||||||
<div className="min-h-screen flex flex-col">
|
<div className="min-h-screen flex flex-col">
|
||||||
|
|||||||
@@ -31,13 +31,8 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
// Refs for lifecycle and cleanup management
|
// Refs for lifecycle and cleanup management
|
||||||
const isMountedRef = useRef(true);
|
const isMountedRef = useRef(true);
|
||||||
const profileFetchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
const profileFetchTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const profileRetryCountRef = useRef(0);
|
|
||||||
const sessionVerifiedRef = useRef(false);
|
|
||||||
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 loadingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
const loadingStateRef = useRef(loading);
|
|
||||||
const lastVisibilityVerificationRef = useRef<number>(Date.now());
|
|
||||||
|
|
||||||
const fetchProfile = async (userId: string) => {
|
const fetchProfile = async (userId: string) => {
|
||||||
try {
|
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) => {
|
const verifySession = async (updateLoadingState = false) => {
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
|
||||||
setLoading(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data: { session }, error } = await supabase.auth.getSession();
|
const { data: { session }, error } = await supabase.auth.getSession();
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
authError('[Auth] Session verification failed:', error);
|
authError('[Auth] Session verification failed:', error);
|
||||||
setSessionError(error.message);
|
setSessionError(error.message);
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
authLog('[Auth] No active session found');
|
authLog('[Auth] No active session found');
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
authLog('[Auth] Session verified:', session.user.email);
|
authLog('[Auth] Session verified:', session.user.email);
|
||||||
sessionVerifiedRef.current = true;
|
|
||||||
|
|
||||||
// Update state if session was found but not set
|
// Update state if session was found but not set
|
||||||
if (!user && isMountedRef.current) {
|
if (!user && isMountedRef.current) {
|
||||||
setSession(session);
|
setSession(session);
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
sessionVerifiedRef.current = true;
|
|
||||||
} else if (updateLoadingState && isMountedRef.current) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
authError('[Auth] Session verification error:', error);
|
authError('[Auth] Session verification error:', error);
|
||||||
if (updateLoadingState && isMountedRef.current) {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Keep loading state ref in sync
|
|
||||||
useEffect(() => {
|
|
||||||
loadingStateRef.current = loading;
|
|
||||||
authLog('[Auth] Loading state changed:', loading);
|
|
||||||
}, [loading]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
authLog('[Auth] Initializing auth provider');
|
authLog('[Auth] Initializing auth provider');
|
||||||
|
|
||||||
@@ -153,35 +125,31 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
// Update session and user state based on event
|
// Update session and user state based on event
|
||||||
if (event === 'SIGNED_IN' && session) {
|
if (event === 'SIGNED_IN' && session) {
|
||||||
authLog('[Auth] SIGNED_IN detected, setting session and user');
|
authLog('[Auth] SIGNED_IN - user authenticated');
|
||||||
setSession(session);
|
setSession(session);
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
sessionVerifiedRef.current = true;
|
setLoading(false);
|
||||||
setLoading(false); // Resolved - user exists
|
|
||||||
} else if (event === 'INITIAL_SESSION') {
|
} else if (event === 'INITIAL_SESSION') {
|
||||||
if (session?.user) {
|
if (session?.user) {
|
||||||
authLog('[Auth] INITIAL_SESSION with user, setting session');
|
authLog('[Auth] INITIAL_SESSION - user exists');
|
||||||
setSession(session);
|
setSession(session);
|
||||||
setUser(session.user);
|
setUser(session.user);
|
||||||
sessionVerifiedRef.current = true;
|
setLoading(false);
|
||||||
setLoading(false); // Resolved - user exists
|
|
||||||
} else {
|
} else {
|
||||||
authLog('[Auth] INITIAL_SESSION with no user - setting loading to false');
|
authLog('[Auth] INITIAL_SESSION - no user');
|
||||||
setSession(null);
|
setSession(null);
|
||||||
setUser(null);
|
setUser(null);
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
sessionVerifiedRef.current = false;
|
setLoading(false);
|
||||||
setLoading(false); // Resolved - no user
|
return;
|
||||||
return; // Exit early, no need to fetch profile
|
|
||||||
}
|
}
|
||||||
} else if (event === 'SIGNED_OUT') {
|
} else if (event === 'SIGNED_OUT') {
|
||||||
authLog('[Auth] SIGNED_OUT detected, clearing all state');
|
authLog('[Auth] SIGNED_OUT - clearing state');
|
||||||
setSession(null);
|
setSession(null);
|
||||||
setUser(null);
|
setUser(null);
|
||||||
setProfile(null);
|
setProfile(null);
|
||||||
sessionVerifiedRef.current = false;
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return; // Exit early, no need to fetch profile
|
return;
|
||||||
} else {
|
} else {
|
||||||
setSession(session);
|
setSession(session);
|
||||||
setUser(session?.user ?? null);
|
setUser(session?.user ?? null);
|
||||||
@@ -279,57 +247,10 @@ function AuthProviderComponent({ children }: { children: React.ReactNode }) {
|
|||||||
authLog('[Auth] getSession completed, session exists:', !!session);
|
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 () => {
|
return () => {
|
||||||
authLog('[Auth] Cleaning up auth provider');
|
authLog('[Auth] Cleaning up auth provider');
|
||||||
isMountedRef.current = false;
|
isMountedRef.current = false;
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
clearTimeout(verificationTimeout);
|
|
||||||
if (loadingTimeoutRef.current) {
|
|
||||||
clearTimeout(loadingTimeoutRef.current);
|
|
||||||
}
|
|
||||||
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
||||||
|
|
||||||
// Clear any pending timeouts
|
// Clear any pending timeouts
|
||||||
if (profileFetchTimeoutRef.current) {
|
if (profileFetchTimeoutRef.current) {
|
||||||
|
|||||||
Reference in New Issue
Block a user