import { telephonySessionStatus } from '@ringcentral-integration/commons/enums/telephonySessionStatus'; import { getWebphoneSessionDisplayName, isInbound, isRinging, } from '@ringcentral-integration/commons/lib/callLogHelpers'; import { isHolding as isTelephonySessionOnHold } from '@ringcentral-integration/commons/modules/ActiveCallControl'; import sessionStatus from '@ringcentral-integration/commons/modules/Webphone/sessionStatus'; import { isOnHold } from '@ringcentral-integration/commons/modules/Webphone/webphoneHelper'; import { format } from '@ringcentral-integration/utils'; import clsx from 'clsx'; import type { FunctionComponent } from 'react'; import React, { Component } from 'react'; import AnswerIcon from '../../assets/images/Answer.svg'; import EndIcon from '../../assets/images/End.svg'; import HoldIcon from '../../assets/images/Hold.svg'; import HoldAnswerIcon from '../../assets/images/HoldAnswer.svg'; import IgnoreIcon from '../../assets/images/Ignore.svg'; import MergeIntoConferenceIcon from '../../assets/images/MergeIntoConferenceIcon.svg'; import SwitchIcon from '../../assets/images/Switch.svg'; import TransferIcon from '../../assets/images/Transfer.svg'; import VoicemailIcon from '../../assets/images/Voicemail.svg'; import SwitchImage from '../../assets/images/img_call_switch.svg'; import i18n, { t } from '../ActiveCallItem/i18n'; import CallIcon from '../CallIcon'; import CircleButton from '../CircleButton'; import ContactDisplay from '../ContactDisplay'; import { DurationCounter } from '../DurationCounter'; import MediaObject from '../MediaObject'; import type { ActiveCallControlButtonsProps, ActiveCallItemProps, ActiveCallItemState, ModalContentProps, WebphoneButtonsProps, } from './ActiveCallItem.interface'; import styles from './styles.scss'; export const ModalContent: FunctionComponent = ({ contactName, confirmContext, }) => { return (
{confirmContext ?? t('comfirmContext', { displayName: contactName, })}
); }; const WebphoneButtons: FunctionComponent = ({ currentLocale, session = undefined, webphoneReject, webphoneHangup, webphoneResume, webphoneAnswer, webphoneHold, showMergeCall = false, showHold = true, disableMerge = true, onMergeCall = (i) => i, disableLinks = false, isOnHold, telephonySessionId, webphoneIgnore, showHoldAnswerBtn, showIgnoreBtn, isConnecting = false, isCallQueueCall, }) => { if (!session) { return null; } let answerBtn; let ignoreBtn; let endBtn; // @ts-expect-error TS(2345): Argument of type 'WebPhoneSession' is not assignab... Remove this comment to see the full error message if (isInbound(session) && session.callStatus === sessionStatus.connecting) { showHold = false; answerBtn = ( {!showHoldAnswerBtn ? ( { e.stopPropagation(); webphoneAnswer(session.id, telephonySessionId); }} icon={AnswerIcon} showBorder={false} disabled={disableLinks} /> ) : ( { e.stopPropagation(); webphoneAnswer(session.id, telephonySessionId, true); }} > )} ); endBtn = !isCallQueueCall && ( { e.stopPropagation(); webphoneReject(session.id, telephonySessionId); }} iconWidth={260} iconX={120} icon={VoicemailIcon} showBorder={false} disabled={disableLinks} /> ); if (showIgnoreBtn) { const ignoreTitle = i18n.getString('ignore', currentLocale); ignoreBtn = ( { e.stopPropagation(); // @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message webphoneIgnore(telephonySessionId); }} iconWidth={260} iconX={120} icon={IgnoreIcon} showBorder disabled={disableLinks} /> ); } } else { endBtn = ( { e.stopPropagation(); webphoneHangup(session.id, telephonySessionId); }} iconWidth={260} iconX={120} icon={EndIcon} showBorder={false} disabled={disableLinks} /> ); } let holdBtn; let mergeBtn; if (showHold) { if (isOnHold(session)) { holdBtn = ( { e.stopPropagation(); webphoneResume(session.id, telephonySessionId); }} iconWidth={260} iconX={120} icon={HoldIcon} disabled={disableLinks || isConnecting} showBorder /> ); } else { holdBtn = ( { e.stopPropagation(); webphoneHold(session.id, telephonySessionId); }} iconWidth={260} iconX={120} icon={HoldIcon} disabled={disableLinks || isConnecting} showBorder /> ); } } if (showMergeCall) { mergeBtn = ( { e.stopPropagation(); onMergeCall(session.id, telephonySessionId); }} iconWidth={260} iconX={120} icon={MergeIntoConferenceIcon} showBorder disabled={disableMerge || disableLinks} /> ); } return ( <> {ignoreBtn} {holdBtn} {mergeBtn} {endBtn} {answerBtn} ); }; const ActiveCallControlButtons: FunctionComponent< ActiveCallControlButtonsProps > = ({ session = undefined, showRingoutCallControl, showSwitchCall, showTransferCall, showHoldOnOtherDevice, currentLocale, disableLinks = false, telephonySessionId, ringoutHangup, ringoutReject, ringoutTransfer = undefined, ringing, inbound, onClickSwitchBtn = undefined, webphoneResume = undefined, webphoneHold = undefined, isConnecting = false, clickSwitchTrack = () => {}, }) => { if (!showRingoutCallControl && !showSwitchCall) return null; let switchCallButton; if (showSwitchCall) { const disabled = disableLinks || ringing; switchCallButton = ( ) => { e.stopPropagation(); if (!disabled) { clickSwitchTrack(); // @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message onClickSwitchBtn(); } }} /> ); } if (!showRingoutCallControl) { return
{switchCallButton}
; } let endBtn; let holdBtn; const inComingCall = inbound && ringing; if (inComingCall) { const rejectTitle = i18n.getString('reject', currentLocale); endBtn = ( { e.stopPropagation(); ringoutReject(telephonySessionId); }} icon={EndIcon} showBorder={false} /> ); } else { endBtn = ( { e.stopPropagation(); ringoutHangup(telephonySessionId); }} icon={EndIcon} showBorder={false} /> ); const disabled = disableLinks || isConnecting || ringing; if (session) { // @ts-expect-error TS(2345): Argument of type 'object' is not assignable to par... Remove this comment to see the full error message if (isTelephonySessionOnHold(session)) { holdBtn = ( { e.stopPropagation(); // @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message webphoneResume('', telephonySessionId); }} iconWidth={260} iconX={120} icon={HoldIcon} disabled={disabled} showBorder /> ); } else { holdBtn = ( { e.stopPropagation(); // @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message webphoneHold('', telephonySessionId); }} iconWidth={260} iconX={120} icon={HoldIcon} disabled={disabled} showBorder /> ); } } } let transferBtn; if (ringoutTransfer && !inComingCall) { const transferTitle = i18n.getString('transfer', currentLocale); transferBtn = ( { e.stopPropagation(); ringoutTransfer(telephonySessionId); }} icon={TransferIcon} /> ); } return (
{showHoldOnOtherDevice && holdBtn} {showTransferCall && transferBtn} {switchCallButton} {endBtn}
); }; /** * TODO: Gradually replace with this component */ export class ActiveCallItem extends Component< ActiveCallItemProps, ActiveCallItemState > { static defaultProps = { isLogging: false, disableLinks: false, enableContactFallback: false, brand: 'RingCentral', showContactDisplayPlaceholder: true, sourceIcons: {}, phoneTypeRenderer: undefined, phoneSourceNameRenderer: undefined, renderContactName: undefined, renderSubContactName: undefined, renderExtraButton: undefined, contactDisplayStyle: '', isOnConferenceCall: false, onClick: undefined, showAvatar: true, getAvatarUrl: undefined, showMergeCall: false, showHold: true, disableMerge: false, onMergeCall: (i: any) => i, showCallDetail: false, updateSessionMatchedContact: (i: any) => i, showRingoutCallControl: false, showMultipleMatch: false, showSwitchCall: false, showTransferCall: true, showHoldOnOtherDevice: false, isOnHold, }; _userSelection: boolean; // @ts-expect-error TS(2564): Property 'toVoicemailTimeout' has no initializer a... Remove this comment to see the full error message toVoicemailTimeout: number; // @ts-expect-error TS(2564): Property '_mounted' has no initializer and is not ... Remove this comment to see the full error message _mounted: boolean; webphoneToVoicemail: (sessionId: string, telephonySessionId: string) => any; // @ts-expect-error TS(2564): Property 'modalId' has no initializer and is not d... Remove this comment to see the full error message modalId: string; constructor(props: ActiveCallItemProps) { super(props); this.state = { selected: 0, isLogging: false, // @ts-expect-error TS(2322): Type 'null' is not assignable to type 'string'. avatarUrl: null, extraNum: 0, }; this._userSelection = false; // this.contactDisplay = null; this.webphoneToVoicemail = (sessionId, telephonySessionId) => { if (typeof this.props.webphoneToVoicemail !== 'function') { return; } this.props.webphoneToVoicemail(sessionId, telephonySessionId); this.toVoicemailTimeout = window.setTimeout(() => { this.props.webphoneReject(sessionId, telephonySessionId); }, 3000); }; } setContact(nextProps = this.props) { const { isOnConferenceCall, conferenceCallParties } = nextProps; if (isOnConferenceCall) { this.setState({ avatarUrl: conferenceCallParties.map((profile) => profile.avatarUrl)[0], extraNum: conferenceCallParties.length > 0 ? conferenceCallParties.length - 1 : 0, }); return; } const selected = this.getSelectedContactIdx(nextProps); this.onSelectContact( this.getSelectedContact(selected, nextProps), // @ts-expect-error TS(2345): Argument of type 'number | null' is not assignable... Remove this comment to see the full error message selected, ); } // @ts-expect-error TS(4114): This member must have an 'override' modifier becau... Remove this comment to see the full error message componentDidMount() { this._mounted = true; this.setContact(); } // @ts-expect-error TS(4114): This member must have an 'override' modifier becau... Remove this comment to see the full error message UNSAFE_componentWillReceiveProps(nextProps: ActiveCallItemProps) { if (this.getContactMatches(nextProps) !== this.getContactMatches()) { this.setContact(nextProps); } } // @ts-expect-error TS(4114): This member must have an 'override' modifier becau... Remove this comment to see the full error message componentWillUnmount() { this._mounted = false; if (this.toVoicemailTimeout) { window.clearTimeout(this.toVoicemailTimeout); // @ts-expect-error TS(2322): Type 'null' is not assignable to type 'number'. this.toVoicemailTimeout = null; } if (this.modalId) { this.props.modalClose(this.modalId); } } getCallInfo() { const { call: { telephonyStatus, startTime, offset }, disableLinks, currentLocale, showCallDetail, useCallDetailV2, } = this.props; if (!showCallDetail) { return null; } // @ts-expect-error TS(2345): Argument of type 'string | undefined' is not assig... Remove this comment to see the full error message const telephonyStatusInfo = i18n.getString(telephonyStatus, currentLocale); const callStatusComp = ( <> | {telephonyStatusInfo} ); if (useCallDetailV2) { return (
); } return (
{disableLinks ? ( i18n.getString('unavailable', currentLocale) ) : ( )} {callStatusComp}
); } getFallbackContactName() { return isInbound(this.props.call) ? this.props.call.from.name : // @ts-expect-error TS(2532): Object is possibly 'undefined'. this.props.call.to.name; } onSelectContact = (value: any, idx: number) => { if (!value || typeof this.props.getAvatarUrl !== 'function') { return; } this._userSelection = true; this.setState({ selected: idx, }); if (value) { this.props.getAvatarUrl(value).then((avatarUrl: string) => { if (this._mounted) { this.setState({ avatarUrl }); } }); if (this.props.call.webphoneSession) { // @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message this.props.updateSessionMatchedContact( this.props.call.webphoneSession.id, value, ); } } }; getSelectedContactIdx = (nextProps = this.props) => { const contactMatches = this.getContactMatches(nextProps); let selected = null; if (!nextProps.call.webphoneSession) { selected = 0; } else if (contactMatches && contactMatches.length) { // @ts-expect-error TS(2339): Property 'contactMatch' does not exist on type 'We... Remove this comment to see the full error message const contact = nextProps.call.webphoneSession.contactMatch; if (contact) { selected = contactMatches.findIndex((match) => match.id === contact.id); } if (selected === -1 || !contact) { selected = 0; } } return selected; }; getSelectedContact = ( selected = this.getSelectedContactIdx(), nextProps = this.props, ) => { const contactMatches = this.getContactMatches(nextProps); // @ts-expect-error TS(2538): Type 'null' cannot be used as an index type. return (contactMatches && contactMatches[selected]) || null; }; getContactMatches(nextProps = this.props) { return isInbound(nextProps.call) ? nextProps.call.fromMatches : nextProps.call.toMatches; } getPhoneNumber() { return isInbound(this.props.call) ? this.props.call.from.phoneNumber || this.props.call.from.extensionNumber : // @ts-expect-error TS(2532): Object is possibly 'undefined'. this.props.call.to.phoneNumber || this.props.call.to.extensionNumber; } onClickSwitchBtn = () => { const { renderContactName, call, modalConfirm, isWide, currentLocale, webphoneSwitchCall, onSwitchCall, } = this.props; // !refactor // TODO: Consider refactoring modalConfirm out of UI components!!!!!!!!!!!!!! // use modalConfirm for ActiveCallsUI module if (onSwitchCall) { onSwitchCall(call); return; } if (modalConfirm) { const contactName = typeof renderContactName === 'function' ? renderContactName(call) : undefined; this.modalId = modalConfirm({ childrenSize: isWide ? 'medium' : 'small', title: i18n.getString('callSwitch', currentLocale), className: styles.switchDialog, contentProps: { contactName: // @ts-expect-error TS(2339): Property 'title' does not exist on type 'string'. contactName?.title || contactName || this.getPhoneNumber(), }, confirmButtonText: i18n.getString('comfirmOKButton', currentLocale), cancelButtonText: i18n.getString('comfirmCancelButton', currentLocale), onConfirm: () => { webphoneSwitchCall(call); // @ts-expect-error TS(2322): Type 'null' is not assignable to type 'string'. this.modalId = null; }, onCancel: () => { // @ts-expect-error TS(2322): Type 'null' is not assignable to type 'string'. this.modalId = null; }, }); } }; // @ts-expect-error TS(4114): This member must have an 'override' modifier becau... Remove this comment to see the full error message render() { const { warmTransferRole, call: { direction, webphoneSession, telephonySessionId, telephonySession, }, disableLinks, currentLocale, areaCode, countryCode, enableContactFallback, isLogging, brand, showContactDisplayPlaceholder, webphoneHangup, webphoneResume, sourceIcons, phoneTypeRenderer, phoneSourceNameRenderer, renderContactName, renderSubContactName, renderExtraButton, contactDisplayStyle, isOnConferenceCall, webphoneHold, onClick, showMergeCall, showHold, showAvatar, disableMerge, onMergeCall, showCallDetail, webphoneAnswer, ringoutHangup, ringoutTransfer, ringoutReject, showRingoutCallControl, showSwitchCall, showTransferCall, showHoldOnOtherDevice, showMultipleMatch, isOnHold, newCallIcon, webphoneIgnore, showHoldAnswerBtn, showIgnoreBtn, showCallerIdName, clickSwitchTrack, formatPhone, } = this.props; const { avatarUrl, extraNum } = this.state; const phoneNumber = this.getPhoneNumber(); const contactMatches = this.getContactMatches(); const fallbackContactName = this.getFallbackContactName(); // @ts-expect-error TS(2345): Argument of type 'Call' is not assignable to param... Remove this comment to see the full error message const ringing = isRinging(this.props.call); const inbound = isInbound(this.props.call); const contactName = typeof renderContactName === 'function' ? renderContactName(this.props.call) : undefined; const subContactName = typeof renderSubContactName === 'function' ? renderSubContactName(this.props.call) : undefined; const extraButton = typeof renderExtraButton === 'function' ? (
{renderExtraButton(this.props.call)}
) : undefined; const hasCallControl = !!( webphoneSession || showRingoutCallControl || showSwitchCall ); const cursorPointer = hasCallControl && !!onClick; // real outbound call status const isConnecting = telephonySession?.otherParties[0]?.status?.code === telephonySessionStatus.proceeding; const callerIdName = showCallerIdName ? getWebphoneSessionDisplayName(this.props.call.webphoneSession as any) : undefined; // @ts-expect-error const callQueueName = webphoneSession?.callQueueName; const isCallQueueCall = !!callQueueName; return (
any) | null' is not ass... Remove this comment to see the full error message
} mediaBody={
{showCallDetail ? this.getCallInfo() : null}
} mediaRight={
{webphoneSession ? ( boolean) | undefined' ... Remove this comment to see the full error message isOnHold={isOnHold} webphoneIgnore={webphoneIgnore} showIgnoreBtn={showIgnoreBtn} showHoldAnswerBtn={showHoldAnswerBtn} disableLinks={disableLinks} isCallQueueCall={isCallQueueCall} /> ) : ( )} {extraButton}
} />
); } }