diff --git a/packages/ringcentral-integration/enums/callDirections.js b/packages/ringcentral-integration/enums/callDirections.js index 521acd89d1..7e3b8fa4ba 100644 --- a/packages/ringcentral-integration/enums/callDirections.js +++ b/packages/ringcentral-integration/enums/callDirections.js @@ -4,4 +4,3 @@ export default new HashMap({ inbound: 'Inbound', outbound: 'Outbound', }); - diff --git a/packages/ringcentral-widgets/components/ActiveCallsPanel/index.js b/packages/ringcentral-widgets/components/ActiveCallsPanel/index.js index fcc3f89232..705073518a 100644 --- a/packages/ringcentral-widgets/components/ActiveCallsPanel/index.js +++ b/packages/ringcentral-widgets/components/ActiveCallsPanel/index.js @@ -63,7 +63,9 @@ export default class ActiveCallsPanel extends Component { onSaveNotification, onExpandNotification, onDiscardNotification, - notificationContainerStyles + notificationContainerStyles, + onLogBasicInfoClick, + renderSmallCallContrl, } = this.props; return ( @@ -73,9 +75,9 @@ export default class ActiveCallsPanel extends Component { show={currentLog.showLog} onClose={onCloseLogSection} clickOutToClose={false} - // containerStyles={sectionContainerStyles} - // modalStyles={sectionModalStyles} - > + // containerStyles={sectionContainerStyles} + // modalStyles={sectionModalStyles} + > @@ -313,6 +317,8 @@ ActiveCallsPanel.propTypes = { ringoutReject: PropTypes.func, disableLinks: PropTypes.bool, showRingoutCallControl: PropTypes.bool, + onLogBasicInfoClick: PropTypes.func, + renderSmallCallContrl: PropTypes.func, }; ActiveCallsPanel.defaultProps = { @@ -369,4 +375,6 @@ ActiveCallsPanel.defaultProps = { ringoutReject: undefined, disableLinks: false, showRingoutCallControl: false, + onLogBasicInfoClick() { }, + renderSmallCallContrl() { }, }; diff --git a/packages/ringcentral-widgets/components/LogBasicInfo/index.js b/packages/ringcentral-widgets/components/LogBasicInfo/index.js index 25fbdf86c8..a44913987b 100644 --- a/packages/ringcentral-widgets/components/LogBasicInfo/index.js +++ b/packages/ringcentral-widgets/components/LogBasicInfo/index.js @@ -110,7 +110,7 @@ export default function LogBasicInfo(props) { { formatNumber ? ( - | +   ) : null } { this.mainCtrl = ref; }} + onScroll={() => this.checkOverlap()} + className={styles.editSection}> + {editLogSection} + + ); + } + + genSaveLogButton() { + const { + showSaveLogBtn, renderSaveLogButton, + currentLocale, onSaveCallLog, + currentLog } = this.props; const { call, - showSpinner, currentLogCall, } = currentLog; - if (showSpinner) { - return (); - } - const editLogSection = renderEditLogSection({ - currentLocale, - onSaveCallLog, - onUpdateCallLog, - currentLog, - additionalInfo, - }); const buttonPanelClassName = classnames( styles.buttonPanel, this.state.mainCtrlOverlapped && styles.overlapped @@ -74,38 +81,83 @@ export default class LogSection extends Component { styles.primaryButton, currentLogCall.isSaving && styles.disabled ); - const saveLogBtn = showSaveLogBtn ? renderSaveLogButton && ( - renderSaveLogButton({ + if (!showSaveLogBtn) { + return null; + } + if (renderSaveLogButton) { + return renderSaveLogButton({ currentLocale, onSaveCallLog, currentLog, overlapped: this.state.mainCtrlOverlapped - }) - ) || ( + }); + } + return (
- ) : null; + ); + } + + genLogBasicInfo() { return ( -
- -
{ this.mainCtrl = ref; }} - onScroll={() => this.checkOverlap()} - className={styles.editSection}> - {editLogSection} + + ); + } + + genLogBasicInfoWithSmallCallCtrl() { + const currentlog = this.props.currentLog; + const { currentSessionId, call } = currentlog; + const { telephonyStatus, result } = call; + const status = telephonyStatus || result; + // if `result` is exist, call has been disconnect + if (result) { + return this.genLogBasicInfo(); + } + return ( +
+
this.props.onLogBasicInfoClick()}> +
- {saveLogBtn} +
+ {this.props.renderSmallCallContrl(status, currentSessionId)} +
+
+ ); + } + + render() { + const { + currentLog, + isInnerMask, + showSmallCallControl + } = this.props; + const { + showSpinner, + } = currentLog; + if (showSpinner) { + return (); + } + + return ( +
+ {showSmallCallControl ? this.genLogBasicInfoWithSmallCallCtrl() : this.genLogBasicInfo()} + {this.genEditLogSection()} + {this.genSaveLogButton()} { isInnerMask ? (
@@ -125,7 +177,10 @@ LogSection.propTypes = { renderEditLogSection: PropTypes.func, renderSaveLogButton: PropTypes.func, isInnerMask: PropTypes.bool, + onLogBasicInfoClick: PropTypes.func, showSaveLogBtn: PropTypes.bool, + showSmallCallControl: PropTypes.bool, + renderSmallCallContrl: PropTypes.func, }; LogSection.defaultProps = { @@ -137,5 +192,8 @@ LogSection.defaultProps = { renderEditLogSection: undefined, renderSaveLogButton: undefined, isInnerMask: undefined, + onLogBasicInfoClick() { }, + renderSmallCallContrl() { }, showSaveLogBtn: true, + showSmallCallControl: true, }; diff --git a/packages/ringcentral-widgets/components/LogSection/styles.scss b/packages/ringcentral-widgets/components/LogSection/styles.scss index 5e1ea7e89e..5dd91d03cc 100644 --- a/packages/ringcentral-widgets/components/LogSection/styles.scss +++ b/packages/ringcentral-widgets/components/LogSection/styles.scss @@ -66,3 +66,17 @@ $section_height: 36px; height: 100%; z-index: 3; } + +.infoWithCtrlWrapper { + display: flex; + padding: 10px 0; + align-items: center; +} + +.basicInfoWrapper { + cursor: pointer; + flex: 1; +} +.callCtrlWrapper { + padding: 0 10px; +} diff --git a/packages/ringcentral-widgets/components/SmCallControl/i18n/en-US.js b/packages/ringcentral-widgets/components/SmCallControl/i18n/en-US.js new file mode 100644 index 0000000000..86cb15a3ab --- /dev/null +++ b/packages/ringcentral-widgets/components/SmCallControl/i18n/en-US.js @@ -0,0 +1,6 @@ +export default { + mute: 'Mute', + unmute: 'Unmute', + hangup: 'Hangup', + reject: 'Reject', +}; diff --git a/packages/ringcentral-widgets/components/SmCallControl/i18n/index.js b/packages/ringcentral-widgets/components/SmCallControl/i18n/index.js new file mode 100644 index 0000000000..b67573a87a --- /dev/null +++ b/packages/ringcentral-widgets/components/SmCallControl/i18n/index.js @@ -0,0 +1,4 @@ +import I18n from '@ringcentral-integration/i18n'; +import loadLocale from './loadLocale'; + +export default new I18n(loadLocale); diff --git a/packages/ringcentral-widgets/components/SmCallControl/i18n/loadLocale.js b/packages/ringcentral-widgets/components/SmCallControl/i18n/loadLocale.js new file mode 100644 index 0000000000..12b11cfa2e --- /dev/null +++ b/packages/ringcentral-widgets/components/SmCallControl/i18n/loadLocale.js @@ -0,0 +1 @@ +/* loadLocale */ diff --git a/packages/ringcentral-widgets/components/SmCallControl/index.js b/packages/ringcentral-widgets/components/SmCallControl/index.js new file mode 100644 index 0000000000..a8520b2c90 --- /dev/null +++ b/packages/ringcentral-widgets/components/SmCallControl/index.js @@ -0,0 +1,77 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; + +import telephonyStatuses from 'ringcentral-integration/enums/telephonyStatus'; +import callDirections from 'ringcentral-integration/enums/callDirections'; + + +import CircleButton from '../CircleButton'; + +import MuteIcon from '../../assets/images/Mute.svg'; +import UnmuteIcon from '../../assets/images/Unmute.svg'; +import EndIcon from '../../assets/images/End.svg'; +import styles from './styles.scss'; + +import i18n from './i18n'; + + +export default function SmCallControl(props) { + const { + onMute, onUnmute, onHangup, onReject, + isOnMute, callStatus, currentLocale, callDirection, + } = props; + + // reject conditons: call direction is inbound & call status is ringing + function canRejectCall() { + return ( + callDirections.inbound === callDirection && + telephonyStatuses.ringing === callStatus + ); + } + + const muteIcon = isOnMute ? MuteIcon : UnmuteIcon; + const muteAction = isOnMute ? onUnmute : onMute; + const muteTitle = isOnMute ? 'mute' : 'unmute'; + const endTile = canRejectCall() ? 'reject' : 'hangup'; + const endAction = canRejectCall() ? onReject : onHangup; + const disabledCtrl = callStatus === telephonyStatuses.ringing; + return ( +
+ + +
+ ); +} + +SmCallControl.propTypes = { + onMute: PropTypes.func, + onUnmute: PropTypes.func, + onHangup: PropTypes.func, + onReject: PropTypes.func, + isOnMute: PropTypes.bool, + callStatus: PropTypes.string, + currentLocale: PropTypes.string, + callDirection: PropTypes.string.isRequired, +}; +SmCallControl.defaultProps = { + onMute() { }, + onUnmute() { }, + onHangup() { }, + onReject() { }, + isOnMute: false, + callStatus: 'CallConnected', + currentLocale: 'en-US' +}; diff --git a/packages/ringcentral-widgets/components/SmCallControl/styles.scss b/packages/ringcentral-widgets/components/SmCallControl/styles.scss new file mode 100644 index 0000000000..38af2afaf3 --- /dev/null +++ b/packages/ringcentral-widgets/components/SmCallControl/styles.scss @@ -0,0 +1,39 @@ +@import '../../lib/commonStyles/colors.scss'; +@import '../../lib/commonStyles/fonts.scss'; + +.smWraper { + width: 50px; +} +.button { + width: 50%; + box-sizing: border-box; + padding: 2px; +} + +.hangup { + circle { + fill: #ff4646; + } + g, + path { + fill: #ffffff; + } +} +.buttonDisabled { + circle { + fill: $lightgray; + stroke: $gray; + } + path { + fill: $primary-color-highlight-solid; + } + g { + cursor: default; + + &:hover { + circle { + stroke: $gray; + } + } + } +} diff --git a/packages/ringcentral-widgets/containers/SmCallCtrlContainer/index.js b/packages/ringcentral-widgets/containers/SmCallCtrlContainer/index.js new file mode 100644 index 0000000000..caed8163f8 --- /dev/null +++ b/packages/ringcentral-widgets/containers/SmCallCtrlContainer/index.js @@ -0,0 +1,79 @@ +/** + * @file small call contrl + * detail: https://jira.ringcentral.com/browse/RCINT-8248 + */ + +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + + +import SmCallContrl from '../../components/SmCallControl'; +import withPhone from '../../lib/withPhone'; + +function mapToProps(_, { phone }) { + const { + activeCallControl, + } = phone; + const { activeSessions } = activeCallControl; + return { + activeCallControl, + activeSessions + }; +} + +function mapToFunctions(_, { phone }) { + const { activeCallControl } = phone; + return { + mute: activeCallControl.mute.bind(activeCallControl), + unmute: activeCallControl.unmute.bind(activeCallControl), + hangUp: activeCallControl.hangUp.bind(activeCallControl), + reject: activeCallControl.reject.bind(activeCallControl), + }; +} + +/* eslint-disable react/prefer-stateless-function */ +class SmCallCtrlContainer extends Component { + render() { + const { + currentLocale, + activeSessions, + sessionId, + } = this.props; + const currentSession = activeSessions[sessionId]; + if (!currentSession) { + return null; + } + const props = { + onMute: async () => this.props.mute(sessionId), + onUnmute: async () => this.props.unmute(sessionId), + onHangup: async () => this.props.hangUp(sessionId), + onReject: async () => this.props.reject(sessionId), + isOnMute: currentSession.isOnMute, + callStatus: currentSession.callStatus, + callDirection: currentSession.direction, + currentLocale + }; + return ; + } +} +SmCallCtrlContainer.propTypes = { + currentLocale: PropTypes.string, + activeCallControl: PropTypes.object, + activeSessions: PropTypes.object, + sessionId: PropTypes.string, + status: PropTypes.string, + mute: PropTypes.func.isRequired, + unmute: PropTypes.func.isRequired, + hangUp: PropTypes.func.isRequired, + reject: PropTypes.func.isRequired, +}; + +SmCallCtrlContainer.defaultProps = { + currentLocale: 'en-US', + activeCallControl: {}, + activeSessions: {}, + sessionId: '', + status: '', +}; +export default withPhone(connect(mapToProps, mapToFunctions)(SmCallCtrlContainer));