Fix: Correct provider hierarchy and simplify auth

This commit is contained in:
gpt-engineer-app[bot]
2025-10-13 17:09:45 +00:00
parent 083964ff41
commit 7d6c0aabcf
2 changed files with 13 additions and 92 deletions

View File

@@ -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) {