mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: outbound call UI — immediate call card, auto-answer SIP bridge
- ClickToCallButton sets callState='ringing-out' immediately on click - ActiveCallCard shows "Calling..." state for outbound - SIP manager auto-answers incoming SIP when outbound is pending (Kookoo bridge) - CallPrepCard shows lead context while dialing - On error, resets state cleanly Flow: Click Call → UI shows call card → Kookoo dials customer → customer answers → SIP bridges → auto-answer → active call → disposition Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import type { SIPConfig, ConnectionStatus, CallState } from '@/types/sip';
|
||||
// Singleton SIP client — survives React StrictMode remounts
|
||||
let sipClient: SIPClient | null = null;
|
||||
let connected = false;
|
||||
let outboundPending = false;
|
||||
|
||||
type StateUpdater = {
|
||||
setConnectionStatus: (status: ConnectionStatus) => void;
|
||||
@@ -17,6 +18,14 @@ export function registerSipStateUpdater(updater: StateUpdater) {
|
||||
stateUpdater = updater;
|
||||
}
|
||||
|
||||
export function setOutboundPending(pending: boolean) {
|
||||
outboundPending = pending;
|
||||
}
|
||||
|
||||
export function isOutboundPending(): boolean {
|
||||
return outboundPending;
|
||||
}
|
||||
|
||||
export function connectSip(config: SIPConfig): void {
|
||||
if (connected || sipClient?.isRegistered() || sipClient?.isConnected()) {
|
||||
return;
|
||||
@@ -38,6 +47,17 @@ export function connectSip(config: SIPConfig): void {
|
||||
config,
|
||||
(status) => stateUpdater?.setConnectionStatus(status),
|
||||
(state, number) => {
|
||||
// Auto-answer SIP when it's a bridge from our outbound Kookoo call
|
||||
if (state === 'ringing-in' && outboundPending) {
|
||||
outboundPending = false;
|
||||
// Auto-answer after a brief delay to let SIP negotiate
|
||||
setTimeout(() => {
|
||||
sipClient?.answer();
|
||||
stateUpdater?.setCallState('active');
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
stateUpdater?.setCallState(state);
|
||||
if (number !== undefined) stateUpdater?.setCallerNumber(number ?? null);
|
||||
},
|
||||
@@ -50,6 +70,7 @@ export function disconnectSip(): void {
|
||||
sipClient?.disconnect();
|
||||
sipClient = null;
|
||||
connected = false;
|
||||
outboundPending = false;
|
||||
stateUpdater?.setConnectionStatus('disconnected');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user