import { useState, useEffect, useRef, useCallback } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSidebarFlip, faSidebar, faPhone, faXmark, faDeleteLeft, faFlask } from '@fortawesome/pro-duotone-svg-icons'; import { useSetAtom } from 'jotai'; import { sipCallStateAtom, sipCallerNumberAtom, sipCallUcidAtom, sipCallDurationAtom } from '@/state/sip-state'; import { useAuth } from '@/providers/auth-provider'; import { useData } from '@/providers/data-provider'; import { useWorklist } from '@/hooks/use-worklist'; import { useSip } from '@/providers/sip-provider'; import { WorklistPanel } from '@/components/call-desk/worklist-panel'; import type { WorklistLead } from '@/components/call-desk/worklist-panel'; import { ContextPanel } from '@/components/call-desk/context-panel'; import { ActiveCallCard } from '@/components/call-desk/active-call-card'; import { apiClient } from '@/lib/api-client'; import { notify } from '@/lib/toast'; import { cx } from '@/utils/cx'; export const CallDeskPage = () => { const { user } = useAuth(); const { leadActivities, calls, followUps: dataFollowUps, patients, appointments } = useData(); const { callState, callerNumber, callUcid, dialOutbound } = useSip(); const { missedCalls, followUps, marketingLeads, loading } = useWorklist(); const [selectedLead, setSelectedLead] = useState(null); const [contextOpen, setContextOpen] = useState(true); const [activeMissedCallId, setActiveMissedCallId] = useState(null); const [callDismissed, setCallDismissed] = useState(false); const [diallerOpen, setDiallerOpen] = useState(false); const [dialNumber, setDialNumber] = useState(''); const [dialling, setDialling] = useState(false); // DEV: simulate incoming call const setSimCallState = useSetAtom(sipCallStateAtom); const setSimCallerNumber = useSetAtom(sipCallerNumberAtom); const setSimCallUcid = useSetAtom(sipCallUcidAtom); const setSimDuration = useSetAtom(sipCallDurationAtom); const simTimerRef = useRef | null>(null); const startSimCall = useCallback(() => { setSimCallerNumber('+919959966676'); setSimCallUcid(`SIM-${Date.now()}`); setSimDuration(0); setSimCallState('active'); simTimerRef.current = setInterval(() => setSimDuration((d) => d + 1), 1000); }, [setSimCallState, setSimCallerNumber, setSimCallUcid, setSimDuration]); const endSimCall = useCallback(() => { if (simTimerRef.current) { clearInterval(simTimerRef.current); simTimerRef.current = null; } setSimCallState('idle'); setSimCallerNumber(null); setSimCallUcid(null); setSimDuration(0); }, [setSimCallState, setSimCallerNumber, setSimCallUcid, setSimDuration]); const handleDial = async () => { const num = dialNumber.replace(/[^0-9]/g, ''); if (num.length < 10) { notify.error('Enter a valid phone number'); return; } setDialling(true); try { await dialOutbound(num); setDiallerOpen(false); setDialNumber(''); } catch { notify.error('Dial failed'); } finally { setDialling(false); } }; // Reset callDismissed when a new call starts (ringing in or out) if (callDismissed && (callState === 'ringing-in' || callState === 'ringing-out')) { setCallDismissed(false); } const isInCall = !callDismissed && (callState === 'ringing-in' || callState === 'ringing-out' || callState === 'active' || callState === 'ended' || callState === 'failed'); // Resolve caller identity via sidecar (lookup-or-create lead+patient pair) const [resolvedCaller, setResolvedCaller] = useState<{ leadId: string; patientId: string; firstName: string; lastName: string; phone: string; } | null>(null); const resolveAttemptedRef = useRef(null); useEffect(() => { if (!callerNumber || !isInCall) return; if (resolveAttemptedRef.current === callerNumber) return; // already resolving/resolved this number resolveAttemptedRef.current = callerNumber; apiClient.post<{ leadId: string; patientId: string; firstName: string; lastName: string; phone: string; isNew: boolean; }>('/api/caller/resolve', { phone: callerNumber }, { silent: true }) .then((result) => { setResolvedCaller(result); if (result.isNew) { notify.info('New Caller', 'Lead and patient records created'); } }) .catch((err) => { console.warn('[RESOLVE] Caller resolution failed:', err); resolveAttemptedRef.current = null; // allow retry }); }, [callerNumber, isInCall]); // Reset resolved caller when call ends useEffect(() => { if (!isInCall) { setResolvedCaller(null); resolveAttemptedRef.current = null; } }, [isInCall]); // Build activeLead from resolved caller or fallback to client-side match const callerLead = resolvedCaller ? marketingLeads.find((l) => l.id === resolvedCaller.leadId) ?? { id: resolvedCaller.leadId, contactName: { firstName: resolvedCaller.firstName, lastName: resolvedCaller.lastName }, contactPhone: [{ number: resolvedCaller.phone, callingCode: '+91' }], patientId: resolvedCaller.patientId, } : callerNumber ? marketingLeads.find((l) => l.contactPhone?.[0]?.number?.endsWith(callerNumber) || callerNumber.endsWith(l.contactPhone?.[0]?.number ?? '---')) : null; // For inbound calls, use resolved/matched lead. For outbound, use selectedLead. const activeLead = isInCall ? (callerLead ?? (callState === 'ringing-out' ? selectedLead : null)) : selectedLead; const activeLeadFull = activeLead as any; return (
{/* Compact header: title + name on left, status + toggle on right */}

Call Desk

{user.name}
{import.meta.env.DEV && (!isInCall ? ( ) : callUcid?.startsWith('SIM-') && ( ))} {!isInCall && (
{diallerOpen && (
Dial
setDialNumber(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleDial()} placeholder="Enter number" autoFocus className="flex-1 bg-transparent text-lg font-semibold text-primary tracking-wider text-center placeholder:text-placeholder placeholder:font-normal placeholder:text-sm outline-none" /> {dialNumber && ( )}
{['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'].map(key => ( ))}
)}
)}
{/* Main content */}
{/* Main panel */}
{/* Active call */} {isInCall && (
{ setActiveMissedCallId(null); setCallDismissed(true); }} />
)} {/* Worklist — no wrapper, tabs + table fill the space */} {!isInCall && ( setSelectedLead(lead)} selectedLeadId={selectedLead?.id ?? null} onDialMissedCall={(id) => setActiveMissedCallId(id)} /> )}
{/* Context panel — collapsible with smooth transition */}
{contextOpen && ( )}
); };