diff --git a/src/contexts/UserContext.tsx b/src/contexts/UserContext.tsx index acc23f9..a5de4c8 100644 --- a/src/contexts/UserContext.tsx +++ b/src/contexts/UserContext.tsx @@ -87,13 +87,30 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) => useEffect(() => { let mounted = true; + let isFetching = false; // Prevent concurrent deadlocks const handleSession = async (session: any) => { + if (isFetching) return; + isFetching = true; + if (session?.user) { - await fetchUserProfile(session.user.id, session.user.email); + // Promise.race to guarantee we escape infinite loading if Supabase POST/GET hangs + const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("DB Timeout")), 8000)); + try { + await Promise.race([ + fetchUserProfile(session.user.id, session.user.email), + timeout + ]); + } catch (e) { + console.error("UserContext HandleSession Error:", e); + if (mounted) setLoading(false); + } finally { + isFetching = false; + } } else { setUser(null); - setLoading(false); + if (mounted) setLoading(false); + isFetching = false; } }; @@ -110,21 +127,20 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) => setIsAdminView(false); setIsProfessionalView(false); setIsCompletingProfile(false); - setLoading(false); + if (mounted) setLoading(false); + isFetching = false; } }); - // Initialize session manually in case INITIAL_SESSION doesn't trigger - // (sometimes needed depending on supabase-js version and local storage state) + // Fallback for when "INITIAL_SESSION" gets completely skipped by Supabase JS on load supabase.auth.getSession().then(({ data: { session }, error }) => { if (error) { console.error("UserContext: Falha na sessão inicial", error); if (mounted) setLoading(false); } else if (session) { - // Handled gracefully: forces profile fetch if session exists but events failed + // If there's a session but events haven't fired or were skipped, gently process it handleSession(session); } else { - // Se não há sessão e onAuthStateChange não disparou INITIAL_SESSION if (mounted) setLoading(false); } });