import { useState, useEffect, useRef } from 'react'; import { notify } from '@/lib/toast'; export type OzonetelState = 'ready' | 'break' | 'training' | 'calling' | 'in-call' | 'acw' | 'offline'; const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:4100'; export const useAgentState = (agentId: string | null): OzonetelState => { const [state, setState] = useState('offline'); const prevStateRef = useRef('offline'); const esRef = useRef(null); useEffect(() => { if (!agentId) { setState('offline'); return; } // Fetch current state on connect fetch(`${API_URL}/api/supervisor/agent-state?agentId=${agentId}`) .then(res => res.json()) .then(data => { if (data.state) { console.log(`[SSE] Initial state for ${agentId}: ${data.state}`); prevStateRef.current = data.state; setState(data.state); } }) .catch(() => {}); // Open SSE stream const url = `${API_URL}/api/supervisor/agent-state/stream?agentId=${agentId}`; console.log(`[SSE] Connecting: ${url}`); const es = new EventSource(url); esRef.current = es; es.onmessage = (event) => { try { const data = JSON.parse(event.data); console.log(`[SSE] State update: ${agentId} → ${data.state}`); // Force-logout: only triggered by explicit admin action, not normal Ozonetel logout if (data.state === 'force-logout') { console.log('[SSE] Force-logout received — clearing session'); notify.info('Session Ended', 'Your session was ended by an administrator.'); es.close(); localStorage.removeItem('helix_access_token'); localStorage.removeItem('helix_refresh_token'); localStorage.removeItem('helix_agent_config'); localStorage.removeItem('helix_user'); import('@/state/sip-manager').then(({ disconnectSip }) => disconnectSip()).catch(() => {}); setTimeout(() => { window.location.href = '/login'; }, 1500); return; } prevStateRef.current = data.state; setState(data.state); } catch { console.warn('[SSE] Failed to parse event:', event.data); } }; es.onerror = () => { console.warn('[SSE] Connection error — will auto-reconnect'); }; return () => { console.log('[SSE] Closing connection'); es.close(); esRef.current = null; }; }, [agentId]); return state; };