import { useState, useEffect } from 'react'; import { getStatsClient } from './useStatsApi'; import { SESSION_CHART_EVENT_TYPES } from '../lib/session-events'; import type { SessionSummary, SessionTimelinePoint, SessionEvent } from '../types/stats'; export function toErrorMessage(err: unknown): string { return err instanceof Error ? err.message : String(err); } export function useSessions(limit = 50) { const [sessions, setSessions] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; setLoading(true); setError(null); const client = getStatsClient(); client .getSessions(limit) .then((nextSessions) => { if (cancelled) return; setSessions(nextSessions); }) .catch((err) => { if (cancelled) return; setError(toErrorMessage(err)); }) .finally(() => { if (cancelled) return; setLoading(false); }); return () => { cancelled = true; }; }, [limit]); return { sessions, loading, error }; } export interface KnownWordsTimelinePoint { linesSeen: number; knownWordsSeen: number; } export function useSessionDetail(sessionId: number | null) { const [timeline, setTimeline] = useState([]); const [events, setEvents] = useState([]); const [knownWordsTimeline, setKnownWordsTimeline] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; setError(null); if (sessionId == null) { setTimeline([]); setEvents([]); setKnownWordsTimeline([]); setLoading(false); return () => { cancelled = true; }; } setLoading(true); setTimeline([]); setEvents([]); setKnownWordsTimeline([]); const client = getStatsClient(); Promise.all([ client.getSessionTimeline(sessionId), client.getSessionEvents(sessionId, 500, [...SESSION_CHART_EVENT_TYPES]), client.getSessionKnownWordsTimeline(sessionId), ]) .then(([nextTimeline, nextEvents, nextKnownWords]) => { if (cancelled) return; setTimeline(nextTimeline); setEvents(nextEvents); setKnownWordsTimeline(nextKnownWords); }) .catch((err) => { if (cancelled) return; setError(toErrorMessage(err)); }) .finally(() => { if (cancelled) return; setLoading(false); }); return () => { cancelled = true; }; }, [sessionId]); return { timeline, events, knownWordsTimeline, loading, error }; }