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(() => {
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<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 {
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);
}
});