From f77f42f29768078d7b3c2d131f0c1580ad7fd617 Mon Sep 17 00:00:00 2001 From: Varnit Goyal Date: Thu, 28 Nov 2024 11:39:22 +0530 Subject: [PATCH] TP-89230 | ameyo rev eng (#1231) * TP-89230 | ameyo rev eng * TP-50000 | ameyo rev eng * :TP-89230 | integrate universal call sdk * :TP-89230 | integrate universal call sdk --------- Co-authored-by: varnit goyal --- .npmrc | 5 +- package.json | 2 + src/App.tsx | 1 + .../Ameyo/AmeyoCollapsibleToolbarV4.tsx | 1473 +++++++++++++++++ .../Ameyo/broadcastChannelMessage.ts | 4 + src/components/Ameyo/forcedLogoutDialog.tsx | 22 + src/components/sidebar/SideNavBar.tsx | 30 +- web-ui-library | 2 +- yarn.lock | 88 +- 9 files changed, 1602 insertions(+), 25 deletions(-) create mode 100644 src/components/Ameyo/AmeyoCollapsibleToolbarV4.tsx create mode 100644 src/components/Ameyo/broadcastChannelMessage.ts create mode 100644 src/components/Ameyo/forcedLogoutDialog.tsx diff --git a/.npmrc b/.npmrc index 94d22ff5..9bc52224 100644 --- a/.npmrc +++ b/.npmrc @@ -2,4 +2,7 @@ //registry.npmjs.org/:_authToken=NpmToken.1a3d3462-fb82-364c-bc64-0051e24635b3 @navi:registry=https://nexus.cmd.navi-tech.in/repository/npm-packages/ -//https://nexus.cmd.navi-tech.in/repository/npm-packages/:_authToken=NpmToken.1a3d3462-fb82-364c-bc64-0051e24635b3 \ No newline at end of file +//https://nexus.cmd.navi-tech.in/repository/npm-packages/:_authToken=NpmToken.1a3d3462-fb82-364c-bc64-0051e24635b3 + +@universal-call-sdk:registry=https://nexus.cmd.navi-tech.in/repository/npm-packages/ +//https://nexus.cmd.navi-tech.in/repository/npm-packages/:_authToken=NpmToken.1a3d3462-fb82-364c-bc64-0051e24635b3 diff --git a/package.json b/package.json index d843c225..2862992d 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,8 @@ "@types/react-infinite-scroller": "1.2.5", "@types/react-transition-group": "^4.4.5", "@types/uuid": "^9.0.2", + "@universal-call-sdk/adapter-ameyo": "^1.0.61", + "@universal-call-sdk/core": "^1.0.21", "ag-grid-community": "^28.1.1", "ag-grid-react": "^28.1.1", "autoprefixer": "^10.4.16", diff --git a/src/App.tsx b/src/App.tsx index 8db1973e..8552cf7c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -56,6 +56,7 @@ declare global { google: any; clientIp?: string; alfredSessionId?: string; + ameyoInitialized: boolean; } interface Navigator { userAgentData: { diff --git a/src/components/Ameyo/AmeyoCollapsibleToolbarV4.tsx b/src/components/Ameyo/AmeyoCollapsibleToolbarV4.tsx new file mode 100644 index 00000000..513e1dfa --- /dev/null +++ b/src/components/Ameyo/AmeyoCollapsibleToolbarV4.tsx @@ -0,0 +1,1473 @@ +/* eslint-disable no-console */ +import { AmeyoIcon } from '@cp/assets/icons/AmeyoIcon'; +import styles from './AmeyoCollapsibleToolbar.module.scss'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { Typography } from '@primitives'; +import CloseIcon from '../../assets/icons/CloseIcon'; +import { RssIcon } from '@cp/assets/icons/RssIcon'; +import { useDispatch, useSelector } from 'react-redux'; +import { RootState } from '../../store'; +import CyclicArrow from '../../assets/icons/CyclicArrow'; +import useOutsideClick from '@hooks/useOutsideClick'; +import { + EXTENSION_LISTENER_TYPES, + ExtensionHandler, + ExtensionHelper +} from '@cp/utils/extension.utils'; +import { + AMEYO_CALL_EVENTS, + AMEYO_STATUS_CODES, + AMEYO_STATUS_RANKS, + AmeyoCallData, + IAmeyoRecalibratedData, + naviExtension +} from '../../service/naviExtension.service'; +import Switch from '@primitives/Switch'; +import { AllCasesSummary } from '@cp/pages/Cases/constants/CasesInterfaces'; +import { getCustomerDetails } from '@cp/pages/CaseDetails/actions/casesDetailsActions'; +import { getCustomerReferenceIdFromLAN, getTelephones } from './ameyoActions'; +import { AudioPlayer } from '../AudioPlayer/AudioPlayer'; +import ameyoRinging from '../../assets/audio/ring.wav'; +import { ITelePhoneData } from '@cp/pages/CaseDetails/interfaces/CaseDetail.type'; +import axiosInstance, { ApiKeys, getApiUrl } from '../../utils/ApiHelper'; +import { + CreateInteractionRequest, + IConnectedCustomer, + onToggleAmeyoStatusDataProps, + PhoneNumberSources +} from './interfaces'; +import { + CALLING_MODES, + ECallingType, + InteractionType +} from '@cp/pages/CaseDetails/feedbackForm/interfaces/index.type'; +import { CosmosSyncBlockStatus, setAmeyoCallDetails } from '@cp/reducers/commonSlice'; +import { toast } from '@primitives/Toast'; +import { createQueryParams } from '@cp/utils/QueryParamsHelper'; +import { handleTabClose, isFunction, navigateToCaseDetails } from '@cp/utils/commonUtils'; +import APP_ROUTES from '../../layout/Routes'; +import { useNavigate } from 'react-router-dom'; +import GridRow from '@navi/web-ui/lib/layouts/Grid/GridRow/GridRow'; +import GridColumn from '@navi/web-ui/lib/layouts/Grid/GridColumn/GridColumn'; +import cx from 'classnames'; +import { addClickstreamEvent } from '../../service/clickStreamEventService'; +import { AMEYO_SESSION_EVENTS, CLICKSTREAM_EVENT_NAMES } from '../../service/clickStream.constant'; +import MuteIcon from 'src/assets/icons/MuteIcon'; +import UnMuteIcon from 'src/assets/icons/UnMuteIcon'; +import { Tooltip, TooltipContent, TooltipTrigger } from '../TooltipV2/TooltipV2'; +import { + AMEYO_CALL_COUNT_POLLING_INTERVAL, + AMEYO_MUTE_DISCLAIMER_INTERVAL, + AmeyoCallState, + AmeyoConstants, + AmeyoToggleNewStatus +} from './constants'; +import MicOff from 'src/assets/icons/MicOff'; +import HangUpCallIcon from 'src/assets/icons/HangUpCallIcon'; +import MuteCircledIcon from 'src/assets/icons/MuteCircledIcon'; +import UnMuteCircledIcon from 'src/assets/icons/UnMuteCircledIcon'; +import { jsxToString } from './utils'; +import NaviTabIcon from 'src/assets/icons/NaviTabIcon'; +import ErrorIcon from 'src/assets/icons/ErrorIcon'; +import { LITMUS_EXPERIMENT_NAMES } from '@cp/src/constants/litmusExperimentNames'; +import isLitmusExperimentEnabled from '@cp/src/utils/isLitmusExperimentEnabled'; +import { LocalStorage } from '@cp/src/utils/StorageUtils'; +import { LOCAL_STORAGE_KEYS } from '@cp/src/constants/StorageKeys'; +import { + resetState, + setAmeyoCallData, + setAmeyoExtensionToggleOn, + setButtonLoadingStates, + setConnectedCustomerData, + setCurrentState, + setIsAmeyoErronous, + setIsAmeyoExtOffDisclaimerVisible, + setIsAvailable, + setIsMuteDisclaimerVisible, + setIsVisible, + setNotificationBubbleColor, + setShouldPlayRingtone, + setShowAmeyoErroneousMsg, + setTelephoneSource, + setToolbarAuthState +} from '@cp/reducers/ameyoSlice'; +import { BUBBLE_COLORS, BUTTON_ENABLED_TIMEOUT } from '@cp/constants/ameyoConstants'; +import { poll } from '@cp/utils/polling'; +import { getCallBridgeData } from '@cp/pages/auth/AuthActions'; +import { noop } from '@utils/common'; +import KeyValueLabel from '@primitives/KeyValueLabel'; +import useCallSdk from '@universal-call-sdk/core/lib/useCallSdk'; +import AmeyoAdapter from '@universal-call-sdk/adapter-ameyo/lib/main'; +import { StateType } from '@universal-call-sdk/adapter-ameyo/lib/types'; +import { BroadcastChannelMessages } from '@cp/components/Ameyo/broadcastChannelMessage'; +import enachValueCard from '@cp/pages/CaseDetails/components/EmiSchedule/EnachValueCard'; +import { setIsSidebarSwitchDisable } from '@cp/reducers/humanReminderSlice'; +import { setAgentAvailability } from '@cp/pages/Dashboard/dc-97/HumanReminderAction'; +import ForcedLogoutDialog from '@cp/components/Ameyo/forcedLogoutDialog'; +import { setAmeyoLoggedIn } from '@cp/src/service/ameyo.service'; + +type IInteractionData = { + interactionId: string; + recipientNumber: string; + crtObjectId: string; +}; + +export const AmeyoCollapsibleToolbarV4 = (props: { + isCallHappening: (isHappening: boolean) => void; +}) => { + const { authData, ameyoExtensionToggleOn, campaignId } = useSelector((state: RootState) => { + return { + authData: state.common.userData, + ameyoExtensionToggleOn: state.humanReminder?.ameyoExtensionToggleOn, + campaignId: state?.common?.userData?.campaignId + }; + }); + const { + isAmeyoErronous, + ameyoCallData, + toolbarAuthState, + isVisible, + telephoneSource, + notificationBubbleColor, + shouldPlayRingtone, + isMuteDisclaimerVisible, + isAmeyoExtOffDisclaimerVisible, + buttonLoadingStates, + connectedCustomerData, + showAmeyoErroneousMsg, + currentAmeyoState, + isAvailable: isAmeyoAvailable + } = useSelector((state: RootState) => state?.ameyoSlice); + const { ameyoConnectedCallCount } = useSelector((state: RootState) => ({ + ameyoConnectedCallCount: + state?.leaderboard?.callbridgeData?.successfulAmeyoAttemptedCount ?? '--' + })); + let authError = false; + const navigate = useNavigate(); + const currentRef = useRef(null); + const dispatch = useDispatch(); + const toolbarAuthStateRef = useRef(toolbarAuthState); + toolbarAuthStateRef.current = toolbarAuthState; + const timerId = useRef(); + const [interactionData, setInteractionData] = useState(null); + const [currentAmeyoCallDetails, setCurrentAmeyoCallDetails] = useState<{ + lan: string; + phoneNumber: string; + crtObjectId: string; + }>({ lan: '', phoneNumber: '', crtObjectId: '' }); + const [callCountEnabled, setCallCountEnabled] = useState(false); + const ameyoCallsCountIntervalRef = useRef<() => void>(); + const { + acceptCall: acceptCallNew, + rejectCall: rejectCallNew, + registerOnCallConnected, + registerOnCallIncoming, + callState, + registerOnForcedLogoutListener, + registerOnAgentAvailabilityChange, + registerOnCallDisconnected, + unmuteCall: unmuteCallNew, + muteCall: muteCallNew, + initialize, + registerOnAdapterReady, + getAgentAvailability, + setAvailable, + setOnBreak, + getLatestCallState + } = useCallSdk({ + AdapterClass: AmeyoAdapter, + adapterOptions: { + baseUrl: 'https://naviapp1.ameyo.net:8443', + loginUrl: 'naviapp1.ameyo.net', + eventListenerUrl: 'https://naviapp1.ameyo.net:8443/ameyorestapi/pushes?', + userName: authData?.email, + password: authData?.ameyoKey + } + }); + + const [multiTabDialerDisabled, setMultiTabDialerDisabled] = useState(false); + const [forcedLogout, setForcedLogout] = useState(false); + const isAgentOnline = useSelector((store: RootState) => store.common.isAgentOnline); + const isLonghornBlocked = + useSelector((store: RootState) => store.common.cosmosSyncBlockStatus) === + CosmosSyncBlockStatus.BLOCKED; + const isAgentWithInOperativeHours = useSelector( + (state: RootState) => state?.common?.userData?.withinOperativeHours + ); + + useEffect(() => { + // if(authData?.userImpersonated && showAmeyoDia) + const ameyoInitBoardcaseChannel = new BroadcastChannel('ameyoInitBoardcastChannel'); + let ameyoInitialisationTimerid: NodeJS.Timeout | number = 0; + + ameyoInitBoardcaseChannel.postMessage({ + type: BroadcastChannelMessages.ask_for_ameyo_initiation + }); + + ameyoInitBoardcaseChannel.onmessage = event => { + console.log('debugging boardcast channel messages', event, 'event data'); + if (event.data.type === BroadcastChannelMessages.already_initialized) { + console.log('Adapter Ready'); + clearTimeout(ameyoInitialisationTimerid); + setMultiTabDialerDisabled(true); + return; + } + + if (event.data.type === BroadcastChannelMessages.ask_for_ameyo_initiation) { + if (window.ameyoInitialized) { + ameyoInitBoardcaseChannel.postMessage({ + type: BroadcastChannelMessages.already_initialized + }); + } + } + }; + ameyoInitialisationTimerid = setTimeout(() => { + //BC message not recieved let's initialize it here after 2 sec + initialize(); + console.log('initializing ameyo'); + registerOnAdapterReady(() => { + setAmeyoLoggedIn(); + window.postMessage({ type: 'onAmeyoStatusChange', data: 'ready' }); + console.log('Adapter Ready'); + }); + registerOnCallIncoming((call: StateType) => { + console.log('Incoming Call', call); + }); + registerOnCallConnected((call: StateType) => { + console.log('Call Connected', call); + }); + registerOnCallDisconnected((call: StateType) => { + console.log('Call Disconnected', call); + }); + registerOnAgentAvailabilityChange((isAvailable: boolean) => { + console.log('Agent Availability Changed', isAvailable); + dispatch(setIsAvailable(isAvailable)); + }); + registerOnForcedLogoutListener(() => { + setForcedLogout(true); + }); + window.ameyoInitialized = true; + }, 2000); + }, []); + // --------------- ***** --------------------- + + // there is a third state called authError, in which the user + // is expected to do stuff, so although he is still !loggedIn + // he is also not loggedOut, hence isLoggedOut!=isLoggedIn + + const isLoggedIn = useMemo(() => { + dispatch(setIsAmeyoErronous(false)); + return ( + AMEYO_STATUS_RANKS[AMEYO_STATUS_CODES.LOGGED_IN].occuranceOrder <= + AMEYO_STATUS_RANKS[toolbarAuthState].occuranceOrder + ); + }, [toolbarAuthState]); + + const handleKeyPress = (event: React.KeyboardEvent) => { + if (ameyoExtensionToggleOn && !isAmeyoErronous) { + if (event.ctrlKey && (event.key === 'm' || event.key === 'M')) { + handleMuteOngoingCall(AmeyoConstants.AMEYO_SHORTCUT); + } + } + }; + + const checkConditionsAndSetVisibilityForMuteDisclaimer = () => { + if (currentAmeyoState === AmeyoCallState.TALKING && ameyoCallData.mutedAt) { + dispatch(setIsMuteDisclaimerVisible(true)); + } + }; + + const handleCloseDisclaimer = () => { + dispatch(setIsMuteDisclaimerVisible(false)); + clearInterval(timerId.current); + timerId.current = setInterval(checkConditionsAndSetVisibilityForMuteDisclaimer, 5000); + }; + + const handleCloseAmeyoExtensionDisclaimer = () => { + dispatch(setIsAmeyoExtOffDisclaimerVisible(false)); + }; + + const handleCloseAmeyoErroneousDisclaimer = () => { + dispatch(setShowAmeyoErroneousMsg(false)); + }; + + const isLoggedOut = useMemo(() => { + return ( + AMEYO_STATUS_RANKS[AMEYO_STATUS_CODES.LOGGED_OUT].occuranceOrder >= + AMEYO_STATUS_RANKS[toolbarAuthState].occuranceOrder + ); + }, [toolbarAuthState]); + + const createInteractionApi = (additionalParams: { + phone: string | number; + loanaccountnumber: string; + crtObjectId: string; + }) => { + const { loanaccountnumber, phone, crtObjectId } = additionalParams; + const url = getApiUrl(ApiKeys.CREATE_AMEYO_INTERACTION); + const data: CreateInteractionRequest = { + accountNumber: loanaccountnumber, + recipientPhoneNumber: phone, + callingMode: CALLING_MODES.AUTO_DIALLER, + interactionType: InteractionType.AMEYO, + externalCallId: crtObjectId + }; + console.log('ameyo debugging', 'About to create interaction'); + return axiosInstance.post(url, data).then(resp => { + console.log('ameyo debugging', 'create interaction response in accept call', resp); + setInteractionData({ + interactionId: resp?.data?.referenceId, + recipientNumber: resp?.data?.source.recipientNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + dispatch( + setAmeyoCallDetails({ + interactionId: resp?.data?.referenceId, + recipientNumber: resp?.data?.source.recipientNumber, + crtObjectId: ameyoCallData?.crtObjectId + }) + ); + }); + }; + + const createInteraction = ( + connectedCustomerData: IConnectedCustomer, + lan: string, + phone: string, + crtObjId: string + ) => { + try { + console.log('ameyo debugging', { + ameyoCallData: { lan, crtObjId, phone }, + connectedCustomerData + }); + createInteractionApi({ + loanaccountnumber: lan, + phone: phone + '', + crtObjectId: crtObjId + }) + .catch(err => { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_CREATE_INTERACTION_FAILED, { + lan: lan, + phoneNumber: phone, + crtObjectId: crtObjId + }); + console.log('ameyo debugging', 'error in creating interaction', err); + }) + .finally(() => { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_CALL_ACCEPTED_SUCCESSFULLY, { + loanAccountNumber: lan, + phoneNumber: phone, + crtObjectId: crtObjId + }); + }); + } catch (e) { + toast('Error creating interaction', { type: 'info' }); + } + }; + + const onCallInComingCallback = (phoneNumber: number, lan: string, crtObjectId: string) => { + console.log('ameyo debugging', 'on incoming callback called'); + dispatch(setCurrentState(AmeyoCallState.RINGING)); + console.log('ameyo debugging', 'setting up ameyo call data', { phoneNumber, lan, crtObjectId }); + setCurrentAmeyoCallDetails({ phoneNumber: phoneNumber + '', lan, crtObjectId }); + fetchAndSetConnectedCustomerData({ lan, phoneNumber: String(phoneNumber) }).catch(err => { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_FETCH_CONNECTED_CUSTOMER_FAILED, { + phoneNumber, + lan + }); + toast('Error fetching connected customer data', { type: 'error' }); + }); + }; + const onCallConnectedCallback = (phoneNumber: number, lan: string, crtObjectId: string) => { + // update state to connected , show disconnect button + dispatch(setCurrentState(AmeyoCallState.TALKING)); + ExtensionHandler.updateIsPending(true); + }; + + function performAmeyoStateChangeSideEffect(status: AMEYO_STATUS_CODES, availabilty = false) { + dispatch(setToolbarAuthState(status)); + if ( + AMEYO_STATUS_RANKS[AMEYO_STATUS_CODES.LOGGED_OUT].occuranceOrder >= + AMEYO_STATUS_RANKS[status].occuranceOrder && + authData?.email && + authData?.ameyoKey + ) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_SUCCESSFUL_LOGOUT, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus() + }); + } + // status is anything [loggedIn, ready) + if ( + AMEYO_STATUS_RANKS[AMEYO_STATUS_CODES.READY].occuranceOrder > + AMEYO_STATUS_RANKS[status].occuranceOrder && + AMEYO_STATUS_RANKS[AMEYO_STATUS_CODES.LOGGED_IN].occuranceOrder <= + AMEYO_STATUS_RANKS[status].occuranceOrder + ) { + dispatch(setNotificationBubbleColor(BUBBLE_COLORS.PINK)); + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_SUCCESSFUL_LOGIN); + } + // when ready + if (status === AMEYO_STATUS_CODES.READY) { + dispatch(setNotificationBubbleColor(BUBBLE_COLORS.ORANGE)); + } + if (availabilty) { + dispatch(setNotificationBubbleColor(BUBBLE_COLORS.GREEN)); + } + if (authData?.ameyoKey && !authData?.email) { + toast('No email found, cannot login in ameyo.', { type: 'info' }); + } + } + + function onAmeyoAuthStateChanged(currentState: AMEYO_STATUS_CODES) { + if (currentState === AMEYO_STATUS_CODES.LOGGED_IN) { + if (!authError) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_LOGIN_AUTO_SUCCESSFUL, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + } + + authError = false; + } else if (currentState === AMEYO_STATUS_CODES.AUTH_ERROR) { + authError = true; + } + + performAmeyoStateChangeSideEffect(currentState, ExtensionHandler.isAvailable()); + } + + function onAmeyoAvailabiltyChanged(isAvailable: boolean) { + dispatch(setIsAvailable(isAvailable)); + } + + function onAmeyoCallDataChanged(callData: AmeyoCallData) { + console.log('ameyo debugging', 'call data changed', callData); + dispatch(setAmeyoCallData(callData)); + const resetValue = LocalStorage.getItem(LOCAL_STORAGE_KEYS.AMEYO_CALL_RESET_FLAG); + const isResetAllowed = resetValue ? resetValue === 'true' : false; + isResetAllowed && resetButtonState(); + } + + function resetButtonState() { + dispatch( + setButtonLoadingStates({ + ...buttonLoadingStates, + acceptButton: false, + rejectButton: false, + disconnectButton: false + }) + ); + } + const onAmeyoErroneous = () => { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_ERRONEOUS, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus() + }); + + dispatch(setIsAmeyoErronous(true)); + }; + + const onToggleAmeyoStatus = (onToggleAmeyoStatusData: onToggleAmeyoStatusDataProps) => { + if (onToggleAmeyoStatusData.ameyoToggleNewStatus === AmeyoToggleNewStatus.OFF) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_EXTENSION_TOGGLE_OFF_CLICKED, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + + dispatch(setAmeyoExtensionToggleOn(false)); + + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_EXTENSION_TOGGEL_OFF_SUCCESSFULL, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + return; + } + if (onToggleAmeyoStatusData.ameyoToggleNewStatus === AmeyoToggleNewStatus.ON) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_EXTENSION_TOGGLE_ON_CLICKED, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + + dispatch(setAmeyoExtensionToggleOn(true)); + + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_EXTENSION_TOGGEL_ON_SUCCESSFULL, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + return; + } + }; + + const agentOnlineHandler = () => { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_AVAILABLE_TOGGLE_CLICKED, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus() + }); + if (getAgentAvailability()) { + setOnBreak(); + } else { + setAvailable(); + } + }; + + const hangupCall = (type: string) => { + rejectCallNew(); + newAmeyoResync(); + return; + }; + + const newAmeyoResync = () => { + if (getLatestCallState() === 'IDLE' || getLatestCallState() === 'CALL_DISCONNECTED') { + dispatch(resetState()); + } + return; + }; + + function acceptCall() { + acceptCallNew(); + newAmeyoResync(); + if (buttonLoadingStates.acceptButton) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.LH_AMEYO_CALL_DISABLED_ACCEPT_CLICKED, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + + return; + } + + createInteraction( + connectedCustomerData, + currentAmeyoCallDetails?.lan || '', + currentAmeyoCallDetails?.phoneNumber || '', + currentAmeyoCallDetails?.crtObjectId || '' + ); + dispatch(setShouldPlayRingtone(false)); + dispatch( + setButtonLoadingStates({ ...buttonLoadingStates, acceptButton: true, rejectButton: true }) + ); + console.log('ameyo debugging', 'interaction data', interactionData); + navigateToCaseDetail(); + + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_CALL_ACCEPT_CLICKED, { + loanAccountNumber: currentAmeyoCallDetails?.lan, + phoneNumber: currentAmeyoCallDetails?.phoneNumber, + crtObjectId: currentAmeyoCallDetails?.crtObjectId + }); + if (isAmeyoErronous) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_ACCEPT_ERROR, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + } + } + + function rejectCall() { + if (buttonLoadingStates.rejectButton) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.LH_AMEYO_CALL_DISABLED_REJECT_CLICKED, { + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus(), + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber + }); + + return; + } + + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_CALL_REJECT_CLICKED, { + loanAccountNumber: currentAmeyoCallDetails?.lan, + phoneNumber: currentAmeyoCallDetails?.phoneNumber, + crtObjectId: currentAmeyoCallDetails?.crtObjectId + }); + if (isAmeyoErronous) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_REJECT_ERROR, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + } + rejectCallNew(); + } + + const handleMuteOngoingCall = (type: string) => { + if (isAmeyoErronous) { + dispatch(setShowAmeyoErroneousMsg(true)); + if (ameyoCallData?.mutedAt) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_UNMUTE_ERROR, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + return; + } + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_MUTE_ERROR, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + + return; + } + if (!ameyoExtensionToggleOn) { + dispatch(setIsAmeyoExtOffDisclaimerVisible(true)); + return; + } + if (ameyoCallData?.mutedAt) { + if (type === AmeyoConstants.AMEYO_WIDGET) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_UNMUTE_WIDGET_CLICKED, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + } + if (type === AmeyoConstants.AMEYO_TOOLBAR) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_UNMUTE_TOOLBAR_CLICKED, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + } + unmuteCallNew(); + ExtensionHandler.unMuteCall(() => { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_UNMUTE_SUCCESSFULL, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.lan, + crtObjectId: ameyoCallData?.crtObjectId + }); + }); + + return; + } + + if (type === AmeyoConstants.AMEYO_WIDGET) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_MUTE_WIDGET_CLICKED, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + crtObjectId: ameyoCallData?.crtObjectId + }); + } + if (type === AmeyoConstants.AMEYO_TOOLBAR) { + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_MUTE_TOOLBAR_CLICKED, { + loanAccountNumber: ameyoCallData?.lan, + phoneNumber: ameyoCallData?.phoneNumber, + campaignId, + ameyoStatus: ExtensionHandler.currentAmeyoStatus() + }); + } + muteCallNew(); + }; + const onAmeyoAcceptError = () => { + resetButtonState(); + }; + + function navigateToCaseDetail() { + if (!connectedCustomerData?.customerName) { + toast('Please use LAN search to navigate to this case.', { type: 'info' }); + return; + } + const searchParams = createQueryParams({ + AMEYO: { phoneNumber: connectedCustomerData?.phoneNumber || '', method: ECallingType.AMEYO } + }); + navigateToCaseDetails( + connectedCustomerData?.customerId || '', + connectedCustomerData?.lan || '', + connectedCustomerData?.caseReferenceId || '', + connectedCustomerData?.businessVertical || '', + navigate, + APP_ROUTES.CASE_DETAIL.path, + searchParams + ); + } + + function fetchAndSetConnectedCustomerData(params: { lan: string; phoneNumber: string }) { + const lan = params?.lan || connectedCustomerData.lan; + const phoneNumber = params?.phoneNumber || connectedCustomerData.phoneNumber; + let getCustomerReferenceIdPromise = null; + let getTelephonesPromise = null; + if (lan && phoneNumber) { + getCustomerReferenceIdPromise = getCustomerReferenceIdFromLAN( + lan, + (loanAccountNumber: string, customerDetails: AllCasesSummary) => { + if (loanAccountNumber && customerDetails?.customerId) { + dispatch(getCustomerDetails(loanAccountNumber, customerDetails.customerId)); + dispatch( + setConnectedCustomerData({ + lan, + phoneNumber, + customerId: customerDetails?.customerId, + customerName: customerDetails?.customerName, + caseReferenceId: customerDetails?.caseReferenceId, + businessVertical: customerDetails?.businessVertical + }) + ); + } + } + ); + // checked on BE customerId is not null + // Also it is not required to check for phoneNumber + getTelephonesPromise = getTelephones(lan, '', (telephones: ITelePhoneData[]) => { + const source = + telephones?.find(telephone => telephone.number === phoneNumber)?.source || ''; + dispatch( + setTelephoneSource( + PhoneNumberSources?.[source as keyof typeof PhoneNumberSources] ?? source + ) + ); + }); + } + return Promise.all([getCustomerReferenceIdPromise, getTelephonesPromise]); + } + + useOutsideClick(currentRef, () => { + dispatch(setIsVisible(false)); + }); + + const onSendCurrentCallStatus = (data?: IAmeyoRecalibratedData) => { + if ( + data?.callStatus === AMEYO_CALL_EVENTS.DISCONNECTED || + data?.callStatus === AMEYO_CALL_EVENTS.IDLE + ) { + dispatch(resetState()); + return; + } else if (data?.callStatus === AMEYO_CALL_EVENTS.CONNECTED) { + dispatch(setCurrentState(AmeyoCallState.TALKING)); + if (connectedCustomerData?.lan) { + return; + } + fetchAndSetConnectedCustomerData({ lan: data?.lan, phoneNumber: data?.phoneNumber }); + } + }; + + useEffect(() => { + isLitmusExperimentEnabled(LITMUS_EXPERIMENT_NAMES.COLLECTION_AMEYO_FIX, { + 'x-customer-id': authData?.referenceId + }).then(res => { + LocalStorage.setItem(LOCAL_STORAGE_KEYS.AMEYO_CALL_RESET_FLAG, res?.result); + }); + }, []); + + useEffect(() => { + dispatch(setAmeyoCallData(ExtensionHandler.currentCallStatus())); + dispatch(setIsAvailable(ExtensionHandler.isAvailable())); + }, []); + + useEffect(() => { + performAmeyoStateChangeSideEffect( + ExtensionHandler.currentAmeyoStatus(), + ExtensionHandler.isAvailable() + ); + }, [authData]); + + useEffect(() => { + if ( + currentAmeyoState === AmeyoCallState.TALKING && + ameyoExtensionToggleOn && + !isAmeyoErronous + ) { + const onKeyDown = (event: any) => handleKeyPress(event); + document.addEventListener('keydown', onKeyDown); + + return () => { + document.removeEventListener('keydown', onKeyDown); + }; + } + }, [currentAmeyoState, ameyoCallData, ameyoExtensionToggleOn, isAmeyoErronous]); + + useEffect(() => { + checkConditionsAndSetVisibilityForMuteDisclaimer(); + timerId.current = setInterval( + checkConditionsAndSetVisibilityForMuteDisclaimer, + AMEYO_MUTE_DISCLAIMER_INTERVAL + ); + + return () => { + clearInterval(timerId.current); + }; + }, [ameyoCallData]); + + useEffect(() => { + if (currentAmeyoState === AmeyoCallState.TALKING && !isVisible) { + if (!ameyoExtensionToggleOn && !isAmeyoErronous) { + dispatch(setIsAmeyoExtOffDisclaimerVisible(true)); + return; + } + + dispatch(setIsAmeyoExtOffDisclaimerVisible(false)); + } + }, [ameyoExtensionToggleOn, isAmeyoErronous]); + + useEffect(() => { + if (currentAmeyoState === AmeyoCallState.TALKING && !isVisible) { + if (isAmeyoErronous) { + dispatch(setShowAmeyoErroneousMsg(true)); + return; + } + dispatch(setShowAmeyoErroneousMsg(false)); + } + }, [isAmeyoErronous]); + + useEffect(() => { + /** + * this would be the case if someone opens the new tab while he is on call + */ + if (currentAmeyoState === AmeyoCallState.TALKING && !connectedCustomerData?.customerName) { + fetchAndSetConnectedCustomerData({ + lan: connectedCustomerData.lan, + phoneNumber: connectedCustomerData.phoneNumber + }); + } + resetButtonState(); + }, [currentAmeyoState]); + useEffect(() => { + if ( + currentAmeyoState === AmeyoCallState.RINGING || + currentAmeyoState === AmeyoCallState.TALKING + ) { + window.addEventListener('beforeunload', handleTabClose); + props.isCallHappening(true); + } + if ( + currentAmeyoState !== AmeyoCallState.RINGING && + currentAmeyoState !== AmeyoCallState.TALKING + ) { + props.isCallHappening(false); + } + return () => { + window.removeEventListener('beforeunload', handleTabClose); + }; + }, [currentAmeyoState]); + + useEffect(() => { + if ( + buttonLoadingStates.disconnectButton || + buttonLoadingStates.rejectButton || + buttonLoadingStates.acceptButton + ) { + setTimeout(resetButtonState, BUTTON_ENABLED_TIMEOUT); + } + }, [buttonLoadingStates]); + + useEffect(() => { + if (currentAmeyoState === AmeyoCallState.RINGING) { + dispatch(setIsVisible(true)); + dispatch(setShouldPlayRingtone(true)); + fetchAndSetConnectedCustomerData({ + lan: connectedCustomerData.lan, + phoneNumber: connectedCustomerData.phoneNumber + }); + addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_RINGING, { + ringingAt: ameyoCallData?.ringingAt, + acceptedAt: ameyoCallData?.acceptedAt, + disconnectedAt: ameyoCallData?.disconnectedAt, + mutedAt: ameyoCallData?.mutedAt, + unMutedAt: ameyoCallData?.unMutedAt, + phoneNumber: currentAmeyoCallDetails?.phoneNumber, + lan: currentAmeyoCallDetails?.lan, + crtObjectId: currentAmeyoCallDetails?.crtObjectId + }); + } + }, [currentAmeyoState]); + + useEffect(() => { + if ( + !( + currentAmeyoState === AmeyoCallState.TALKING || currentAmeyoState === AmeyoCallState.RINGING + ) + ) { + dispatch( + setConnectedCustomerData({ phoneNumber: '', lan: '', customerId: '', customerName: '' }) + ); + dispatch(setTelephoneSource('')); + } + }, [currentAmeyoState]); + + useEffect(() => { + const link = document.createElement('link'); + link.type = 'image/svg+xml'; + link.rel = 'icon'; + + const svgString = jsxToString(ameyoCallData.mutedAt ? : ); + const svgBlob = new Blob([svgString], { type: 'image/svg+xml' }); + + link.href = URL.createObjectURL(svgBlob); + + const existingFavicon = document.querySelector('link[rel="icon"]'); + + if (existingFavicon) { + document.head.removeChild(existingFavicon); + } + + document.head.appendChild(link); + + return () => { + URL.revokeObjectURL(link.href); + document.head.removeChild(link); + }; + }, [ameyoCallData]); + + useEffect(() => { + if (toolbarAuthState === AMEYO_STATUS_CODES.AUTH_ERROR) { + dispatch(setIsVisible(true)); + } + }, [toolbarAuthState, isLoggedIn]); + + // useEffect(() => { + // performAmeyoStateChangeSideEffect(ExtensionHandler.currentAmeyoStatus(), isAmeyoAvailable); + // }, [isAmeyoAvailable]); + + // useEffect(() => { + // const checkAvailabilityAndCallEvent = () => { + // if (naviExtension.isAvailable()) { + // addClickstreamEvent(AMEYO_SESSION_EVENTS.LH_AMEYO_USER_AVAILABILITY); + // } + // }; + // + // checkAvailabilityAndCallEvent(); + // + // const intervalId = setInterval(checkAvailabilityAndCallEvent, 30000); + // + // return () => clearInterval(intervalId); + // }, []); + + const onCallDisConnectedCallback = (phoneNumber: number, lan: string, crtObjectId: string) => { + dispatch(setCurrentState(AmeyoCallState.IDLE)); + }; + const isTalkingOrRinging = useMemo( + () => + currentAmeyoState === AmeyoCallState.RINGING || currentAmeyoState === AmeyoCallState.TALKING, + [currentAmeyoState] + ); + const showExtensionDisabledMessage = + currentAmeyoState === AmeyoCallState.TALKING && + isAmeyoExtOffDisclaimerVisible && + !isAmeyoErronous && + !isVisible; + const showOngoingMutedCallDisclaimer = + currentAmeyoState === AmeyoCallState.TALKING && + ameyoCallData.mutedAt && + ameyoExtensionToggleOn && + !isAmeyoExtOffDisclaimerVisible && + !showAmeyoErroneousMsg && + !isAmeyoErronous && + !isVisible; + const bottomValue = + currentAmeyoState === AmeyoCallState.TALKING && (!ameyoExtensionToggleOn || isAmeyoErronous) + ? -68 + : toolbarAuthState === AMEYO_STATUS_CODES.READY + ? -57 + : 2; + + useEffect(() => { + ExtensionHelper.addExtensionListener(EXTENSION_LISTENER_TYPES.ameyoErroneous, onAmeyoErroneous); + ExtensionHelper.addExtensionListener( + EXTENSION_LISTENER_TYPES.onCallInComing, + onCallInComingCallback + ); + ExtensionHelper.addExtensionListener( + EXTENSION_LISTENER_TYPES.onCallConnected, + onCallConnectedCallback + ); + ExtensionHelper.addExtensionListener( + EXTENSION_LISTENER_TYPES.onCallDisConnected, + onCallDisConnectedCallback + ); + }, []); + + useEffect(() => { + ExtensionHelper.addExtensionListener( + EXTENSION_LISTENER_TYPES.toggleAmeyoStatus, + onToggleAmeyoStatus + ); + }, []); + + useEffect(() => { + isLitmusExperimentEnabled(LITMUS_EXPERIMENT_NAMES.COLLECTION_AMEYO_CALL_COUNT_POLLING, { + 'x-customer-id': authData?.referenceId + }).then(res => { + if (res?.result) { + setCallCountEnabled(true); + if (isVisible) { + ameyoCallsCountIntervalRef.current = poll( + () => { + dispatch( + getCallBridgeData({ includeAmeyoCallCount: true, includeCallBridgeCount: false }) + ); + }, + undefined, + AMEYO_CALL_COUNT_POLLING_INTERVAL, + noop + ); + } else { + isFunction(ameyoCallsCountIntervalRef.current) && ameyoCallsCountIntervalRef.current(); + } + } else { + setCallCountEnabled(false); + } + }); + return () => { + isFunction(ameyoCallsCountIntervalRef.current) && ameyoCallsCountIntervalRef.current(); + }; + }, [isVisible]); + + return ( +
+
+ { +
+ + +
handleMuteOngoingCall(AmeyoConstants.AMEYO_TOOLBAR)} + className={ + ameyoExtensionToggleOn && !isAmeyoErronous + ? styles.muteUnmuteToolTipWrapper + : styles.disabledUnmuteToolTipWrapper + } + > + {ameyoCallData?.mutedAt ? : } +
+
+ {ameyoExtensionToggleOn && !isAmeyoErronous && ( + + {ameyoCallData?.mutedAt + ? AmeyoConstants.UNMUTE_ONGOING_CALL_TOOLTIP + : AmeyoConstants.MUTE_ONGOING_CALL_TOOLTIP} + + )} +
+ + +
hangupCall(AmeyoConstants.AMEYO_TOOLBAR)} + className={ + ameyoExtensionToggleOn && !isAmeyoErronous + ? styles.diconnectBtnWrapper + : styles.disabledDiconnectBtnWrapper + } + > + +
+
+ {ameyoExtensionToggleOn && !isAmeyoErronous && ( + + {AmeyoConstants.DISCONNECT_ONGOING_AMEYO_CALL} + + )} +
+
+ } +
{ + dispatch(setIsVisible(!isVisible)); + }} + className={styles.toolbarWrapper} + > + +
+ +
+
+ {isLoggedIn ? ( +
+ ) : toolbarAuthState === AMEYO_STATUS_CODES.AUTH_ERROR ? ( +
+

!

+
+ ) : ( +
+ +
+ )} +
+ + Ameyo + + {currentAmeyoState === AmeyoCallState.TALKING && showAmeyoErroneousMsg && !isVisible && ( +
+ {AmeyoConstants.AMEYO_ERRONEOUS_MSG} + { + handleCloseAmeyoErroneousDisclaimer(); + }} + > + + +
+ )} + {showExtensionDisabledMessage && ( +
+ {AmeyoConstants.AMEYO_EXTENSION_DISABLED_MSG} + { + handleCloseAmeyoExtensionDisclaimer(); + }} + > + + +
+ )} + {showOngoingMutedCallDisclaimer && ( +
+ {AmeyoConstants.ONGOING_MUTED_CALL_DICLAIMER} + { + handleCloseDisclaimer(); + }} + > + + +
+ )} +
+ {multiTabDialerDisabled ? ( +
+

+ Dialer is disabled since ameyo is active on another tab +

+ { + dispatch(setIsVisible(false)); + }} + className={styles.paddedSpan} + > + + +
+ ) : null} + {isLoggedIn && !multiTabDialerDisabled ? ( + <> + {toolbarAuthState === AMEYO_STATUS_CODES.READY ? ( +
+ + {toolbarAuthState === AMEYO_STATUS_CODES.READY && !isTalkingOrRinging ? ( + + ) : ( + + + {connectedCustomerData?.phoneNumber}{' '} + {telephoneSource ? telephoneSource : ''} + + + )} +
+ {currentAmeyoState === AmeyoCallState.TALKING && ( + + + handleMuteOngoingCall(AmeyoConstants.AMEYO_WIDGET)} + className={ + ameyoExtensionToggleOn && !isAmeyoErronous + ? '' + : styles.disabledMuteIconWraper + } + > + {ameyoCallData?.mutedAt ? : } + + + {ameyoExtensionToggleOn && !isAmeyoErronous && ( + + {ameyoCallData?.mutedAt + ? AmeyoConstants.UNMUTE_ONGOING_CALL_TOOLTIP + : AmeyoConstants.MUTE_ONGOING_CALL_TOOLTIP} + + )} + + )} + { + dispatch(setIsVisible(false)); + ExtensionHandler.getCurrentCallStatus(); + }} + className={styles.paddedSpan} + > + + +
+
+
+ {currentAmeyoState === AmeyoCallState.RINGING ? ( +
+ + + + {connectedCustomerData?.customerName || 'A Customer'} + {' '} + is on the call.
+
+ + LAN : {ameyoCallData?.lan} + +
+
+
+ Accept +
+
+ Reject +
+
+
+ ) : currentAmeyoState === AmeyoCallState.TALKING ? ( +
+ + + + {connectedCustomerData?.customerName || 'A Customer'} + {' '} + is on the call.
+
+ + LAN : {ameyoCallData?.lan} + +
+
+
hangupCall(AmeyoConstants.AMEYO_WIDGET)} + > + Disconnect +
+
+
+ ) : ( +
+ {callCountEnabled && ( + + )} + + {isAmeyoAvailable ? ( + + Please wait while we connect you with a customer... + + ) : ( + + Please Mark yourself as Available using the toggle above to start + receiving calls + + )} + +
+ )} +
+ {currentAmeyoState === AmeyoCallState.TALKING && + (!ameyoExtensionToggleOn || isAmeyoErronous) && ( +
+ +
+ {isAmeyoErronous + ? AmeyoConstants.AMEYO_ERRONEOUS_MSG + : AmeyoConstants.AMEYO_EXTENSION_DISABLED_MSG} +
+
+ )} +
+ ) : ( + + + + Please wait... Ameyo is loading + + + + { + dispatch(setIsVisible(false)); + ExtensionHandler.getCurrentCallStatus(); + }} + > + + + + + )} + + ) : authData?.userImpersonated ? ( +
+

Dialer is disabled.

+ { + dispatch(setIsVisible(false)); + ExtensionHandler.getCurrentCallStatus(); + }} + className={styles.paddedSpan} + > + + +
+ ) : isLoggedOut ? ( +
+

We are trying to log you into Ameyo...

+ { + dispatch(setIsVisible(false)); + ExtensionHandler.getCurrentCallStatus(); + }} + className={styles.paddedSpan} + > + + +
+ ) : toolbarAuthState === AMEYO_STATUS_CODES.AUTH_ERROR ? ( +
+

+ An error occurred. +
+ { + ExtensionHandler.focusAmeyoTab(); + }} + className={styles.goToAmeyoCTA} + > + Go to Ameyo + {' '} + to login . +

+ { + dispatch(setIsVisible(false)); + }} + className={styles.paddedSpan} + > + + +
+ ) : ( + <> + )} +
+ setForcedLogout(false)} + relogin={() => window.location.reload()} + /> +
+ ); +}; diff --git a/src/components/Ameyo/broadcastChannelMessage.ts b/src/components/Ameyo/broadcastChannelMessage.ts new file mode 100644 index 00000000..3c8bccbd --- /dev/null +++ b/src/components/Ameyo/broadcastChannelMessage.ts @@ -0,0 +1,4 @@ +export enum BroadcastChannelMessages { + 'ask_for_ameyo_initiation' = 'ask_for_ameyo_initiation', + 'already_initialized' = 'already_initiated' +} diff --git a/src/components/Ameyo/forcedLogoutDialog.tsx b/src/components/Ameyo/forcedLogoutDialog.tsx new file mode 100644 index 00000000..47323ead --- /dev/null +++ b/src/components/Ameyo/forcedLogoutDialog.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import Modal from '@cp/components/Modal/Modal'; +import { Button } from '@primitives'; + +type ForceLogoutDialogProps = { + isVisible: boolean; + setOnClose: () => void; + relogin: () => void; +}; + +export const ForcedLogoutDialog = ({ isVisible, setOnClose, relogin }: ForceLogoutDialogProps) => { + return ( +
+ + Ameyo is logged out due to multiple login attempts. Please login again. + + +
+ ); +}; + +export default ForcedLogoutDialog; diff --git a/src/components/sidebar/SideNavBar.tsx b/src/components/sidebar/SideNavBar.tsx index 8fd918e7..7a370dc4 100644 --- a/src/components/sidebar/SideNavBar.tsx +++ b/src/components/sidebar/SideNavBar.tsx @@ -4,6 +4,7 @@ import cx from 'classnames'; import { Link, useLocation } from 'react-router-dom'; // styles import styles from './SideNavBar.module.scss'; + // functions, components and utlis import NaviNewLogoIcon from '@navi/web-ui/lib/icons/NaviLogoIcon/NaviNewLogoIcon'; import SideBarItems, { DASHBOARD_URL, HideSideBar } from './SideBarItems'; @@ -77,6 +78,7 @@ import AgencyIcon from '@cp/src/assets/icons/AgencyIcon'; import RefreshIcon from '@icons/RefreshIcon'; import AgencyOperationsIcon from '@cp/assets/icons/AgencyOperationsIcon'; import { noop } from '@utils/common'; +import { AmeyoCollapsibleToolbarV4 } from '@cp/components/Ameyo/AmeyoCollapsibleToolbarV4'; interface ISideNavbarProps { isDc97User?: boolean; @@ -181,6 +183,16 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) { const isAgencyCappingEnabled = useSelector( (store: RootState) => store?.common?.featureFlags?.agencyCappingEnabled ); + + const [isAmeyoNewIntegrationEnabled, setIsAmeyoNewIntegrationEnabled] = useState(false); + + useEffect(() => { + isLitmusExperimentEnabled(LITMUS_EXPERIMENT_NAMES.COLLECTION_AMEYO_TELE_V3, { + 'x-customer-id': userData?.referenceId + }).then(res => { + setIsAmeyoNewIntegrationEnabled(res?.result); + }); + }, []); const cleanupAndLogout = () => { clearParamsMap(); dispatch(setAuthData({ token: null })); @@ -250,7 +262,7 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) { ExtensionHandler.setAvailability(!isAgentOnline, clickStreamData); } else { - if (user?.email && user?.ameyoKey && user?.token) { + if (user?.email && user?.ameyoKey && user?.token && !isAmeyoNewIntegrationEnabled) { ExtensionHandler.login(user.email, user.ameyoKey); } toast('Ameyo is not ready yet', { type: 'error' }); @@ -844,11 +856,17 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) { isAgentOfflineInLonghorn || isLonghornBlocked || !isAgentWithInOperativeHours })} > - { - setDisableLogout(isHappening); - }} - /> + {isAmeyoNewIntegrationEnabled ? ( + setDisableLogout(isHappening)} + /> + ) : ( + { + setDisableLogout(isHappening); + }} + /> + )} ) : ( <> diff --git a/web-ui-library b/web-ui-library index 2f13d09f..58388435 160000 --- a/web-ui-library +++ b/web-ui-library @@ -1 +1 @@ -Subproject commit 2f13d09faacbaec1235b8fa669c1549d8fc67de8 +Subproject commit 58388435d2f494b1db0ce353a5e998c4f10af96b diff --git a/yarn.lock b/yarn.lock index e5ebeebc..1fea739c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2262,6 +2262,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz" integrity sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg== +"@types/node@^22.7.7": + version "22.10.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.0.tgz#89bfc9e82496b9c7edea3382583fa94f75896e81" + integrity sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA== + dependencies: + undici-types "~6.20.0" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz" @@ -2468,6 +2475,28 @@ "@typescript-eslint/types" "5.56.0" eslint-visitor-keys "^3.3.0" +"@universal-call-sdk/adapter-ameyo@^1.0.61": + version "1.0.61" + resolved "https://nexus.cmd.navi-tech.in/repository/npm-packages/@universal-call-sdk/adapter-ameyo/-/adapter-ameyo-1.0.61.tgz#f2912e2688eb2b778045990db3d562d5af4ccaaf" + integrity sha512-Ti1vZx1l78jHFcIs2Dn1yOSxzVkbNfWIcyeIfP1LpF5Ef5kqHoUv2YKqe7VncyDBTFW+GotAYEX9fJQ6Oh5rKQ== + dependencies: + "@universal-call-sdk/common" "^1.0.16" + +"@universal-call-sdk/common@^1.0.16": + version "1.0.16" + resolved "https://nexus.cmd.navi-tech.in/repository/npm-packages/@universal-call-sdk/common/-/common-1.0.16.tgz#a5e8263a1b104f3628bef936f490200729e0ee8f" + integrity sha512-JE7yoSmIkAl5hYsBqnx4R379TIV6ZF3T0dMyfXlmaJMaGs/okx0YBAB4CQ1F98Wi55UiK/kXOgvEfeVuPl6xkQ== + +"@universal-call-sdk/core@^1.0.21": + version "1.0.21" + resolved "https://nexus.cmd.navi-tech.in/repository/npm-packages/@universal-call-sdk/core/-/core-1.0.21.tgz#88ab569f58e1f929fcad5d51264416107d0ab4fc" + integrity sha512-YLKAaGxrGKjUYd0kWeNKQsM9STrow+g5usIGB4SFy57hFgw9967MuxOcOx9MrGTQqfxIoHXnmsrbB7Su374Crw== + dependencies: + "@types/node" "^22.7.7" + path "^0.12.7" + react "17.0.2" + react-dom "17.0.2" + "@vitejs/plugin-react@4.0.3": version "4.0.3" resolved "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.3.tgz" @@ -8054,6 +8083,14 @@ path-type@^4.0.0: resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== + dependencies: + process "^0.11.1" + util "^0.10.3" + pathe@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz" @@ -8233,6 +8270,11 @@ process-nextick-args@~2.0.0: resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.1: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + processenv@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/processenv/-/processenv-1.1.0.tgz#3867422468954f1af82ce7bfb944c8adadd5cdf7" @@ -8434,6 +8476,15 @@ react-custom-scrollbars@^4.2.0: prop-types "^15.5.10" raf "^3.1.0" +react-dom@17.0.2, react-dom@^17.0.2: + version "17.0.2" + resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/react-dom/-/react-dom-17.0.2.tgz" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + react-dom@^15.6.1: version "15.7.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-15.7.0.tgz" @@ -8444,15 +8495,6 @@ react-dom@^15.6.1: object-assign "^4.1.0" prop-types "^15.5.10" -react-dom@^17.0.2: - version "17.0.2" - resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - react-google-recaptcha@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz" @@ -8626,6 +8668,14 @@ react-window@^1.8.10: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" +react@17.0.2, react@^17.0.2: + version "17.0.2" + resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/react/-/react-17.0.2.tgz" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + react@^15.6.1: version "15.7.0" resolved "https://registry.npmjs.org/react/-/react-15.7.0.tgz" @@ -8637,14 +8687,6 @@ react@^15.6.1: object-assign "^4.1.0" prop-types "^15.5.10" -react@^17.0.2: - version "17.0.2" - resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - read-cache@^1.0.0: version "1.0.0" resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/read-cache/-/read-cache-1.0.0.tgz" @@ -10052,6 +10094,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + unique-filename@^1.1.1: version "1.1.1" resolved "https://nexus.cmd.navi-tech.in/repository/navi-commons/unique-filename/-/unique-filename-1.1.1.tgz" @@ -10174,6 +10221,13 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +util@^0.10.3: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"