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 }) => (
);
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 ? (
) : 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
)}
>
);
};