From a30e510928e8337288a07338c7773444665f5cb1 Mon Sep 17 00:00:00 2001 From: Antonio <36625268+tonyco97@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:30:29 +0100 Subject: [PATCH] fix: missing phone island on incoming call (#75) --- src/components/Socket.tsx | 190 +++++++++++++++++++++++--------------- src/components/WebRTC.tsx | 14 ++- src/lib/phone/call.ts | 10 +- src/models/currentCall.ts | 4 + src/services/astproxy.ts | 35 +++---- src/types/user.ts | 1 + 6 files changed, 153 insertions(+), 101 deletions(-) diff --git a/src/components/Socket.tsx b/src/components/Socket.tsx index 4354b6d..c2a0f42 100644 --- a/src/components/Socket.tsx +++ b/src/components/Socket.tsx @@ -94,105 +94,141 @@ export const Socket: FC = ({ // With conversation if (res.status) { const { extensions } = store.getState().users + const { default_device } = store.getState().currentUser + const { endpoints, username } = store.getState().currentUser + const { incoming, outgoing } = store.getState().currentCall + + const hasOnlineNethlink = () => { + if (!extensions || !username) return false + + // Get all extensions for current user + const userExtensions: any = Object.values(extensions).filter( + (ext) => ext?.username === username, + ) + + // Check if any extension is nethlink type and online + return userExtensions?.some((ext) => { + const endpointExtension = endpoints?.extension.find( + (endpoint) => endpoint.id === ext?.exten, + ) + return endpointExtension?.type === 'nethlink' && ext?.status !== 'offline' + }) + } switch (res.status) { case 'ringing': - // The name and the number are updated here not in webrtc - dispatch.currentCall.checkIncomingUpdatePlay({ - conversationId: conv.id, - displayName: getDisplayName(conv), - number: `${conv.counterpartNum}`, - incomingSocket: true, - username: - `${ - extensions && - extensions[conv.counterpartNum] && - extensions[conv.counterpartNum].username - }` || '', - ownerExtension: conv.owner, - }) - - eventDispatch('phone-island-call-ringing', {}) - - break - // @ts-ignore - case 'busy': - if (conv && conv.connected) { - // Current call accepted and update connected call - dispatch.currentCall.updateCurrentCall({ + if ( + (uaType === 'mobile' && hasOnlineNethlink()) || + (uaType === 'desktop' && + (default_device?.type === 'webrtc' || + (default_device?.type === undefined && !hasOnlineNethlink()) || + (!hasOnlineNethlink() && default_device?.type === 'physical'))) + ) { + dispatch.currentCall.checkIncomingUpdatePlay({ conversationId: conv.id, displayName: getDisplayName(conv), number: `${conv.counterpartNum}`, - ownerExtension: conv.owner, + incomingSocket: true, username: `${ extensions && extensions[conv.counterpartNum] && extensions[conv.counterpartNum].username }` || '', + ownerExtension: conv.owner, }) - // Update the current call informations for physical devices - dispatch.currentCall.checkAcceptedUpdate({ - acceptedSocket: true, - }) - // Add call to transfer calls - dispatch.currentCall.addTransferCalls({ - type: 'transferred', - displayName: getDisplayName(conv), - number: `${conv.counterpartNum}`, - startTime: `${getTimestampInSeconds()}`, - }) + store.dispatch.island.setIslandView('call') - if (isPhysical()) { - checkDefaultDeviceConversationActive(conv) - } - if (view === 'call' && transferring) { + eventDispatch('phone-island-call-ringing', {}) + } + break + // @ts-ignore + case 'busy': + if ( + (uaType === 'mobile' && hasOnlineNethlink()) || + (uaType === 'desktop' && + (default_device?.type === 'webrtc' || + (default_device?.type === undefined && !hasOnlineNethlink()) || + (!hasOnlineNethlink() && default_device?.type === 'physical'))) + ) { + if (conv && conv.connected) { + // Current call accepted and update connected call dispatch.currentCall.updateCurrentCall({ - transferring: false, + conversationId: conv.id, + displayName: getDisplayName(conv), + number: `${conv.counterpartNum}`, + ownerExtension: conv.owner, + username: + `${ + extensions && + extensions[conv.counterpartNum] && + extensions[conv.counterpartNum].username + }` || '', }) - } - } - // Delete transfer calls if there are more than one ( in case of call switch after transfer) - if (transferCalls.length > 1) { - dispatch.currentCall.deleteTransferCalls() - } - // Handle not connected calls - else if (conv && !conv.connected) { - if (transferring && !transferSwitching) { - // Handle hangup during transfer - const inTransferCalls = transferCalls.find( - (item) => item.number === conv.counterpartNum, - ) - if (!conv.connected && inTransferCalls) { - // Update transferring data for the current call + // Update the current call informations for physical devices + dispatch.currentCall.checkAcceptedUpdate({ + acceptedSocket: true, + }) + // Add call to transfer calls + dispatch.currentCall.addTransferCalls({ + type: 'transferred', + displayName: getDisplayName(conv), + number: `${conv.counterpartNum}`, + startTime: `${getTimestampInSeconds()}`, + }) + + if (isPhysical()) { + checkDefaultDeviceConversationActive(conv) + } + if (view === 'call' && transferring) { dispatch.currentCall.updateCurrentCall({ transferring: false, }) - eventDispatch('phone-island-call-transfer-failed', {}) - // Reset transfer switching - // TODO - It needs to enhance how conversation connections (conv.connected) are updated server side - // TODO - The transfer end is not handled when the an user hangups or after call switch - dispatch.currentCall.updateTransferSwitching(false) } } - if (conv?.counterpartName === 'REC') { - dispatch.physicalRecorder.setRecordingTempVariable(true) + // Delete transfer calls if there are more than one ( in case of call switch after transfer) + if (transferCalls.length > 1) { + dispatch.currentCall.deleteTransferCalls() + } + // Handle not connected calls + else if (conv && !conv.connected) { + if (transferring && !transferSwitching) { + // Handle hangup during transfer + const inTransferCalls = transferCalls.find( + (item) => item.number === conv.counterpartNum, + ) + if (!conv.connected && inTransferCalls) { + // Update transferring data for the current call + dispatch.currentCall.updateCurrentCall({ + transferring: false, + }) + eventDispatch('phone-island-call-transfer-failed', {}) + // Reset transfer switching + // TODO - It needs to enhance how conversation connections (conv.connected) are updated server side + // TODO - The transfer end is not handled when the an user hangups or after call switch + dispatch.currentCall.updateTransferSwitching(false) + } + } + if (conv?.counterpartName === 'REC') { + dispatch.physicalRecorder.setRecordingTempVariable(true) + } + } + // Handle outgoing call + if (conv && !conv.connected && conv.direction === 'out') { + // Update the current outgoing conversation + dispatch.currentCall.checkOutgoingUpdate({ + outgoingSocket: true, + displayName: getDisplayName(conv), + number: `${conv.counterpartNum}`, + username: + `${ + extensions && + extensions[conv.counterpartNum] && + extensions[conv.counterpartNum].username + }` || '', + }) } } - // Handle outgoing call - if (conv && !conv.connected && conv.direction === 'out') { - // Update the current outgoing conversation - dispatch.currentCall.checkOutgoingUpdate({ - outgoingSocket: true, - displayName: getDisplayName(conv), - number: `${conv.counterpartNum}`, - username: - `${ - extensions && - extensions[conv.counterpartNum] && - extensions[conv.counterpartNum].username - }` || '', - }) - } + case 'onhold': // The new conversation during transferring const { counterpartName, counterpartNum, startTime } = conv diff --git a/src/components/WebRTC.tsx b/src/components/WebRTC.tsx index d4e4a19..e2510e7 100644 --- a/src/components/WebRTC.tsx +++ b/src/components/WebRTC.tsx @@ -158,6 +158,7 @@ export const WebRTC: FC = ({ var event = result['event'] // Get the recording state const { recording } = store.getState().recorder + const { view } = store.getState().island // Manage different types of events switch (event) { @@ -225,6 +226,9 @@ export const WebRTC: FC = ({ } // Update webrtc lastActivity time dispatch.webrtc.updateLastActivity(new Date().getTime()) + if (view !== 'call') { + dispatch.island.setIslandView('call') + } break // After an outgoing call start on 183 code, it means @@ -271,10 +275,11 @@ export const WebRTC: FC = ({ } if ( - (uaType === 'mobile' && - (default_device?.type === 'nethlink' || hasOnlineNethlink())) || + (uaType === 'mobile' && hasOnlineNethlink()) || (uaType === 'desktop' && - (default_device?.type === 'webrtc' || !hasOnlineNethlink())) + (default_device?.type === 'webrtc' || + (default_device?.type === undefined && !hasOnlineNethlink()) || + (!hasOnlineNethlink() && default_device?.type === 'physical'))) ) { // Update webrtc state dispatch.webrtc.updateWebRTC({ jsepGlobal: jsep }) @@ -293,12 +298,14 @@ export const WebRTC: FC = ({ }) if (janus.current.log) { + dispatch.currentCall.updateIncoming(true) janus.current.log('Incoming call from ' + result['username'] + '!') } } // Update the webrtc last activity time dispatch.webrtc.updateLastActivity(new Date().getTime()) + store.dispatch.island.setIslandView('call') } break @@ -575,7 +582,6 @@ export const WebRTC: FC = ({ useEventListener('phone-island-attach', (data) => { initWebRTC() - store.dispatch.currentUser.updateCurrentDefaultDevice(data?.deviceInformationObject) eventDispatch('phone-island-attached', {}) }) diff --git a/src/lib/phone/call.ts b/src/lib/phone/call.ts index c88d966..f225498 100644 --- a/src/lib/phone/call.ts +++ b/src/lib/phone/call.ts @@ -188,11 +188,12 @@ export async function blindTransfer(number: string) { const { conversationId } = store.getState().currentCall const { default_device } = store.getState().currentUser // Transfer the call through blind transfer - if (conversationId && default_device?.id && number) { + let default_device_details = default_device?.id || default_device?.exten + if (conversationId && default_device_details && number) { return await blindTransferRequest({ convid: conversationId, to: number, - endpointId: default_device.id, + endpointId: default_device_details, }) } } @@ -204,12 +205,13 @@ export async function attendedTransfer(number: string) { // Retrieve current conversation info const { conversationId } = store.getState().currentCall const { default_device } = store.getState().currentUser + let default_device_details = default_device?.id || default_device?.exten // Transfer the call through attended transfer - if (conversationId && default_device?.id && number) { + if (conversationId && default_device_details && number) { return await attendedTransferRequest({ convid: conversationId, to: number, - endpointId: default_device.id, + endpointId: default_device_details, }) } } diff --git a/src/models/currentCall.ts b/src/models/currentCall.ts index 54f471c..4cfc2ad 100644 --- a/src/models/currentCall.ts +++ b/src/models/currentCall.ts @@ -92,6 +92,10 @@ export const currentCall = createModel()({ state.startTime = payload return state }, + updateIncoming: (state, payload: boolean) => { + state.incoming = payload + return state + }, reset: () => { return defaultState }, diff --git a/src/services/astproxy.ts b/src/services/astproxy.ts index ecf21d9..442726f 100644 --- a/src/services/astproxy.ts +++ b/src/services/astproxy.ts @@ -109,25 +109,28 @@ export async function answerPhysical() { // get data const { default_device } = store.getState().currentUser + let default_device_details = default_device?.id || default_device?.exten // compose body - let body: any = { - endpointId: default_device?.id, - endpointType: 'extension', - } + if (default_device_details !== undefined) { + let body: any = { + endpointId: default_device?.exten || default_device?.id, + endpointType: 'extension', + } - try { - const { baseURL, headers } = store.getState().fetchDefaults - const response = await fetch(`${baseURL}/astproxy/answer`, { - method: 'POST', - headers: { ...headers }, - body: JSON.stringify(body), - }) - if (!response.ok) { - throw new Error(response.statusText) + try { + const { baseURL, headers } = store.getState().fetchDefaults + const response = await fetch(`${baseURL}/astproxy/answer`, { + method: 'POST', + headers: { ...headers }, + body: JSON.stringify(body), + }) + if (!response.ok) { + throw new Error(response.statusText) + } + return true + } catch (error: any) { + throw new Error(error) } - return true - } catch (error: any) { - throw new Error(error) } } diff --git a/src/types/user.ts b/src/types/user.ts index 03ce76f..2f2be40 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -22,6 +22,7 @@ export interface UserExtensionTypes { hold: boolean } proxy_port: string | null + exten: string } export interface PermissionTypes {