import { useState, useEffect } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from './useAuth'; import { logger } from '@/utils/logger'; interface SessionLog { id: string; user_id: string; session_start: string; session_end: string | null; duration_minutes: number | null; ip_address: string | null; user_agent: string | null; is_active: boolean; created_at: string; updated_at: string; } interface OnlineUser { user_id: string; email: string; full_name: string; avatar_url: string; session_start: string; } interface SessionStats { total_sessions: number; total_users: number; average_duration: number; active_sessions: number; } export const useSessionLogs = () => { const [sessionLogs, setSessionLogs] = useState([]); const [onlineUsers, setOnlineUsers] = useState([]); const [sessionStats, setSessionStats] = useState(null); const [loading, setLoading] = useState(false); const [currentSessionId, setCurrentSessionId] = useState(null); const { user } = useAuth(); // Iniciar sessão quando o usuário faz login const startSession = async () => { if (!user) return; try { logger.info('Starting user session'); // Finalizar sessões ativas anteriores (caso houve falha no logout) await supabase .from('user_session_logs') .update({ is_active: false, session_end: new Date().toISOString(), duration_minutes: 0 }) .eq('user_id', user.id) .eq('is_active', true); // Criar nova sessão const { data, error } = await supabase .from('user_session_logs') .insert({ user_id: user.id, ip_address: null, // Pode ser obtido do frontend se necessário user_agent: navigator.userAgent, is_active: true }) .select() .single(); if (error) { logger.error('Error starting session:', error); throw error; } setCurrentSessionId(data.id); // Armazenar ID da sessão no localStorage para persistência localStorage.setItem('currentSessionId', data.id); logger.success('Session started successfully'); } catch (error) { logger.error('Erro ao iniciar sessão:', error); } }; // Finalizar sessão quando o usuário faz logout const endSession = async () => { const sessionId = currentSessionId || localStorage.getItem('currentSessionId'); if (!sessionId) return; try { logger.info('Ending user session'); await supabase.rpc('end_user_session', { session_id: sessionId }); setCurrentSessionId(null); localStorage.removeItem('currentSessionId'); logger.success('Session ended successfully'); } catch (error) { logger.error('Erro ao finalizar sessão:', error); } }; // Buscar logs de sessão const fetchSessionLogs = async (filters?: { userId?: string; startDate?: string; endDate?: string; }) => { setLoading(true); try { logger.info('Fetching session logs with filters:', filters); let query = supabase .from('user_session_logs') .select('*') .order('session_start', { ascending: false }); if (filters?.userId) { query = query.eq('user_id', filters.userId); } if (filters?.startDate) { query = query.gte('session_start', filters.startDate); } if (filters?.endDate) { query = query.lte('session_start', filters.endDate); } const { data, error } = await query; if (error) { logger.error('Error fetching session logs:', error); throw error; } setSessionLogs(data as SessionLog[] || []); logger.success('Session logs fetched successfully'); } catch (error) { logger.error('Erro ao buscar logs de sessão:', error); } finally { setLoading(false); } }; // Buscar usuários online const fetchOnlineUsers = async () => { try { logger.info('Fetching online users'); const { data, error } = await supabase.rpc('get_online_users'); if (error) { logger.error('Error fetching online users:', error); throw error; } setOnlineUsers(data || []); logger.success('Online users fetched successfully'); } catch (error) { logger.error('Erro ao buscar usuários online:', error); } }; // Buscar estatísticas de sessão const fetchSessionStats = async (filters?: { userId?: string; period?: 'day' | 'week' | 'month'; }) => { try { logger.info('Fetching session stats with filters:', filters); let query = supabase .from('user_session_logs') .select('*'); if (filters?.userId) { query = query.eq('user_id', filters.userId); } // Filtrar por período if (filters?.period) { const now = new Date(); let startDate; switch (filters.period) { case 'day': startDate = new Date(now.setDate(now.getDate() - 1)); break; case 'week': startDate = new Date(now.setDate(now.getDate() - 7)); break; case 'month': startDate = new Date(now.setMonth(now.getMonth() - 1)); break; } if (startDate) { query = query.gte('session_start', startDate.toISOString()); } } const { data, error } = await query; if (error) { logger.error('Error fetching session stats:', error); throw error; } const stats: SessionStats = { total_sessions: data?.length || 0, total_users: new Set(data?.map(log => log.user_id)).size || 0, average_duration: data?.reduce((acc, log) => acc + (log.duration_minutes || 0), 0) / (data?.length || 1) || 0, active_sessions: data?.filter(log => log.is_active).length || 0 }; setSessionStats(stats); logger.success('Session stats fetched successfully'); } catch (error) { logger.error('Erro ao buscar estatísticas:', error); } }; // Exportar relatório const exportReport = async (format: 'csv' | 'json', filters?: { userId?: string; startDate?: string; endDate?: string; }) => { try { logger.info(`Exporting report in ${format} format`); let query = supabase .from('user_session_logs') .select('*') .order('session_start', { ascending: false }); if (filters?.userId) { query = query.eq('user_id', filters.userId); } if (filters?.startDate) { query = query.gte('session_start', filters.startDate); } if (filters?.endDate) { query = query.lte('session_start', filters.endDate); } const { data, error } = await query; if (error) { logger.error('Error exporting report:', error); throw error; } // Buscar informações dos usuários separadamente const userIds = Array.from(new Set(data?.map(log => log.user_id) || [])); const { data: users } = await supabase .from('profiles') .select('id, email, full_name') .in('id', userIds); const userMap = new Map(users?.map(user => [user.id, user]) || []); if (format === 'csv') { const csv = [ 'Email,Nome,Início da Sessão,Fim da Sessão,Duração (min),Status', ...(data || []).map(log => { const user = userMap.get(log.user_id); return `${user?.email || ''},${user?.full_name || ''},${log.session_start},${log.session_end || ''},${log.duration_minutes || ''},${log.is_active ? 'Ativa' : 'Finalizada'}`; }) ].join('\n'); const blob = new Blob([csv], { type: 'text/csv' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `relatorio-sessoes-${new Date().toISOString().split('T')[0]}.csv`; a.click(); URL.revokeObjectURL(url); } else { const enrichedData = data?.map(log => ({ ...log, user_info: userMap.get(log.user_id) })); const json = JSON.stringify(enrichedData, null, 2); const blob = new Blob([json], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `relatorio-sessoes-${new Date().toISOString().split('T')[0]}.json`; a.click(); URL.revokeObjectURL(url); } logger.success('Report exported successfully'); } catch (error) { logger.error('Erro ao exportar relatório:', error); } }; // Atualizar automaticamente usuários online e fazer heartbeat da sessão useEffect(() => { fetchOnlineUsers(); 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) .then(({ error }) => { if (error) console.error('Heartbeat error:', error); }); } }, 30000); // Atualizar a cada 30 segundos return () => clearInterval(interval); }, [currentSessionId]); // Gerenciar sessão baseado no estado de autenticação useEffect(() => { if (user && !currentSessionId && !localStorage.getItem('currentSessionId')) { startSession(); } else if (!user && currentSessionId) { endSession(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [user]); // Finalizar sessão quando a janela é fechada useEffect(() => { const handleBeforeUnload = () => { const sessionId = currentSessionId || localStorage.getItem('currentSessionId'); if (sessionId) { // Para navegadores modernos, usar navigator.sendBeacon se disponível if (navigator.sendBeacon) { const payload = JSON.stringify({ session_id: sessionId }); navigator.sendBeacon('/api/end-session', payload); } } }; window.addEventListener('beforeunload', handleBeforeUnload); return () => window.removeEventListener('beforeunload', handleBeforeUnload); }, [currentSessionId]); return { sessionLogs, onlineUsers, sessionStats, loading, currentSessionId, startSession, endSession, fetchSessionLogs, fetchOnlineUsers, fetchSessionStats, exportReport }; };