UNPKG

ringcentral-widgets

Version:
354 lines (334 loc) 11.9 kB
import { RcUIModuleV2 } from '@ringcentral-integration/core'; import { ObjectMapValue } from '@ringcentral-integration/core/lib/ObjectMap'; import { filter, find, values } from 'ramda'; import { Module } from 'ringcentral-integration/lib/di'; import { ConferenceCall, LastCallInfo, } from 'ringcentral-integration/modules/ConferenceCallV2'; import { Webphone } from 'ringcentral-integration/modules/WebphoneV2'; import callDirections from '../../../ringcentral-integration/enums/callDirections'; import { NormalizedSession } from '../../../ringcentral-integration/interfaces/Webphone.interface'; import { formatNumber } from '../../../ringcentral-integration/lib/formatNumber'; import callingModes from '../../../ringcentral-integration/modules/CallingSettings/callingModes'; import { sessionStatus } from '../../../ringcentral-integration/modules/Webphone/sessionStatus'; import callCtrlLayouts from '../../enums/callCtrlLayouts'; import { CallControlComponentProps, Deps, getLastCallInfoFromWebphoneSession, } from './CallControlUI.interface'; @Module({ name: 'CallControlUI', deps: [ 'Webphone', 'Locale', 'ContactMatcher', 'RegionSettings', 'Brand', 'ContactSearch', 'CallingSettings', 'ConnectivityManager', 'ForwardingNumber', 'CallMonitor', 'ExtensionInfo', { dep: 'ConferenceCall', optional: true }, { dep: 'RouterInteraction', optional: true }, ], }) export class CallControlUI extends RcUIModuleV2<Deps> { constructor(deps: Deps) { super({ deps, }); } getUIProps({ params, showCallQueueName = false, showPark = false, children, }: CallControlComponentProps) { const { brand, callingSettings, conferenceCall, connectivityManager, contactMatcher, contactSearch, forwardingNumber, regionSettings, locale, webphone, } = this._deps; const sessionId = params?.sessionId; const currentSession = (sessionId ? find((session) => session.id === sessionId, webphone.sessions) : webphone.activeSession) || ({} as NormalizedSession); const contactMapping = contactMatcher?.dataMapping; const fromMatches = contactMapping?.[currentSession.from] ?? []; const toMatches = contactMapping?.[currentSession.to] ?? []; const nameMatches = currentSession.direction === callDirections.outbound ? toMatches : fromMatches; const isWebRTC = callingSettings.callingMode === callingModes.webphone; const isInboundCall = currentSession.direction === callDirections.inbound; let lastCallInfo = conferenceCall?.lastCallInfo; const conferenceCallEquipped = conferenceCall?.hasPermission ?? false; const conferenceData = conferenceCallEquipped ? values(conferenceCall.conferences)[0] : undefined; const isOnConference = conferenceCallEquipped ? conferenceCall.isConferenceSession(currentSession.id) : false; const isMerging = conferenceCallEquipped && conferenceCall.isMerging; const conferenceCallId = conferenceData && isWebRTC ? conferenceData.conference.id : null; const isConferenceCallOverload = conferenceData && isWebRTC ? conferenceCall.isOverload(conferenceCallId) : false; const hasConferenceCall = !!conferenceData; const conferenceCallParties = conferenceCallEquipped ? conferenceCall.partyProfiles : undefined; // TODO: investigate whether this can simply use isMerging const fromSessionId = conferenceCallEquipped ? conferenceCall.mergingPair?.fromSessionId : undefined; const hideChildren = conferenceCallEquipped && !isInboundCall && fromSessionId && fromSessionId !== currentSession.id; lastCallInfo && lastCallInfo.status !== sessionStatus.finished; if (currentSession.warmTransferSessionId) { const warmTransferSession = webphone.sessions.find( (session) => session.id === currentSession.warmTransferSessionId, ); lastCallInfo = getLastCallInfoFromWebphoneSession(warmTransferSession); } const disableLinks = !!( connectivityManager.isOfflineMode || connectivityManager.isVoipOnlyMode ); return { brand: brand.fullName, nameMatches, currentLocale: locale.currentLocale, session: currentSession, areaCode: regionSettings.areaCode, countryCode: regionSettings.countryCode, showBackButton: true, // callMonitor.calls.length > 0, searchContactList: contactSearch.sortedResult, showSpinner: isMerging, conferenceCallEquipped, hasConferenceCall, conferenceCallParties, conferenceCallId, lastCallInfo, // TODO: investigate whether it's better to just // use isMerging and let the component decide whether to display children children: hideChildren ? null : children, isOnConference, isWebRTC, disableLinks, isConferenceCallOverload, disableFlip: forwardingNumber.flipNumbers.length === 0, showCallQueueName, showPark, }; } getInitialLayout = ({ conferenceCallEquipped, isOnConference, lastCallInfo, session, }: { conferenceCallEquipped: boolean; isOnConference: boolean; lastCallInfo?: LastCallInfo; session?: NormalizedSession; }) => { const { conferenceCall, webphone } = this._deps; let layout = callCtrlLayouts.normalCtrl; if (session.warmTransferSessionId) { return callCtrlLayouts.completeTransferCtrl; } if (!conferenceCallEquipped) { return layout; } if (isOnConference) { return callCtrlLayouts.conferenceCtrl; } const isInboundCall = session.direction === callDirections.inbound; const { fromSessionId } = conferenceCall.mergingPair; const fromSession = find( (x: any) => x.id === fromSessionId, webphone.sessions, ); const activeSessionId = webphone && webphone.activeSession && webphone.activeSession.id; if ( !isOnConference && !isInboundCall && fromSession && fromSessionId !== session.id && lastCallInfo && (session.callStatus !== sessionStatus.onHold || (session.callStatus === sessionStatus.onHold && session.id === activeSessionId)) ) { // enter merge ctrl page. layout = callCtrlLayouts.mergeCtrl; } return layout; }; getUIFunctions({ getAvatarUrl, onBackButtonClick, phoneTypeRenderer, phoneSourceNameRenderer, }: CallControlComponentProps) { const { conferenceCall, webphone, regionSettings, extensionInfo, callingSettings, callMonitor, routerInteraction, contactSearch, } = this._deps; return { getInitialLayout: this.getInitialLayout, formatPhone: (phoneNumber: string) => formatNumber({ phoneNumber, areaCode: regionSettings.areaCode, countryCode: regionSettings.countryCode, siteCode: extensionInfo?.site?.code ?? '', isMultipleSiteEnabled: extensionInfo.isMultipleSiteEnabled, }), onHangup: ( sessionId: string, layout: ObjectMapValue<typeof callCtrlLayouts>, ) => { webphone.hangup(sessionId); if (layout && layout === callCtrlLayouts.mergeCtrl) { callMonitor.mergeControlClickHangupTrack(); } }, onMute: (sessionId: string) => webphone.mute(sessionId), onUnmute: (sessionId: string) => webphone.unmute(sessionId), onHold: (sessionId: string) => webphone.hold(sessionId), onUnhold: (sessionId: string) => { webphone.unhold(sessionId); }, onRecord: (sessionId: string) => webphone.startRecord(sessionId), onStopRecord: (sessionId: string) => webphone.stopRecord(sessionId), sendDTMF: (...args: Parameters<Webphone['sendDTMF']>) => webphone.sendDTMF(...args), updateSessionMatchedContact: ( ...args: Parameters<Webphone['updateSessionMatchedContact']> ) => webphone.updateSessionMatchedContact(...args), getAvatarUrl, onBackButtonClick, onFlip: (sessionId: string) => { routerInteraction.push(`/flip/${sessionId}`); }, onTransfer: (sessionId: string) => { routerInteraction.push(`/transfer/${sessionId}/webphone`); }, onCompleteTransfer: (sessionId: string) => { webphone.completeWarmTransfer(sessionId); }, onPark: (sessionId: string) => webphone.park(sessionId), searchContact: (searchString: string) => contactSearch.debouncedSearch({ searchString }), phoneTypeRenderer, phoneSourceNameRenderer, onAdd: (sessionId: string) => { // track user click add on call control callMonitor.callControlClickAddTrack(); const session = find((x: any) => x.id === sessionId, webphone.sessions); if (!session || !conferenceCall.validateCallRecording(session)) { return; } let fromNumber = callingSettings.fromNumber; if (session.direction === callDirections.outbound) { fromNumber = session.fromNumber; // keep the same fromNumber } const otherCalls = filter( (call: any) => call.webphoneSession && call.webphoneSession.id !== session.id, callMonitor.allCalls, ); if (otherCalls.length) { // goto 'calls on hold' page routerInteraction.push( `/conferenceCall/callsOnhold/${fromNumber}/${session.id}`, ); } else { if (conferenceCall) { conferenceCall.setMergeParty({ fromSessionId: sessionId }); } // goto dialer directly routerInteraction.push( `/conferenceCall/dialer/${fromNumber}/${sessionId}`, ); } }, onBeforeMerge: (sessionId: string) => { const session = find((x: any) => x.id === sessionId, webphone.sessions); if (!session || !conferenceCall.validateCallRecording(session)) { return false; } if (conferenceCall) { const conferenceData = Object.values(conferenceCall.conferences)[0]; if (conferenceData) { const conferenceSession = find( (x: any) => x.id === conferenceData.sessionId, webphone.sessions, ); if ( conferenceSession && !conferenceCall.validateCallRecording(conferenceSession) ) { return false; } } } return true; }, onMerge: async (sessionId: string) => { const sessions = await conferenceCall.parseMergingSessions({ sessionId, }); if (sessions) { await conferenceCall.mergeSessions(sessions); } }, gotoParticipantsCtrl: () => { routerInteraction.push('/conferenceCall/participants'); // track user click participant area on call control callMonitor.callControlClickParticipantAreaTrack(); }, loadConference: (conferenceId: string) => { if (conferenceCall) { conferenceCall.loadConference(conferenceId); } }, closeMergingPair: () => { return conferenceCall && conferenceCall.closeMergingPair(); }, setMergeParty: (...args: Parameters<ConferenceCall['setMergeParty']>) => { return conferenceCall && conferenceCall.setMergeParty(...args); }, // user action track functions afterHideMergeConfirm: () => callMonitor.confirmMergeClickCloseTrack(), afterConfirmMerge: () => callMonitor.confirmMergeClickMergeTrack(), afterOnMerge: () => callMonitor.callControlClickMergeTrack(), }; } }