Enables agents to initiate outbound calls and receive incoming calls directly from the Chatwoot dashboard, with Twilio as the initial provider. Fixes: #11481 > This is an integration branch to ensure features works well and might be often broken on down merges, we will be extracting the functionalities via smaller PRs into develop - [x] https://github.com/chatwoot/chatwoot/pull/11775 - [x] https://github.com/chatwoot/chatwoot/pull/12218 - [x] https://github.com/chatwoot/chatwoot/pull/12243 - [x] https://github.com/chatwoot/chatwoot/pull/12268 - [x] https://github.com/chatwoot/chatwoot/pull/12361 - [x] https://github.com/chatwoot/chatwoot/pull/12782 - [x] #13064 - [ ] Ability for agents to join the inbound calls ( included in this PR ) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com>
80 lines
2.0 KiB
JavaScript
80 lines
2.0 KiB
JavaScript
import { CONTENT_TYPES } from 'dashboard/components-next/message/constants';
|
|
import { useCallsStore } from 'dashboard/stores/calls';
|
|
import types from 'dashboard/store/mutation-types';
|
|
|
|
export const TERMINAL_STATUSES = [
|
|
'completed',
|
|
'busy',
|
|
'failed',
|
|
'no-answer',
|
|
'canceled',
|
|
'missed',
|
|
'ended',
|
|
];
|
|
|
|
export const isInbound = direction => direction === 'inbound';
|
|
|
|
const isVoiceCallMessage = message => {
|
|
return CONTENT_TYPES.VOICE_CALL === message?.content_type;
|
|
};
|
|
|
|
const shouldSkipCall = (callDirection, senderId, currentUserId) => {
|
|
return callDirection === 'outbound' && senderId !== currentUserId;
|
|
};
|
|
|
|
function extractCallData(message) {
|
|
const contentData = message?.content_attributes?.data || {};
|
|
return {
|
|
callSid: contentData.call_sid,
|
|
status: contentData.status,
|
|
callDirection: contentData.call_direction,
|
|
conversationId: message?.conversation_id,
|
|
senderId: message?.sender?.id,
|
|
};
|
|
}
|
|
|
|
export function handleVoiceCallCreated(message, currentUserId) {
|
|
if (!isVoiceCallMessage(message)) return;
|
|
|
|
const { callSid, callDirection, conversationId, senderId } =
|
|
extractCallData(message);
|
|
|
|
if (shouldSkipCall(callDirection, senderId, currentUserId)) return;
|
|
|
|
const callsStore = useCallsStore();
|
|
callsStore.addCall({
|
|
callSid,
|
|
conversationId,
|
|
callDirection,
|
|
senderId,
|
|
});
|
|
}
|
|
|
|
export function handleVoiceCallUpdated(commit, message, currentUserId) {
|
|
if (!isVoiceCallMessage(message)) return;
|
|
|
|
const { callSid, status, callDirection, conversationId, senderId } =
|
|
extractCallData(message);
|
|
|
|
const callsStore = useCallsStore();
|
|
|
|
callsStore.handleCallStatusChanged({ callSid, status, conversationId });
|
|
|
|
const callInfo = { conversationId, callStatus: status };
|
|
commit(types.UPDATE_CONVERSATION_CALL_STATUS, callInfo);
|
|
commit(types.UPDATE_MESSAGE_CALL_STATUS, callInfo);
|
|
|
|
const isNewCall =
|
|
status === 'ringing' &&
|
|
!shouldSkipCall(callDirection, senderId, currentUserId);
|
|
|
|
if (isNewCall) {
|
|
callsStore.addCall({
|
|
callSid,
|
|
conversationId,
|
|
callDirection,
|
|
senderId,
|
|
});
|
|
}
|
|
}
|