fix: refactor whatsapp calling for lint compliance, outbound call UI, and SDP handling

This commit is contained in:
Tanmay Deep Sharma
2026-03-18 14:59:56 +05:30
parent c813505e7d
commit 1e3c6ad620
13 changed files with 339 additions and 261 deletions
@@ -15,6 +15,7 @@ const {
hasIncomingCall,
isAccepting,
isMuted,
isOutboundRinging,
callError,
formattedCallDuration,
acceptCall,
@@ -150,7 +151,10 @@ onUnmounted(() => {
v-if="hasActiveCall"
class="flex items-center gap-3 p-4 bg-n-solid-2 rounded-xl shadow-xl outline outline-1 outline-n-strong"
>
<div class="ring-2 ring-n-teal-9 rounded-full inline-flex">
<div
class="ring-2 ring-n-teal-9 rounded-full inline-flex"
:class="{ 'animate-pulse': isOutboundRinging }"
>
<Avatar
:src="activeCall.caller?.avatar"
:name="activeCall.caller?.name || activeCall.caller?.phone"
@@ -166,8 +170,17 @@ onUnmounted(() => {
t('WHATSAPP_CALL.UNKNOWN_CALLER')
}}
</p>
<p class="font-mono text-sm text-n-teal-9">
{{ formattedCallDuration }}
<p
class="text-sm"
:class="
isOutboundRinging ? 'text-n-slate-11' : 'font-mono text-n-teal-9'
"
>
{{
isOutboundRinging
? t('WHATSAPP_CALL.RINGING')
: formattedCallDuration
}}
</p>
</div>
<div class="flex shrink-0 gap-2">
@@ -16,6 +16,10 @@ import { useI18n } from 'vue-i18n';
import WhatsappCallsAPI from 'dashboard/api/whatsappCalls';
import { emitter } from 'shared/helpers/mitt';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import {
useWhatsappCallsStore,
setOutboundCallProperty,
} from 'dashboard/stores/whatsappCalls';
const props = defineProps({
chat: {
@@ -34,6 +38,7 @@ const route = useRoute();
const conversationHeader = ref(null);
const { width } = useElementSize(conversationHeader);
const { isAWebWidgetInbox, isAWhatsAppCloudChannel } = useInbox();
const whatsappCallsStore = useWhatsappCallsStore();
const isInitiatingCall = ref(false);
const currentChat = computed(() => store.getters.getSelectedChat);
@@ -127,7 +132,7 @@ const initiateWhatsappCall = async () => {
});
localStream.getTracks().forEach(track => pc.addTrack(track, localStream));
// Handle remote audio from Meta
// Handle remote audio from Meta — ontrack fires when the callee picks up
pc.ontrack = event => {
const [stream] = event.streams;
if (!stream) return;
@@ -135,12 +140,15 @@ const initiateWhatsappCall = async () => {
audio.srcObject = stream;
audio.autoplay = true;
document.body.appendChild(audio);
window.__outboundCallAudio = audio;
setOutboundCallProperty('audio', audio);
// Remote audio arrived — callee picked up, transition from ringing to connected
whatsappCallsStore.markActiveCallConnected();
};
// eslint-disable-next-line no-console
pc.oniceconnectionstatechange = () =>
pc.oniceconnectionstatechange = () => {
// eslint-disable-next-line no-console
console.log('[WhatsApp Call] Outbound ICE state:', pc.iceConnectionState);
};
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
@@ -155,16 +163,17 @@ const initiateWhatsappCall = async () => {
);
const callStatus = response.data?.status;
if (callStatus === 'permission_requested' || callStatus === 'permission_pending') {
if (
callStatus === 'permission_requested' ||
callStatus === 'permission_pending'
) {
pc.close();
localStream.getTracks().forEach(track => track.stop());
const messageKey = callStatus === 'permission_requested'
? 'WHATSAPP_CALL.PERMISSION_REQUESTED'
: 'WHATSAPP_CALL.PERMISSION_PENDING';
emitter.emit(BUS_EVENTS.SHOW_ALERT, {
message: t(messageKey),
type: 'info',
});
const message =
callStatus === 'permission_requested'
? t('WHATSAPP_CALL.PERMISSION_REQUESTED')
: t('WHATSAPP_CALL.PERMISSION_PENDING');
emitter.emit(BUS_EVENTS.SHOW_ALERT, { message, type: 'info' });
return;
}
@@ -173,9 +182,25 @@ const initiateWhatsappCall = async () => {
type: 'success',
});
window.__outboundCallPC = pc;
window.__outboundCallStream = localStream;
window.__outboundCallId = response.data?.call_id;
const outboundCallId = response.data?.call_id;
setOutboundCallProperty('pc', pc);
setOutboundCallProperty('stream', localStream);
setOutboundCallProperty('callId', outboundCallId);
// Set active call in store so the WhatsappCallWidget renders
// Status starts as 'ringing' — updated to 'connected' when SDP answer arrives
whatsappCallsStore.setActiveCall({
id: response.data?.id,
callId: outboundCallId,
direction: 'outbound',
status: 'ringing',
conversationId: currentChat.value.id,
caller: {
name: currentContact.value?.name,
phone: currentContact.value?.phone_number,
avatar: currentContact.value?.thumbnail,
},
});
} catch (err) {
if (pc) pc.close();
if (localStream) localStream.getTracks().forEach(track => track.stop());