231 lines
6.9 KiB
TypeScript
231 lines
6.9 KiB
TypeScript
import {MessagingType, parseQuerystring} from "./assets/js/ajaxClient.ts";
|
|
|
|
import {CallStatus, PushType, CallState} from "./types.ts";
|
|
|
|
interface EventData {
|
|
pushType: PushType;
|
|
data: any; // We can make this more specific if needed
|
|
}
|
|
|
|
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 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
|
|
});
|
|
break;
|
|
|
|
case 'connected':
|
|
if (!this.state.isConnected) {
|
|
this.state.isConnected = true;
|
|
this.sendConnectedMessage();
|
|
}
|
|
break;
|
|
|
|
case 'hungup':
|
|
this.handleCallDisconnect();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private handleCustomerCallUpdate(data: any) {
|
|
this.state.customerCallStatus = data?.status;
|
|
this.state.crtObjectId = data?.crtObjectId;
|
|
|
|
// Keep disconnect handling
|
|
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.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) {
|
|
if (data?.isOnBreak) {
|
|
window.postMessage({
|
|
type: MessagingType.ON_AMEYO_AGENT_ON_BREAK,
|
|
data: {
|
|
reason: data
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
export const callStateManager = new CallStateManager();
|
|
|
|
export function extractAndProcessEvents(rawResponse: any) {
|
|
const parts = rawResponse
|
|
.replaceAll(`Content-type: application/json ; charset: utf-8\r\n\r\n`, '')
|
|
.split("--DON'T_PANIC!_more_will_follow\r\n")
|
|
.map((part: string) => {
|
|
try {
|
|
return JSON.parse(part.trim());
|
|
} catch {
|
|
return null;
|
|
}
|
|
})
|
|
.filter(Boolean);
|
|
|
|
// Process events in order, prioritizing CRMCreateNotifyPush
|
|
const sortedParts: EventData[] = [
|
|
...parts.filter((part: EventData | null): part is EventData =>
|
|
part?.pushType === PushType.CRMCreateNotify),
|
|
...parts.filter((part: EventData | null): part is EventData =>
|
|
part?.pushType !== PushType.CRMCreateNotify)
|
|
];
|
|
sortedParts.forEach(event => {
|
|
try {
|
|
callStateManager.handleEvent(event);
|
|
} catch (error) {
|
|
console.error('Error processing event:', event, error);
|
|
}
|
|
});
|
|
}
|