fix(auth): adiciona heartbeat global e previne multi-sessoes acumluadas no painel

This commit is contained in:
2026-08-13 21:11:57 +00:00
parent 938f22a423
commit ad00e3b65d
2 changed files with 38 additions and 8 deletions
+22 -4
View File
@@ -140,6 +140,13 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const shouldSkipLogging = await isAdminOrDeveloper(userId);
if (shouldSkipLogging) return;
// Desativar qualquer sessão antiga que ficou presa (fechar abas sem logout)
await supabase
.from('user_session_logs')
.update({ is_active: false, session_end: new Date().toISOString() })
.eq('user_id', userId)
.eq('is_active', true);
const { data, error } = await supabase
.from('user_session_logs')
.insert({
@@ -225,11 +232,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
if (mounted) {
setAuthInitialized(true);
setUserOnline(session.user.id);
const existingSessionId = localStorage.getItem('currentSessionId');
if (!existingSessionId) {
// Sempre cria uma nova sessão, resetando contadores anteriores
startSessionLog(session.user.id);
}
}
}, 100);
} else if (mounted) {
setSession(null);
@@ -282,12 +287,25 @@ export function AuthProvider({ children }: { children: ReactNode }) {
if (user && authInitialized) {
cleanupInterval = setInterval(async () => {
// Enviar Heartbeat global da sessão (mantém o usuário online de fato)
const sessionId = localStorage.getItem('currentSessionId');
if (sessionId) {
try {
await supabase
.from('user_session_logs')
.update({ updated_at: new Date().toISOString() })
.eq('id', sessionId);
} catch (e) {
console.error('Falha no heartbeat da sessão', e);
}
}
try {
await supabase.rpc('cleanup_offline_users');
} catch {
// Ignora se RPC não existir
}
}, 60000);
}, 30000); // 30 segundos
const handleBeforeUnload = () => {
if (user) {
+15 -3
View File
@@ -296,12 +296,24 @@ export const useSessionLogs = () => {
}
};
// Atualizar automaticamente usuários online
// Atualizar automaticamente usuários online e fazer heartbeat da sessão
useEffect(() => {
fetchOnlineUsers();
const interval = setInterval(fetchOnlineUsers, 30000); // Atualizar a cada 30 segundos
const interval = setInterval(() => {
fetchOnlineUsers();
const sessionId = currentSessionId || localStorage.getItem('currentSessionId');
if (sessionId) {
// Heartbeat pings database every 30s to keep session alive
supabase
.from('user_session_logs')
.update({ updated_at: new Date().toISOString() })
.eq('id', sessionId)
.catch(console.error);
}
}, 30000); // Atualizar a cada 30 segundos
return () => clearInterval(interval);
}, []);
}, [currentSessionId]);
// Gerenciar sessão baseado no estado de autenticação
useEffect(() => {