import { useState, useEffect, useRef } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPhoneHangup, faHeadset, faCommentDots, faUsers } from '@fortawesome/pro-duotone-svg-icons'; import { faIcon } from '@/lib/icon-wrapper'; import { Button } from '@/components/base/buttons/button'; import { supervisorSip } from '@/lib/supervisor-sip-client'; import { apiClient } from '@/lib/api-client'; import { notify } from '@/lib/toast'; import { cx } from '@/utils/cx'; const HangupIcon = faIcon(faPhoneHangup); const HeadsetIcon = faIcon(faHeadset); type BargeStatus = 'idle' | 'connecting' | 'connected' | 'ended'; type BargeMode = 'listen' | 'whisper' | 'barge'; const MODE_DTMF: Record = { listen: '4', whisper: '5', barge: '6' }; const MODE_CONFIG: Record = { listen: { label: 'Listen', description: 'Silent monitoring — nobody knows you are here', icon: faHeadset, activeClass: 'border-secondary bg-secondary', }, whisper: { label: 'Whisper', description: 'Only the agent can hear you', icon: faCommentDots, activeClass: 'border-brand bg-brand-primary', }, barge: { label: 'Barge', description: 'Both agent and patient can hear you', icon: faUsers, activeClass: 'border-error bg-error-primary', }, }; type BargeControlsProps = { ucid: string; agentId: string; agentNumber: string; agentName: string; onDisconnected?: () => void; }; export const BargeControls = ({ ucid, agentId, agentNumber, agentName, onDisconnected }: BargeControlsProps) => { const [status, setStatus] = useState('idle'); const [mode, setMode] = useState('listen'); const [duration, setDuration] = useState(0); const connectedAtRef = useRef(null); // Duration counter useEffect(() => { if (status !== 'connected') return; connectedAtRef.current = Date.now(); const interval = setInterval(() => { setDuration(Math.floor((Date.now() - (connectedAtRef.current ?? Date.now())) / 1000)); }, 1000); return () => clearInterval(interval); }, [status]); // Cleanup on unmount useEffect(() => { return () => { if (supervisorSip.isCallActive()) { supervisorSip.close(); apiClient.post('/api/supervisor/barge/end', { agentId }, { silent: true }).catch(() => {}); } }; }, [agentId]); const handleConnect = async () => { setStatus('connecting'); setMode('listen'); setDuration(0); try { const result = await apiClient.post<{ sipNumber: string; sipPassword: string; sipDomain: string; sipPort: string; }>('/api/supervisor/barge', { ucid, agentId, agentNumber }); supervisorSip.on('registered', () => { // Ozonetel will send incoming call after SIP registration }); supervisorSip.on('callConnected', () => { setStatus('connected'); supervisorSip.sendDTMF('4'); // default: listen mode notify.success('Connected', `Monitoring ${agentName}'s call`); }); supervisorSip.on('callEnded', () => { setStatus('ended'); apiClient.post('/api/supervisor/barge/end', { agentId }, { silent: true }).catch(() => {}); onDisconnected?.(); }); supervisorSip.on('callFailed', (cause: string) => { setStatus('ended'); notify.error('Connection Failed', cause ?? 'Could not connect to call'); apiClient.post('/api/supervisor/barge/end', { agentId }, { silent: true }).catch(() => {}); }); supervisorSip.on('registrationFailed', (cause: string) => { setStatus('ended'); notify.error('SIP Registration Failed', cause ?? 'Could not register'); }); supervisorSip.init({ domain: result.sipDomain, port: result.sipPort, number: result.sipNumber, password: result.sipPassword, }); supervisorSip.register(); } catch (err: any) { setStatus('idle'); notify.error('Barge Failed', err.message ?? 'Could not initiate barge'); } }; const handleModeChange = (newMode: BargeMode) => { if (newMode === mode) return; supervisorSip.sendDTMF(MODE_DTMF[newMode]); setMode(newMode); apiClient.post('/api/supervisor/barge/mode', { agentId, mode: newMode }, { silent: true }).catch(() => {}); }; const handleHangup = () => { supervisorSip.close(); setStatus('ended'); apiClient.post('/api/supervisor/barge/end', { agentId }, { silent: true }).catch(() => {}); onDisconnected?.(); }; const formatDuration = (sec: number) => { const m = Math.floor(sec / 60); const s = sec % 60; return `${m}:${s.toString().padStart(2, '0')}`; }; // Idle / ended state if (status === 'idle' || status === 'ended') { return (

{status === 'ended' ? 'Session ended' : 'Ready to monitor'}

); } // Connecting state if (status === 'connecting') { return (
Connecting...

Registering SIP and joining call

); } // Connected state return (
{/* Status bar */}
Connected
{formatDuration(duration)}
{/* Mode tabs */}
{(['listen', 'whisper', 'barge'] as BargeMode[]).map((m) => { const config = MODE_CONFIG[m]; const isActive = mode === m; return ( ); })}
{/* Mode description */}

{MODE_CONFIG[mode].description}

{/* Hang up */}
); };