diff --git a/packages/adapter-ameyo/lib/api.ts b/packages/adapter-ameyo/lib/api.ts index 321593e..60d77d7 100644 --- a/packages/adapter-ameyo/lib/api.ts +++ b/packages/adapter-ameyo/lib/api.ts @@ -1,9 +1,8 @@ import getResponseWithoutCors from "@universal-call-sdk/common/lib/utils/getResponseWithoutCors.ts"; -import { RequestKeys} from "./types"; +import {CallTransferData, RequestKeys} from "./types"; import RequestType from "@universal-call-sdk/common/lib/types/RequestType.ts"; - export const loginInAmeyo = (userId: string, password: string) => { console.log('loginInAmeyo', userId, password); return getResponseWithoutCors({ @@ -27,7 +26,7 @@ export const loginInAmeyo = (userId: string, password: string) => { }; export const maintainHeartbeat = (sessionId: string, webcoreTimestamp: string, counter: number) => { const HEART_BEAT_REQUEST_TEXT = `7|0|8|${window.BASE_AMEYO_URL}/app/application_ui/|93B024BCBAF3AE5EFEC49890FE64CF5F|com.drishti.ameyo.common.ui.rpc.CommonGwtRpcService|keepAliveWithPingPush|java.lang.String/2004016611|java.lang.Integer/3438268394|${sessionId}|${webcoreTimestamp}|1|2|3|4|3|5|5|6|7|8|6|${counter}|${sessionId}|`; - setInterval(()=> getResponseWithoutCors({ + setInterval(() => getResponseWithoutCors({ url: `${window.BASE_AMEYO_URL}/ameyo40/service`, method: 'POST', requestKey: RequestKeys.AMEYO_HEARTBEAT, @@ -110,7 +109,7 @@ export const autoSelectExtension = (sessionId: string, userId: string) => { requestType: RequestType.JSON, data: { sessionId: sessionId, - params: { 'user.id': userId } + params: {'user.id': userId} }, headers: { sessionId: sessionId @@ -139,7 +138,7 @@ export const setAutoStatus = (sessionId: string) => { method: 'POST', requestKey: RequestKeys.SET_AUTO_STATUS, requestType: RequestType.JSON, - data: { userSessionId: sessionId, status: true }, + data: {userSessionId: sessionId, status: true}, headers: { sessionId: sessionId } @@ -152,18 +151,18 @@ export const ameyoHangupUser = (sessionId: string, userCRTObjectId: string) => { method: 'POST', requestKey: RequestKeys.HANGUP_USER, requestType: RequestType.JSON, - data: { sessionId, userCRTObjectId }, + data: {sessionId, userCRTObjectId}, headers: { sessionId } }); }; -export const ameyoDisposeCall = (sessionId: string, campaignId : string,crtObjectId: string, userCRTObjectId: string) => { +export const ameyoDisposeCall = (sessionId: string, campaignId: string, crtObjectId: string, userCRTObjectId: string) => { return getResponseWithoutCors({ url: `${window.BASE_AMEYO_URL}/ameyorestapi/voice/disposeCall`, method: 'POST', - requestKey: RequestKeys.HANGUP_USER, + requestKey: RequestKeys.DISPOSE_CALL, requestType: RequestType.JSON, data: { sessionId, @@ -193,3 +192,38 @@ export const getCampaignId = (sessionId: string) => { } }); } + +export const getAllAgentsForTransferCall = (sessionId: string) => { + return getResponseWithoutCors({ + url: `${window.BASE_AMEYO_URL}/ameyorestapi/voice/getAllUserCampaignVoicePresencesByContactCenterId`, + method: 'GET', + requestKey: RequestKeys.GET_AGENTS_FOR_CALL_TRANSFER, + requestType: RequestType.JSON, + data: {}, + headers: { + sessionId + } + }); +} + + +export const transferCallToAgent = (data: CallTransferData, sessionId: string, crtObjectId: string, userCRTObjectId: string, campaignId: string) => { + return getResponseWithoutCors({ + url: `${window.BASE_AMEYO_URL}/ameyorestapi/voice/transferToUserInDifferentCampaign`, + method: 'POST', + requestKey: RequestKeys.TRANSFER_CALL_TO_AGENT, + requestType: RequestType.JSON, + data: { + sourceCampaignId: campaignId, + sourceCRTObjectId: userCRTObjectId, + targetCampaignId: data?.campaignId, + targetCRTObjectId: data?.targetCRTObjectId, + transferredCRTObjectIds: [crtObjectId], + "requestId": "48ae79ab-faad-21f5-b694-ad3d9e4e0690" + }, + headers: { + sessionId + } + }); +} + diff --git a/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts b/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts index 0debc45..ae51d29 100644 --- a/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts +++ b/packages/adapter-ameyo/lib/assets/js/ajaxClient.ts @@ -11,7 +11,7 @@ export enum MessagingType { ON_AMEYO_CALL_DISCONNECTED = 'onAmeyoCallDisconnected', ON_AMEYO_AGENT_ON_BREAK = 'onAmeyoAgentOnBreak', ON_AMEYO_FORCED_LOGOUT = 'onAmeyoForcedLogout', - + ON_AMEYO_CALL_TRANSFER = 'onAmeyoCallTransfer', } @@ -43,6 +43,8 @@ let http = createRequestObject(); enum pushResponseTypes { UserCallModelUpdatedPush = 'UserCallModelUpdatedPush', + CustomerCallMemberUpdatedPush = 'CustomerCallMemberUpdatedPush', + UserCallMemberUpdatedPush = 'UserCallMemberUpdatedPush', CRMCreateNotifyPush = 'CRMCreateNotifyPush', UserCCRuntimeUpdatedPush = 'UserCCRuntimeUpdatedPush', UserLoggedOffPush = 'UserLoggedOffPush' @@ -85,7 +87,25 @@ function extractUserCallModelUpdatedPush(rawResponse) { res = jsonData; sendCallStatusMessage(res); } - if (jsonData.pushType === pushResponseTypes.UserCCRuntimeUpdatedPush) { + if (jsonData?.pushType === pushResponseTypes.CustomerCallMemberUpdatedPush) { + const payload = jsonData?.data; + // handle for transfer call + if (payload?.isDisposing && + payload?.status === 'hungup') + sendCallStatusMessage(jsonData); + } + if (jsonData?.pushType === pushResponseTypes.UserCallMemberUpdatedPush) { + const payload = jsonData?.data; + const validStatuses = ["ringing", "connected", "hungup"]; + // handle for transfer call + if (payload?.associationType === 'transfer.association' && validStatuses.includes(payload?.status)) { + window.postMessage({ + type: MessagingType.ON_AMEYO_CALL_TRANSFER, + data: payload + }) + } + } + if (jsonData?.pushType === pushResponseTypes.UserCCRuntimeUpdatedPush) { const payload = jsonData?.data; //handle ameyo erroronous condition if (payload?.isOnBreak) { diff --git a/packages/adapter-ameyo/lib/main.ts b/packages/adapter-ameyo/lib/main.ts index a7c1f7b..73b8fd6 100644 --- a/packages/adapter-ameyo/lib/main.ts +++ b/packages/adapter-ameyo/lib/main.ts @@ -1,6 +1,13 @@ import IAdapter from "@universal-call-sdk/common/lib/Interfaces/IAdapter.ts"; import GenericObject from "@universal-call-sdk/common/lib/types/GenericObject.ts"; -import {AmeyoInitializationOptions, CALL_STATES, RequestKeys, SipAccountInfo, StateType} from "./types.ts"; +import { + AmeyoInitializationOptions, + CALL_STATES, + CallTransferData, + RequestKeys, + SipAccountInfo, + StateType +} from "./types.ts"; import MessagingType from "../types/MessagingType.ts"; import { ameyoHangupUser, @@ -11,7 +18,8 @@ import { selectCampaign, setAgentActive, setAgentOnBreak, setAutoStatus, - getCampaignId, ameyoDisposeCall + getCampaignId, ameyoDisposeCall, + getAllAgentsForTransferCall, transferCallToAgent } from "./api.ts"; import { acceptSipCall, @@ -32,6 +40,8 @@ class AmeyoAdapter implements IAdapter { onAgentAvailabilityChange: (isAgentAvailable: boolean) => void onForcedLogout: () => void, onLoginFailed: (err: GenericObject)=>void + onAgentsForCallTransfer: (data: GenericObject) => void + onCallTransferStatus: (data: GenericObject) => void; }; private currentCallState: string; private eventListenerUrl: string; @@ -69,6 +79,10 @@ class AmeyoAdapter implements IAdapter { }, onForcedLogout: () => { }, + onAgentsForCallTransfer: () => { + }, + onCallTransferStatus: () => { + }, onLoginFailed: ()=>{ } @@ -93,7 +107,7 @@ class AmeyoAdapter implements IAdapter { } - _initializeSipStack = ({accountName, userName, domain="", password}: SipAccountInfo) => { + _initializeSipStack = ({accountName, userName, domain = "", password}: SipAccountInfo) => { console.log('initializing sip stack'); const domainOnly = domain?.split?.(':')?.[0]; const port = domain?.split?.(':')?.[1]; @@ -166,6 +180,9 @@ class AmeyoAdapter implements IAdapter { this.callbacks.onAgentAvailabilityChange(false); window.postMessage({type: 'onAmeyoAvailabiltyChange', data: false},); } + if (payload?.data?.requestKey === RequestKeys.GET_AGENTS_FOR_CALL_TRANSFER) { + this.callbacks.onAgentsForCallTransfer(payload?.data?.response); + } } _registerMessageListener = async ({data}: GenericObject) => { @@ -196,6 +213,9 @@ class AmeyoAdapter implements IAdapter { if (data?.type === MessagingType.ON_AMEYO_FORCED_LOGOUT) { this.callbacks.onForcedLogout() } + if(data?.type === MessagingType.ON_AMEYO_CALL_TRANSFER){ + this.callbacks.onCallTransferStatus(data?.data); + } }; registerOnCallIncoming(callback: (callState: StateType) => void) { @@ -233,6 +253,15 @@ class AmeyoAdapter implements IAdapter { this.callbacks.onLoginFailed = callback } + registerOnAgentsForCallTransfer(callback: (data: GenericObject) => void) { + console.log('registerOnAgentsForCallTransfer'); + this.callbacks.onAgentsForCallTransfer = callback; + } + + registerOnCallTransferStatus(callback: (data: GenericObject) => void) { + this.callbacks.onCallTransferStatus = callback; + } + acceptCall() { console.log('acceptCall'); acceptSipCall(); @@ -275,10 +304,22 @@ class AmeyoAdapter implements IAdapter { return this.currentCallState; } + getAvailableAgentsForCallTransfer() { + getAllAgentsForTransferCall(this.sessionId); + } + + transferCallToAgent(data: CallTransferData) { + transferCallToAgent(data, + this.sessionId, + this.currentCallMetadata?.crtObjectId, + this.currentCallMetadata?.userCRTObjectId, + this.campaignId); + } + private _appendTags: () => void = () => { const script = document.createElement('script'); script.src = 'https://public-assets.np.navi-gi.in/jarvis/sip5ml.js'; // Assuming it's placed in the public folder - script.async=true; + script.async = true; document.head.appendChild(script); const is_already_appended = document.querySelector('#audio_remote') && document.querySelector('#video_local') && document.querySelector('#video_remote') && document.querySelector('#ringtone') && document.querySelector('#ringbacktone') && document.querySelector('#dtmfTone'); if (is_already_appended) { @@ -372,10 +413,10 @@ class AmeyoAdapter implements IAdapter { src: 'https://public-assets.np.navi-gi.in/jarvis/dtmf.wav', }); const onSipSetupReadyEvent = new CustomEvent('onSipSetupReady', { - detail: { message: 'Custom page loaded event triggered' } + detail: {message: 'Custom page loaded event triggered'} }); - script.onload = ()=>{ + script.onload = () => { window.dispatchEvent(onSipSetupReadyEvent) } diff --git a/packages/adapter-ameyo/lib/types.ts b/packages/adapter-ameyo/lib/types.ts index eb2c8ae..2617abf 100644 --- a/packages/adapter-ameyo/lib/types.ts +++ b/packages/adapter-ameyo/lib/types.ts @@ -21,9 +21,12 @@ export enum RequestKeys { OMNIQUEUE_SERVICE = 'ameyo_omniqueue', SELECT_CAMPAIGN = 'select_campaign', HANGUP_USER = 'hangup_user', + DISPOSE_CALL = 'dispose_call', AUTO_SELECT_EXTENSION = 'auto_select_extension', SET_AUTO_STATUS = "set_auto_status", GET_CAMPAIGN_ID = "get_campaign_id", + GET_AGENTS_FOR_CALL_TRANSFER = "get_agents_for_call_transfer", + TRANSFER_CALL_TO_AGENT = "transfer_call_to_agent", } export type AmeyoInitializationOptions = { @@ -63,3 +66,8 @@ export enum CALL_STATES { CALL_DISCONNECTED = 'CALL_DISCONNECTED', IDLE = 'IDLE', } + +export type CallTransferData = { + campaignId : string, + targetCRTObjectId: string +} diff --git a/packages/adapter-ameyo/package.json b/packages/adapter-ameyo/package.json index e584d7c..06169d4 100644 --- a/packages/adapter-ameyo/package.json +++ b/packages/adapter-ameyo/package.json @@ -1,6 +1,6 @@ { "name": "@universal-call-sdk/adapter-ameyo", - "version": "1.0.78", + "version": "1.0.80", "type": "module", "scripts": { "dev": "vite", @@ -9,7 +9,7 @@ "preview": "vite preview" }, "dependencies": { - "@universal-call-sdk/common": "^1.0.31" + "@universal-call-sdk/common": "^1.0.33" }, "devDependencies": { "@eslint/js": "^9.11.1", diff --git a/packages/adapter-ameyo/types/MessagingType.ts b/packages/adapter-ameyo/types/MessagingType.ts index 2d46257..3b92302 100644 --- a/packages/adapter-ameyo/types/MessagingType.ts +++ b/packages/adapter-ameyo/types/MessagingType.ts @@ -6,7 +6,8 @@ ON_AMEYO_CALL_DISCONNECTED = 'onAmeyoCallDisconnected', ON_AMEYO_AGENT_ON_BREAK = 'onAmeyoAgentOnBreak', ON_AMEYO_FORCED_LOGOUT = 'onAmeyoForcedLogout', + ON_AMEYO_CALL_TRANSFER = 'onAmeyoCallTransfer', } -export default MessagingType; \ No newline at end of file +export default MessagingType; diff --git a/packages/common/lib/Interfaces/IAdapter.ts b/packages/common/lib/Interfaces/IAdapter.ts index 95dff3c..6e6e828 100644 --- a/packages/common/lib/Interfaces/IAdapter.ts +++ b/packages/common/lib/Interfaces/IAdapter.ts @@ -4,29 +4,27 @@ class IAdapter { registerOnCallIncoming(callback: (callState: GenericObject)=>void) {callback({})} registerOnCallConnected(callback: (callState: GenericObject)=>void) {callback({})} registerOnCallDisconnected(callback: (callState: GenericObject)=>void) {callback({})} - registerOnAdapterReady(callback: ()=> void) {callback()} - registerOnAgentAvailabilityChange(callback: (isAgentAvailable: boolean) => void) {callback(false)} - registerOnForcedLogoutListener(callback:()=>void) {callback()} registerOnLoginFailedListener(callback:()=>void) {callback()} + registerOnAgentsForCallTransfer(callback: (data : GenericObject) => void) {callback({})} + registerOnCallTransferStatus(callback: (data: GenericObject) => void) {callback({})} acceptCall() {} rejectCall() {} muteCall() {} disposeCall() {} unmuteCall() {} - setOnBreak() {} - setAvailable() {} + init() {} + getAgentAvailability(): boolean {return false} getLatestCallState() {return {}} - - - + getAvailableAgentsForCallTransfer() {} + transferCallToAgent(data: GenericObject) {console.log("transfer call", data)} } export default IAdapter; diff --git a/packages/common/package.json b/packages/common/package.json index b28e78b..d3afb83 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -1,6 +1,6 @@ { "name": "@universal-call-sdk/common", - "version": "1.0.31", + "version": "1.0.33", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/core/lib/useCallSdk.ts b/packages/core/lib/useCallSdk.ts index 9b1a064..639e3ec 100644 --- a/packages/core/lib/useCallSdk.ts +++ b/packages/core/lib/useCallSdk.ts @@ -3,29 +3,29 @@ import {GenericObject, StateType} from "./types.ts"; import IAdapter from "@universal-call-sdk/common/lib/Interfaces/IAdapter.ts"; - - -enum actionTypes { - CALL_INCOMING= 'CALL_INCOMING', - CALL_CONNECTED= 'CALL_CONNECTED', - CALL_DISCONNECTED= 'CALL_DISCONNECTED', - CALL_REJECTED= 'CALL_REJECTED', - CALL_MUTED= 'CALL_MUTED', - CALL_UNMUTED= 'CALL_UNMUTED', +enum actionTypes { + CALL_INCOMING = 'CALL_INCOMING', + CALL_CONNECTED = 'CALL_CONNECTED', + CALL_DISCONNECTED = 'CALL_DISCONNECTED', + CALL_REJECTED = 'CALL_REJECTED', + CALL_MUTED = 'CALL_MUTED', + CALL_UNMUTED = 'CALL_UNMUTED', } + type Actions = { type: actionTypes, payload: GenericObject } -function reducer(state : StateType, action: Actions) : GenericObject { - if(action.type === actionTypes.CALL_INCOMING) { + +function reducer(state: StateType, action: Actions): GenericObject { + if (action.type === actionTypes.CALL_INCOMING) { return { ...state, connectedCustomerdata: action.payload, isRinging: true } } - if(action.type === actionTypes.CALL_CONNECTED) { + if (action.type === actionTypes.CALL_CONNECTED) { return { ...state, isCallConnected: true @@ -62,9 +62,7 @@ function reducer(state : StateType, action: Actions) : GenericObject { } - - -const initialState : StateType = { +const initialState: StateType = { connectedCustomerdata: {}, isRinging: false, isCallConnected: false, @@ -73,7 +71,11 @@ const initialState : StateType = { } let adapter: IAdapter; -function UseCallSdk({AdapterClass, adapterOptions} : {AdapterClass: new (adapterOptions: IAdapter)=> IAdapter, adapterOptions: IAdapter}) { + +function UseCallSdk({AdapterClass, adapterOptions}: { + AdapterClass: new (adapterOptions: IAdapter) => IAdapter, + adapterOptions: IAdapter +}) { useEffect(() => { adapter = new AdapterClass(adapterOptions); }, []); @@ -106,6 +108,14 @@ function UseCallSdk({AdapterClass, adapterOptions} : {AdapterClass: new (adapter adapter.registerOnForcedLogoutListener(callback); } + function registerOnAgentsForCallTransfer(callback: (data: GenericObject) => void) { + adapter.registerOnAgentsForCallTransfer(callback); + } + + function registerOnCallTransferStatus(callback: (data: GenericObject) => void) { + adapter.registerOnCallTransferStatus(callback); + } + function registerOnLoginFailedListener(callback:()=>void) { adapter.registerOnLoginFailedListener(callback); } @@ -143,21 +153,31 @@ function UseCallSdk({AdapterClass, adapterOptions} : {AdapterClass: new (adapter } function getAgentAvailability(): boolean { - console.log('prinitng adapter', adapter); - return adapter.getAgentAvailability(); + console.log('printing adapter', adapter); + return adapter.getAgentAvailability(); } function getLatestCallState(): GenericObject { return adapter.getLatestCallState(); } - return { + function getAvailableAgentsForCallTransfer() { + adapter.getAvailableAgentsForCallTransfer(); + } + + function transferCallToAgent(data: GenericObject) { + adapter.transferCallToAgent(data); + } + + return { callState, registerOnCallIncoming, registerOnCallConnected, registerOnCallDisconnected, registerOnAgentAvailabilityChange, registerOnForcedLogoutListener, + registerOnAgentsForCallTransfer, + registerOnCallTransferStatus, registerOnLoginFailedListener, acceptCall, rejectCall, @@ -169,9 +189,10 @@ function UseCallSdk({AdapterClass, adapterOptions} : {AdapterClass: new (adapter getLatestCallState, setOnBreak, registerOnAdapterReady, - getAgentAvailability - - } + getAgentAvailability, + getAvailableAgentsForCallTransfer, + transferCallToAgent + } } export default UseCallSdk; diff --git a/packages/core/package.json b/packages/core/package.json index b6ccbb7..b830b14 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@universal-call-sdk/core", - "version": "1.0.36", + "version": "1.0.38", "type": "module", "scripts": { "dev": "vite",