205 lines
6.3 KiB
TypeScript
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();
|