fix(auth): prevent concurrent dispatch deadlocks and add timeout to UserContext

This commit is contained in:
marciobever 2026-04-22 15:21:33 -03:00
parent 6640162d4d
commit 8502a82b5a

View file

@ -87,13 +87,30 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
useEffect(() => { useEffect(() => {
let mounted = true; let mounted = true;
let isFetching = false; // Prevent concurrent deadlocks
const handleSession = async (session: any) => { const handleSession = async (session: any) => {
if (isFetching) return;
isFetching = true;
if (session?.user) { 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<void>((_, 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 { } else {
setUser(null); setUser(null);
setLoading(false); if (mounted) setLoading(false);
isFetching = false;
} }
}; };
@ -110,21 +127,20 @@ export const UserProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
setIsAdminView(false); setIsAdminView(false);
setIsProfessionalView(false); setIsProfessionalView(false);
setIsCompletingProfile(false); setIsCompletingProfile(false);
setLoading(false); if (mounted) setLoading(false);
isFetching = false;
} }
}); });
// Initialize session manually in case INITIAL_SESSION doesn't trigger // Fallback for when "INITIAL_SESSION" gets completely skipped by Supabase JS on load
// (sometimes needed depending on supabase-js version and local storage state)
supabase.auth.getSession().then(({ data: { session }, error }) => { supabase.auth.getSession().then(({ data: { session }, error }) => {
if (error) { if (error) {
console.error("UserContext: Falha na sessão inicial", error); console.error("UserContext: Falha na sessão inicial", error);
if (mounted) setLoading(false); if (mounted) setLoading(false);
} else if (session) { } 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); handleSession(session);
} else { } else {
// Se não há sessão e onAuthStateChange não disparou INITIAL_SESSION
if (mounted) setLoading(false); if (mounted) setLoading(false);
} }
}); });