Files
call-sdk/packages/adapter-ameyo/lib/callStateManager.ts
2025-01-17 15:53:24 +05:30

205 lines
6.3 KiB
TypeScript

import {MessagingType} from "./assets/js/ajaxClient.ts";
import {CallStatus, PushType, CallState} from "./types.ts";
import {parseQuerystring} from "@universal-call-sdk/common/lib/utils/parsingUtils.ts";
import messagingType from "../types/MessagingType.ts";
import metricsProcessor from "@universal-call-sdk/common/lib/utils/metricsProcessor.ts";
class CallStateManager {
private state: CallState = {
isConnected: false,
lastCallStatus: 'inactive',
customerCallStatus: null,
crtObjectId: null,
connectionAttempts: 0,
customerInfo: null
};
private readonly MAX_CONNECTION_ATTEMPTS = 3;
private connectionTimeout: ReturnType<typeof setTimeout> | null = null;
private metricProcessor : metricsProcessor
public sendConnectedMessage() {
const customerInfo = this.state.customerInfo;
if (customerInfo?.callId || customerInfo?.phoneNumber) {
window.postMessage({
type: MessagingType.ON_AMEYO_CALL_ACCEPTED,
data: customerInfo
});
this.state.connectionAttempts = 0;
this.clearConnectionTimeout();
} else if (this.state.connectionAttempts < this.MAX_CONNECTION_ATTEMPTS) {
this.state.connectionAttempts++;
this.setConnectionTimeout();
} else {
console.warn('Max connection attempts reached without valid customer info');
this.clearConnectionTimeout();
}
}
private setConnectionTimeout() {
this.clearConnectionTimeout();
this.connectionTimeout = setTimeout(() => {
this.sendConnectedMessage();
}, 100 * Math.pow(2, this.state.connectionAttempts)); // Exponential backoff
}
private clearConnectionTimeout() {
if (this.connectionTimeout) {
clearTimeout(this.connectionTimeout);
this.connectionTimeout = null;
}
}
public handleEvent(jsonData: any) {
const pushType = jsonData?.pushType;
const data = jsonData?.data;
switch (pushType) {
case PushType.UserCallModelUpdated:
this.handleCallModelUpdate(data);
break;
case PushType.CustomerCallMemberUpdated:
this.handleCustomerCallUpdate(data);
break;
case PushType.CustomerCallMemberCreated:
this.handleCustomerCallCreated(data);
break;
case PushType.CRMCreateNotify:
this.handleCRMCreate(data);
break;
case PushType.UserCallMemberUpdated:
this.handleUserCallMemberUpdate(data);
break;
case PushType.UserCCRuntimeUpdated:
this.handleUserCCRuntimeUpdate(data);
break;
case PushType.UserLoggedOff:
this.handleUserLoggedOff();
break;
}
}
private handleCallModelUpdate(data: any) {
const status = data?.status as CallStatus;
this.state.lastCallStatus = status;
switch (status) {
case 'ringing':
window.postMessage({
type: MessagingType.ON_AMEYO_CALL_INCOMING,
data: this.state.customerInfo
});
this?.metricProcessor?.pushCounterMetric({
metricName: 'ringing_event_counter',
flow: "ringing_event_counter"
});
break;
case 'hungup':
this.handleCallDisconnect();
break;
}
}
private handleCustomerCallUpdate(data: any) {
this.state.customerCallStatus = data?.status;
this.state.crtObjectId = data?.crtObjectId;
// handle for transfer call
if (data?.isDisposing && data?.status === 'hungup') {
this.handleCallDisconnect();
}
}
private handleCustomerCallCreated(data: any) {
this.state.customerInfo = {
...this.state.customerInfo,
phoneNumber: data?.phone,
crtObjectId: data?.crtObjectId,
callId: data?.callId
};
}
private handleCRMCreate(data: any) {
const crmURL = data?.crmURL;
if (!crmURL) return;
const parsedQuery = parseQuerystring(crmURL);
const userCRTObjectId = parsedQuery?.userCrtObjectId?.replaceAll('%40', '@');
this?.metricProcessor?.pushCounterMetric({
metricName: 'notify_push_event_counter',
flow: "notify_push_event_counter"
});
this.state.customerInfo = {
...this.state.customerInfo,
phoneNumber: parsedQuery?.phone,
lan: parsedQuery?.loanaccountnumber,
crtObjectId: data?.crtObjectId,
userCRTObjectId,
callId: parsedQuery?.unique_id || parsedQuery?.callid
};
}
private handleUserCallMemberUpdate(data: any) {
const validStatuses = ["ringing", "connected", "hungup"];
if (data?.associationType === 'transfer.association' &&
validStatuses.includes(data?.status)) {
window.postMessage({
type: MessagingType.ON_AMEYO_CALL_TRANSFER,
data
});
}
}
private handleUserCCRuntimeUpdate(data: any) {
const payload = data;
window.postMessage({
type: messagingType.ON_AMEYO_AVAILABILITY_CHANGE,
data:{
isOnBreak: payload?.isOnBreak,
reason: payload?.statusDescription
}
})
}
private handleUserLoggedOff() {
window.postMessage({
type: MessagingType.ON_AMEYO_FORCED_LOGOUT,
data: {}
});
}
private handleCallDisconnect() {
window.postMessage({
type: MessagingType.ON_AMEYO_CALL_DISCONNECTED,
data: this.state.customerInfo
});
// Reset state
this.state = {
isConnected: false,
lastCallStatus: 'inactive',
customerCallStatus: null,
crtObjectId: null,
connectionAttempts: 0,
customerInfo: null
};
this.clearConnectionTimeout();
}
public setMetricProcessor(metricProcessor) {
this.metricProcessor = metricsProcessor
}
}
export const callStateManager = new CallStateManager();