mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: CC agent features, live call assist, worklist redesign, brand tokens
CC Agent: - Call transfer (CONFERENCE + KICK_CALL) with inline transfer dialog - Recording pause/resume during active calls - Missed calls API (Ozonetel abandonCalls) - Call history API (Ozonetel fetchCDRDetails) Live Call Assist: - Deepgram Nova STT via raw WebSocket - OpenAI suggestions every 10s with lead context - LiveTranscript component in sidebar during calls - Browser audio capture from remote WebRTC stream Worklist: - Redesigned table: clickable phones, context menu (Call/SMS/WhatsApp) - Last interaction sub-line, source column, improved SLA - Filtered out rows without phone numbers - New missed call notifications Brand: - Logo on login page - Blue scale rebuilt from logo blue rgb(32, 96, 160) - FontAwesome duotone CSS variables set globally - Profile menu icons switched to duotone Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
91
src/components/call-desk/transfer-dialog.tsx
Normal file
91
src/components/call-desk/transfer-dialog.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import { useState } from 'react';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faXmark } from '@fortawesome/pro-duotone-svg-icons';
|
||||
import { Input } from '@/components/base/input/input';
|
||||
import { Button } from '@/components/base/buttons/button';
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
import { notify } from '@/lib/toast';
|
||||
|
||||
type TransferDialogProps = {
|
||||
ucid: string;
|
||||
onClose: () => void;
|
||||
onTransferred: () => void;
|
||||
};
|
||||
|
||||
export const TransferDialog = ({ ucid, onClose, onTransferred }: TransferDialogProps) => {
|
||||
const [number, setNumber] = useState('');
|
||||
const [transferring, setTransferring] = useState(false);
|
||||
const [stage, setStage] = useState<'input' | 'connected'>('input');
|
||||
|
||||
const handleConference = async () => {
|
||||
if (!number.trim()) return;
|
||||
setTransferring(true);
|
||||
try {
|
||||
await apiClient.post('/api/ozonetel/call-control', {
|
||||
action: 'CONFERENCE',
|
||||
ucid,
|
||||
conferenceNumber: `0${number.replace(/\D/g, '')}`,
|
||||
});
|
||||
notify.success('Connected', 'Third party connected. Click Complete to transfer.');
|
||||
setStage('connected');
|
||||
} catch {
|
||||
notify.error('Transfer Failed', 'Could not connect to the target number');
|
||||
} finally {
|
||||
setTransferring(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleComplete = async () => {
|
||||
setTransferring(true);
|
||||
try {
|
||||
await apiClient.post('/api/ozonetel/call-control', {
|
||||
action: 'KICK_CALL',
|
||||
ucid,
|
||||
conferenceNumber: `0${number.replace(/\D/g, '')}`,
|
||||
});
|
||||
notify.success('Transferred', 'Call transferred successfully');
|
||||
onTransferred();
|
||||
} catch {
|
||||
notify.error('Transfer Failed', 'Could not complete transfer');
|
||||
} finally {
|
||||
setTransferring(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-3 rounded-lg border border-secondary bg-secondary p-3">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-xs font-semibold text-secondary">Transfer Call</span>
|
||||
<button onClick={onClose} className="text-fg-quaternary hover:text-fg-secondary transition duration-100 ease-linear">
|
||||
<FontAwesomeIcon icon={faXmark} className="size-3" />
|
||||
</button>
|
||||
</div>
|
||||
{stage === 'input' ? (
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
size="sm"
|
||||
placeholder="Enter phone number"
|
||||
value={number}
|
||||
onChange={setNumber}
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
color="primary"
|
||||
isLoading={transferring}
|
||||
onClick={handleConference}
|
||||
isDisabled={!number.trim()}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-tertiary">Connected to {number}</span>
|
||||
<Button size="sm" color="primary" isLoading={transferring} onClick={handleComplete}>
|
||||
Complete Transfer
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user