import React, { useState, useEffect, useCallback } from 'react'; import { useAuth } from '../context/AuthContext'; import { useToast } from '../components/Toast'; import api from '../api/axios'; import { formatLocalDateTime, formatLocalDate, formatLocalTime } from '../utils/dateUtils'; import PopularityBadge from '../components/PopularityBadge'; function History() { const { isAuthenticated } = useAuth(); const { error, success } = useToast(); const [sessions, setSessions] = useState([]); const [selectedSession, setSelectedSession] = useState(null); const [sessionGames, setSessionGames] = useState([]); const [loading, setLoading] = useState(true); const [showChatImport, setShowChatImport] = useState(false); const [closingSession, setClosingSession] = useState(null); const [showAllSessions, setShowAllSessions] = useState(false); const [deletingSession, setDeletingSession] = useState(null); const loadSessions = useCallback(async () => { try { const response = await api.get('/sessions'); setSessions(response.data); } catch (err) { console.error('Failed to load sessions', err); } finally { setLoading(false); } }, []); const refreshSessionGames = useCallback(async (sessionId, silent = false) => { try { const response = await api.get(`/sessions/${sessionId}/games`); // Reverse chronological order (most recent first) setSessionGames(response.data.reverse()); } catch (err) { if (!silent) { console.error('Failed to load session games', err); } } }, []); useEffect(() => { loadSessions(); }, [loadSessions]); // Auto-select active session if navigating from picker useEffect(() => { if (sessions.length > 0 && !selectedSession) { const activeSession = sessions.find(s => s.is_active === 1); if (activeSession) { loadSessionGames(activeSession.id); } } }, [sessions, selectedSession]); // Poll for session list updates (to detect when sessions end/start) useEffect(() => { const interval = setInterval(() => { loadSessions(); }, 3000); return () => clearInterval(interval); }, [loadSessions]); // Poll for updates on active session games useEffect(() => { if (!selectedSession) return; const currentSession = sessions.find(s => s.id === selectedSession); if (!currentSession || currentSession.is_active !== 1) return; // Refresh games every 3 seconds for active session const interval = setInterval(() => { refreshSessionGames(selectedSession, true); // silent refresh }, 3000); return () => clearInterval(interval); }, [selectedSession, sessions, refreshSessionGames]); const handleExport = async (sessionId, format) => { try { const response = await api.get(`/sessions/${sessionId}/export?format=${format}`, { responseType: 'blob' }); // Create download link const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `session-${sessionId}.${format === 'json' ? 'json' : 'txt'}`); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); window.URL.revokeObjectURL(url); success(`Session exported as ${format.toUpperCase()}`); } catch (err) { console.error('Failed to export session', err); error('Failed to export session'); } }; const loadSessionGames = async (sessionId, silent = false) => { try { const response = await api.get(`/sessions/${sessionId}/games`); setSessionGames(response.data); if (!silent) { setSelectedSession(sessionId); } } catch (err) { if (!silent) { console.error('Failed to load session games', err); } } }; const handleCloseSession = async (sessionId, notes) => { try { await api.post(`/sessions/${sessionId}/close`, { notes }); await loadSessions(); setClosingSession(null); if (selectedSession === sessionId) { // Reload the session details to show updated state loadSessionGames(sessionId); } success('Session ended successfully'); } catch (err) { error('Failed to close session'); } }; const handleDeleteSession = async (sessionId) => { try { await api.delete(`/sessions/${sessionId}`); await loadSessions(); setDeletingSession(null); if (selectedSession === sessionId) { setSelectedSession(null); setSessionGames([]); } success('Session deleted successfully'); } catch (err) { error('Failed to delete session: ' + (err.response?.data?.error || err.message)); } }; if (loading) { return (
Loading...
); } return (

Session History

{/* Sessions List */}

Sessions

{sessions.length > 3 && ( )}
{sessions.length === 0 ? (

No sessions found

) : (
{(showAllSessions ? sessions : sessions.slice(0, 3)).map(session => (
{/* Main session info - clickable */}
loadSessionGames(session.id)} className="p-3 cursor-pointer" >
Session #{session.id} {session.is_active === 1 && ( Active )}
{formatLocalDate(session.created_at)} {session.games_played} game{session.games_played !== 1 ? 's' : ''}
{/* Action buttons for authenticated users */} {isAuthenticated && (
{session.is_active === 1 ? ( ) : ( )}
)}
))}
)}
{/* Session Details */}
{selectedSession ? (

Session #{selectedSession}

{sessions.find(s => s.id === selectedSession)?.is_active === 1 && ( 🟢 Active )}

{sessions.find(s => s.id === selectedSession)?.created_at && formatLocalDateTime(sessions.find(s => s.id === selectedSession).created_at)}

{sessions.find(s => s.id === selectedSession)?.is_active === 1 && (

Games update automatically

)}
{isAuthenticated && sessions.find(s => s.id === selectedSession)?.is_active === 1 && ( )} {isAuthenticated && ( <> )}
{showChatImport && ( setShowChatImport(false)} onImportComplete={() => { loadSessionGames(selectedSession); setShowChatImport(false); }} /> )} {sessionGames.length === 0 ? (

No games played in this session

) : (

Games Played ({sessionGames.length})

{[...sessionGames].reverse().map((game, index) => (
{sessionGames.length - index}. {game.title}
{game.pack_name}
{formatLocalTime(game.played_at)}
{game.manually_added === 1 && ( Manual )}
Players: {game.min_players}-{game.max_players}
Type: {game.game_type || 'N/A'}
Popularity:
))}
)}
) : (

Select a session to view details

)}
{/* End Session Modal */} {closingSession && ( setClosingSession(null)} onConfirm={handleCloseSession} onShowChatImport={() => { setShowChatImport(true); if (closingSession !== selectedSession) { loadSessionGames(closingSession); } }} /> )} {/* Delete Confirmation Modal */} {deletingSession && (

Delete Session?

Are you sure you want to delete Session #{deletingSession}? This will permanently delete all games and chat logs associated with this session. This action cannot be undone.

)}
); } function EndSessionModal({ sessionId, sessionGames, onClose, onConfirm, onShowChatImport }) { const [notes, setNotes] = useState(''); // Check if any games have been voted on (popularity != 0) const hasPopularityData = sessionGames.some(game => game.popularity_score !== 0); const showPopularityWarning = sessionGames.length > 0 && !hasPopularityData; return (

End Session #{sessionId}

{/* Popularity Warning */} {showPopularityWarning && (
⚠️

No Popularity Data

You haven't imported chat reactions yet. Import now to track which games your players loved!

)}