+ const handleCancel = async () => {
+ if (!connectedTarget) { onClose(); return; }
+ // Disconnect the third party, keep the caller
+ setTransferring(true);
+ try {
+ await apiClient.post('/api/ozonetel/call-control', {
+ action: 'KICK_CALL',
+ ucid,
+ conferenceNumber: connectedTarget.phoneNumber,
+ });
+ setConnectedTarget(null);
+ notify.info('Cancelled', 'Transfer cancelled, caller reconnected');
+ } catch {
+ notify.error('Error', 'Could not disconnect third party');
+ } finally {
+ setTransferring(false);
+ }
+ };
+
+ // Connected state — show target + complete/cancel buttons
+ if (connectedTarget) {
+ return (
+
-
-
+ );
+ }
+
+ // Target selection
+ return (
+
+ {/* Search + actions — pinned */}
+
+
+
- ) : (
-
- Connected to {number}
-
-
- )}
+
+
+
+
+ {/* Scrollable target list */}
+
+ {loading ? (
+
Loading...
+ ) : (
+ <>
+ {/* Agents */}
+ {agents.length > 0 && (
+
+
Agents
+
+ {agents.map(agent => {
+ const st = statusConfig[agent.status ?? 'offline'] ?? statusConfig.offline;
+ const isSelected = selectedTarget?.id === agent.id;
+ return (
+
+ );
+ })}
+
+
+ )}
+
+ {/* Doctors */}
+ {doctors.length > 0 && (
+
+
Doctors
+
+ {doctors.map(doc => {
+ const isSelected = selectedTarget?.id === doc.id;
+ return (
+
+ );
+ })}
+
+
+ )}
+
+
+ {filtered.length === 0 && !loading && (
+
No matching targets
+ )}
+ >
+ )}
+
+
);
};
diff --git a/src/pages/call-desk.tsx b/src/pages/call-desk.tsx
index 3ad3b3e..64476b8 100644
--- a/src/pages/call-desk.tsx
+++ b/src/pages/call-desk.tsx
@@ -1,6 +1,8 @@
-import { useState, useEffect, useRef } from 'react';
+import { useState, useEffect, useRef, useCallback } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faSidebarFlip, faSidebar, faPhone, faXmark, faDeleteLeft } from '@fortawesome/pro-duotone-svg-icons';
+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';
@@ -10,7 +12,6 @@ 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 { Badge } from '@/components/base/badges/badges';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
import { cx } from '@/utils/cx';
@@ -19,7 +20,7 @@ export const CallDeskPage = () => {
const { user } = useAuth();
const { leadActivities, calls, followUps: dataFollowUps, patients, appointments } = useData();
const { callState, callerNumber, callUcid, dialOutbound } = useSip();
- const { missedCalls, followUps, marketingLeads, totalPending, loading } = useWorklist();
+ const { missedCalls, followUps, marketingLeads, loading } = useWorklist();
const [selectedLead, setSelectedLead] = useState
(null);
const [contextOpen, setContextOpen] = useState(true);
const [activeMissedCallId, setActiveMissedCallId] = useState(null);
@@ -28,6 +29,29 @@ export const CallDeskPage = () => {
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; }
@@ -112,6 +136,23 @@ export const CallDeskPage = () => {
+ {import.meta.env.DEV && (!isInCall ? (
+
+ ) : callUcid?.startsWith('SIM-') && (
+
+ ))}
{!isInCall && (
)}
- {totalPending > 0 && (
-
{totalPending} pending
- )}