import { useEffect, useMemo, useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faHeadset } from '@fortawesome/pro-duotone-svg-icons'; import { TopBar } from '@/components/layout/top-bar'; import { Badge } from '@/components/base/badges/badges'; import { Button } from '@/components/base/buttons/button'; import { Table } from '@/components/application/table/table'; import { apiClient } from '@/lib/api-client'; import { useData } from '@/providers/data-provider'; type ActiveCall = { ucid: string; agentId: string; callerNumber: string; callType: string; startTime: string; status: 'active' | 'on-hold'; }; const formatDuration = (startTime: string): string => { const seconds = Math.max(0, Math.floor((Date.now() - new Date(startTime).getTime()) / 1000)); const m = Math.floor(seconds / 60); const s = seconds % 60; return `${m}:${s.toString().padStart(2, '0')}`; }; const KpiCard = ({ value, label }: { value: string | number; label: string }) => (

{value}

{label}

); export const LiveMonitorPage = () => { const [activeCalls, setActiveCalls] = useState([]); const [loading, setLoading] = useState(true); const [tick, setTick] = useState(0); const { leads } = useData(); // Poll active calls every 5 seconds useEffect(() => { const fetchCalls = () => { apiClient.get('/api/supervisor/active-calls', { silent: true }) .then(setActiveCalls) .catch(() => {}) .finally(() => setLoading(false)); }; fetchCalls(); const interval = setInterval(fetchCalls, 5000); return () => clearInterval(interval); }, []); // Tick every second to update duration counters useEffect(() => { const interval = setInterval(() => setTick(t => t + 1), 1000); return () => clearInterval(interval); }, []); const onHold = activeCalls.filter(c => c.status === 'on-hold').length; const avgDuration = useMemo(() => { if (activeCalls.length === 0) return '0:00'; const totalSec = activeCalls.reduce((sum, c) => { return sum + Math.max(0, Math.floor((Date.now() - new Date(c.startTime).getTime()) / 1000)); }, 0); const avg = Math.floor(totalSec / activeCalls.length); return `${Math.floor(avg / 60)}:${(avg % 60).toString().padStart(2, '0')}`; }, [activeCalls, tick]); // Match caller to lead const resolveCallerName = (phone: string): string | null => { if (!phone) return null; const clean = phone.replace(/\D/g, ''); const lead = leads.find(l => { const lp = (l.contactPhone?.[0]?.number ?? '').replace(/\D/g, ''); return lp && (lp.endsWith(clean) || clean.endsWith(lp)); }); if (lead) { return `${lead.contactName?.firstName ?? ''} ${lead.contactName?.lastName ?? ''}`.trim() || null; } return null; }; return ( <>
{/* KPI Cards */}
{/* Active Calls Table */}

Active Calls

{loading ? (

Loading...

) : activeCalls.length === 0 ? (

No active calls

Active calls will appear here in real-time

) : ( {(call) => { const callerName = resolveCallerName(call.callerNumber); const typeLabel = call.callType === 'InBound' ? 'In' : 'Out'; const typeColor = call.callType === 'InBound' ? 'blue' : 'brand'; return ( {call.agentId}
{callerName && {callerName}} {call.callerNumber}
{typeLabel} {formatDuration(call.startTime)} {call.status}
); }}
)}
{/* Monitoring hint */} {activeCalls.length > 0 && (

Select "Listen" on any active call to start monitoring

Agent will not be notified during listen mode

)}
); };