diff --git a/src/components/call-desk/active-call-card.tsx b/src/components/call-desk/active-call-card.tsx
index b0d1b86..7da9236 100644
--- a/src/components/call-desk/active-call-card.tsx
+++ b/src/components/call-desk/active-call-card.tsx
@@ -105,7 +105,33 @@ export const ActiveCallCard = ({ lead, callerPhone }: ActiveCallCardProps) => {
setCallerNumber(null);
};
- // Ringing state
+ // Outbound ringing — agent initiated the call
+ if (callState === 'ringing-out') {
+ return (
+
+
+
+
+
Calling...
+
{fullName || phoneDisplay}
+ {fullName &&
{phoneDisplay}
}
+
+
+
+
+
+
+ );
+ }
+
+ // Inbound ringing
if (callState === 'ringing-in') {
return (
diff --git a/src/components/call-desk/click-to-call-button.tsx b/src/components/call-desk/click-to-call-button.tsx
index 0532a6f..7be395f 100644
--- a/src/components/call-desk/click-to-call-button.tsx
+++ b/src/components/call-desk/click-to-call-button.tsx
@@ -1,7 +1,10 @@
import { useState } from 'react';
import { Phone01 } from '@untitledui/icons';
+import { useSetAtom } from 'jotai';
import { Button } from '@/components/base/buttons/button';
import { useSip } from '@/providers/sip-provider';
+import { sipCallStateAtom, sipCallerNumberAtom } from '@/state/sip-state';
+import { setOutboundPending } from '@/state/sip-manager';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
@@ -15,14 +18,25 @@ interface ClickToCallButtonProps {
export const ClickToCallButton = ({ phoneNumber, leadId, label, size = 'sm' }: ClickToCallButtonProps) => {
const { isRegistered, isInCall } = useSip();
const [dialing, setDialing] = useState(false);
+ const setCallState = useSetAtom(sipCallStateAtom);
+ const setCallerNumber = useSetAtom(sipCallerNumberAtom);
const handleDial = async () => {
setDialing(true);
+
+ // Immediately show the call UI and mark outbound pending for auto-answer
+ setCallState('ringing-out');
+ setCallerNumber(phoneNumber);
+ setOutboundPending(true);
+
try {
await apiClient.post('/api/ozonetel/dial', { phoneNumber, leadId });
- notify.success('Dialing', `Calling ${phoneNumber}...`);
} catch {
- // apiClient.post already toasts the error
+ // API error — reset call state
+ setCallState('idle');
+ setCallerNumber(null);
+ setOutboundPending(false);
+ notify.error('Dial Failed', 'Could not place the call');
} finally {
setDialing(false);
}
@@ -37,7 +51,7 @@ export const ClickToCallButton = ({ phoneNumber, leadId, label, size = 'sm' }: C
isDisabled={!isRegistered || isInCall || !phoneNumber || dialing}
isLoading={dialing}
>
- {dialing ? 'Dialing...' : (label ?? 'Call')}
+ {label ?? 'Call'}
);
};
diff --git a/src/state/sip-manager.ts b/src/state/sip-manager.ts
index a38b145..e3f3214 100644
--- a/src/state/sip-manager.ts
+++ b/src/state/sip-manager.ts
@@ -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');
}