diff --git a/package.json b/package.json
index fb557562a7..1aade9cb28 100644
--- a/package.json
+++ b/package.json
@@ -84,7 +84,7 @@
"redux-thunk": "^2.1.0",
"ringcentral": "^3.1.2",
"ringcentral-client": "^1.0.0-rc1",
- "ringcentral-integration": "^0.7.1",
+ "ringcentral-integration": "^0.7.4",
"sass-loader": "^6.0.5",
"source-map-loader": "^0.2.1",
"style-loader": "^0.18.2",
diff --git a/src/components/ActiveCallDialPad/styles.scss b/src/components/ActiveCallDialPad/styles.scss
index ee0a0d9420..22d5cdc576 100644
--- a/src/components/ActiveCallDialPad/styles.scss
+++ b/src/components/ActiveCallDialPad/styles.scss
@@ -49,7 +49,9 @@ $input-height: 30px;
}
.stopButton {
- background: #ff4646;
+ circle {
+ fill: #ff4646;
+ }
g, path {
fill: #ffffff;
}
diff --git a/src/components/ActiveCallPad/index.js b/src/components/ActiveCallPad/index.js
index d09d31b806..17bb55dce3 100644
--- a/src/components/ActiveCallPad/index.js
+++ b/src/components/ActiveCallPad/index.js
@@ -95,7 +95,7 @@ export default function ActiveCallPad(props) {
null}
+ onClick={props.onToggleTransferPanel}
title={i18n.getString('transfer', props.currentLocale)}
icon={TransferIcon}
className={styles.callButton}
@@ -139,6 +139,7 @@ ActiveCallPad.propTypes = {
onShowKeyPad: PropTypes.func.isRequired,
onAdd: PropTypes.func.isRequired,
onShowFlipPanel: PropTypes.func.isRequired,
+ onToggleTransferPanel: PropTypes.func.isRequired,
flipNumbers: PropTypes.array.isRequired,
};
diff --git a/src/components/ActiveCallPanel/index.js b/src/components/ActiveCallPanel/index.js
index 0ad09695b4..bce1c0c48b 100644
--- a/src/components/ActiveCallPanel/index.js
+++ b/src/components/ActiveCallPanel/index.js
@@ -111,6 +111,7 @@ function ActiveCallPanel({
hangup,
onAdd,
onShowFlipPanel,
+ onToggleTransferPanel,
children,
showContactDisplayPlaceholder,
brand,
@@ -160,6 +161,7 @@ function ActiveCallPanel({
hangup={hangup}
onAdd={onAdd}
onShowFlipPanel={onShowFlipPanel}
+ onToggleTransferPanel={onToggleTransferPanel}
flipNumbers={flipNumbers}
/>
{children}
@@ -199,6 +201,7 @@ ActiveCallPanel.propTypes = {
showContactDisplayPlaceholder: PropTypes.bool,
onShowFlipPanel: PropTypes.func,
flipNumbers: PropTypes.array,
+ onToggleTransferPanel: PropTypes.func,
};
ActiveCallPanel.defaultProps = {
@@ -213,6 +216,7 @@ ActiveCallPanel.defaultProps = {
showContactDisplayPlaceholder: true,
flipNumbers: [],
onShowFlipPanel: () => null,
+ onToggleTransferPanel: () => null,
};
export default ActiveCallPanel;
diff --git a/src/components/CallCtrlPanel/index.js b/src/components/CallCtrlPanel/index.js
index 476a5d534e..7cdb62a27c 100644
--- a/src/components/CallCtrlPanel/index.js
+++ b/src/components/CallCtrlPanel/index.js
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import ActiveCallDialPad from '../ActiveCallDialPad';
import ActiveCallPanel from '../ActiveCallPanel';
import FlipPanel from '../FlipPanel';
+import TransferPanel from '../TransferPanel';
class CallCtrlPanel extends Component {
constructor(props) {
@@ -36,6 +37,12 @@ class CallCtrlPanel extends Component {
isShowFlipPanel: false
});
};
+
+ this.toggleTransferPanel = () => {
+ this.setState(prevState => ({
+ isShowTransferPanel: !prevState.isShowTransferPanel
+ }));
+ };
}
render() {
@@ -62,6 +69,16 @@ class CallCtrlPanel extends Component {
/>
);
}
+ if (this.state.isShowTransferPanel) {
+ return (
+
+ );
+ }
return (
{this.props.children}
@@ -113,6 +131,7 @@ CallCtrlPanel.propTypes = {
isOnMute: PropTypes.bool,
isOnHold: PropTypes.bool,
isOnFlip: PropTypes.bool,
+ isOnTransfer: PropTypes.bool,
flipNumbers: PropTypes.array,
recordStatus: PropTypes.string.isRequired,
onMute: PropTypes.func.isRequired,
@@ -124,6 +143,7 @@ CallCtrlPanel.propTypes = {
onAdd: PropTypes.func.isRequired,
hangup: PropTypes.func.isRequired,
flip: PropTypes.func.isRequired,
+ transfer: PropTypes.func.isRequired,
onBackButtonClick: PropTypes.func.isRequired,
onKeyPadChange: PropTypes.func.isRequired,
formatPhone: PropTypes.func.isRequired,
@@ -142,7 +162,7 @@ CallCtrlPanel.defaultProps = {
startTime: null,
isOnMute: false,
isOnHold: false,
- isOnRecord: false,
+ isOnTransfer: false,
isOnFlip: false,
flipNumbers: [],
phoneNumber: null,
diff --git a/src/components/TransferPanel/i18n/en-US.js b/src/components/TransferPanel/i18n/en-US.js
new file mode 100644
index 0000000000..659677362c
--- /dev/null
+++ b/src/components/TransferPanel/i18n/en-US.js
@@ -0,0 +1,5 @@
+export default {
+ to: 'To:',
+ transferTo: 'Transfer to',
+ blindTransfer: 'Transfer'
+};
diff --git a/src/components/TransferPanel/i18n/index.js b/src/components/TransferPanel/i18n/index.js
new file mode 100644
index 0000000000..25458f23b1
--- /dev/null
+++ b/src/components/TransferPanel/i18n/index.js
@@ -0,0 +1,4 @@
+import I18n from 'ringcentral-integration/lib/I18n';
+import loadLocale from './loadLocale';
+
+export default new I18n(loadLocale);
diff --git a/src/components/TransferPanel/i18n/loadLocale.js b/src/components/TransferPanel/i18n/loadLocale.js
new file mode 100644
index 0000000000..12b11cfa2e
--- /dev/null
+++ b/src/components/TransferPanel/i18n/loadLocale.js
@@ -0,0 +1 @@
+/* loadLocale */
diff --git a/src/components/TransferPanel/index.js b/src/components/TransferPanel/index.js
new file mode 100644
index 0000000000..da996b9372
--- /dev/null
+++ b/src/components/TransferPanel/index.js
@@ -0,0 +1,98 @@
+import React, { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import DialPad from '../DialPad';
+import BackHeader from '../BackHeader';
+import ActiveCallButton from '../ActiveCallButton';
+import dynamicsFont from '../../assets/DynamicsFont/DynamicsFont.scss';
+import TransferIcon from '../../assets/images/Transfer.svg';
+import styles from './styles.scss';
+import i18n from './i18n';
+
+export default class TransferPanel extends PureComponent {
+ static propTypes = {
+ transfer: PropTypes.func.isRequired,
+ currentLocale: PropTypes.string.isRequired,
+ toggleTransferPanel: PropTypes.func.isRequired,
+ isOnTransfer: PropTypes.bool.isRequired
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: '',
+ };
+ }
+
+ onButtonOutput = (key) => {
+ this.setState((preState) => {
+ const value = preState.value + key;
+ return { value };
+ });
+ }
+
+ handleChange = (event) => {
+ this.setState({ value: event.target.value });
+ }
+
+ clearText = () => {
+ this.setState({
+ value: ''
+ });
+ }
+
+ transfer = () => {
+ this.props.transfer(this.state.value);
+ }
+
+ render() {
+ const showClearButton = this.state.value === '' ? { display: 'none' } : { display: 'block' };
+ const isButtonDisabled = this.state.value === '' || this.props.isOnTransfer;
+ return (
+
+
+
+
+ )}
+ buttons={[]}
+ >
+ {i18n.getString('transferTo', this.props.currentLocale)}
+
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/src/components/TransferPanel/styles.scss b/src/components/TransferPanel/styles.scss
new file mode 100644
index 0000000000..3dc95691c2
--- /dev/null
+++ b/src/components/TransferPanel/styles.scss
@@ -0,0 +1,90 @@
+@import '../../lib/commonStyles/colors';
+@import '../../lib/commonStyles/full-size';
+@import '../../lib/commonStyles/fonts';
+
+$input-height: 30px;
+
+.root {
+ @include full-size;
+ box-sizing: border-box;
+}
+
+.dialInput {
+ height: $input-height;
+ box-sizing: content-box;
+ width: calc(100% - 30px);
+ border: 0px;
+ margin-bottom: 5px;
+ padding: 5px 0;
+ margin: 5px 20px;
+ min-width: 100px;
+ label {
+ color: $darkergray;
+ }
+ input {
+ @include secondary-font;
+ box-sizing: content-box;
+ display: inline-block;
+ text-align: left;
+ padding: 0;
+ outline: 0;
+ height: 100%;
+ width: calc(100% - 55px);
+ margin-left: 5%;
+ background-color: transparent;
+ border: none;
+ font-size:15px;
+ color: $lightblack;
+ }
+ .input::-ms-clear {
+ display: none;
+ }
+}
+
+.padContainer {
+ height: calc(100% - #{$input-height});
+ padding: 0 10px;
+}
+
+.dialPad {
+ height: 65%;
+}
+
+.button {
+ width: 30%;
+ text-align: center;
+ padding: 2px;
+}
+
+.buttonRow {
+ text-align: center;
+ height: 20%;
+}
+
+.backButton {
+ color: $lightblack;
+
+ .backIcon {
+ display: inline-block;
+ position: absolute;
+ transform: rotate(90deg);
+ top: 5px;
+ left: 10px;
+ }
+ .backLabel {
+ display: inline-block;
+ width: 79px;
+ font-size: 14px;
+ }
+}
+.clear {
+ position: absolute;
+ right: 25px;
+ margin-top: -24px;
+ cursor: pointer;
+ font-size: 18px;
+ color: $grey-light;
+ &:hover {
+ color: $rc-blue;
+ }
+}
diff --git a/src/components/WebphoneAlert/i18n/en-US.js b/src/components/WebphoneAlert/i18n/en-US.js
index d33352a6ac..0e46f34e57 100644
--- a/src/components/WebphoneAlert/i18n/en-US.js
+++ b/src/components/WebphoneAlert/i18n/en-US.js
@@ -12,5 +12,6 @@ export default {
[webphoneErrors.holdError]: 'Call cannot be hold at the moment.',
[webphoneErrors.flipError]: 'Cannot flip the call. Please try again later.',
[webphoneErrors.recordError]: 'You cannot record the call at the moment. Error code: {errorCode}',
- [webphoneErrors.recordDisabled]: 'Sorry, your account does not have the feature to record a call. Please contact your account administrator.'
+ [webphoneErrors.recordDisabled]: 'Sorry, your account does not have the feature to record a call. Please contact your account administrator.',
+ [webphoneErrors.transferError]: 'Cannot transfer the call. Please try again later.'
};
diff --git a/src/components/WebphoneAlert/index.js b/src/components/WebphoneAlert/index.js
index f26a34144c..4cdacaaac4 100644
--- a/src/components/WebphoneAlert/index.js
+++ b/src/components/WebphoneAlert/index.js
@@ -37,5 +37,6 @@ WebphoneAlert.handleMessage = ({ message }) => (
(message === webphoneErrors.holdError) ||
(message === webphoneErrors.flipError) ||
(message === webphoneErrors.recordError) ||
- (message === webphoneErrors.recordDisabled)
+ (message === webphoneErrors.recordDisabled) ||
+ (message === webphoneErrors.transferError)
);
diff --git a/src/containers/CallCtrlPage/index.js b/src/containers/CallCtrlPage/index.js
index 48a855479e..c7dc7a7359 100644
--- a/src/containers/CallCtrlPage/index.js
+++ b/src/containers/CallCtrlPage/index.js
@@ -60,6 +60,8 @@ class CallCtrlPage extends Component {
this.props.sendDTMF(value, this.props.session.id);
this.flip = value =>
this.props.flip(value, this.props.session.id);
+ this.transfer = value =>
+ this.props.transfer(value, this.props.session.id);
}
componentDidMount() {
@@ -119,6 +121,7 @@ class CallCtrlPage extends Component {
isOnMute={session.isOnMute}
isOnHold={session.isOnHold}
isOnFlip={session.isOnFlip}
+ isOnTransfer={session.isOnTransfer}
recordStatus={session.recordStatus}
onBackButtonClick={this.props.onBackButtonClick}
onMute={this.onMute}
@@ -131,6 +134,7 @@ class CallCtrlPage extends Component {
hangup={this.hangup}
onAdd={this.props.onAdd}
flip={this.flip}
+ transfer={this.transfer}
nameMatches={this.props.nameMatches}
fallBackName={fallbackUserName}
areaCode={this.props.areaCode}
@@ -155,8 +159,9 @@ CallCtrlPage.propTypes = {
startTime: PropTypes.number,
isOnMute: PropTypes.bool,
isOnHold: PropTypes.bool,
- isOnRecord: PropTypes.bool,
isOnFlip: PropTypes.bool,
+ isOnTransfer: PropTypes.bool,
+ recordStatus: PropTypes.string.isRequired,
to: PropTypes.string,
from: PropTypes.string,
contactMatch: PropTypes.object,
@@ -173,6 +178,7 @@ CallCtrlPage.propTypes = {
formatPhone: PropTypes.func.isRequired,
onAdd: PropTypes.func.isRequired,
flip: PropTypes.func.isRequired,
+ transfer: PropTypes.func.isRequired,
children: PropTypes.node,
nameMatches: PropTypes.array.isRequired,
areaCode: PropTypes.string.isRequired,
@@ -241,6 +247,7 @@ function mapToFunctions(_, {
onBackButtonClick,
onAdd,
flip: (flipNumber, sessionId) => webphone.flip(flipNumber, sessionId),
+ transfer: (transferNumber, sessionId) => webphone.transfer(transferNumber, sessionId)
};
}
diff --git a/yarn.lock b/yarn.lock
index 2d03ea5494..6da9e6042d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2763,12 +2763,6 @@ file-entry-cache@^2.0.0:
flat-cache "^1.2.1"
object-assign "^4.0.1"
-file-loader@^0.10.1:
- version "0.10.1"
- resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.10.1.tgz#815034119891fc6441fb5a64c11bc93c22ddd842"
- dependencies:
- loader-utils "^1.0.2"
-
file-loader@^0.11.2:
version "0.11.2"
resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.2.tgz#4ff1df28af38719a6098093b88c82c71d1794a34"
@@ -6206,7 +6200,7 @@ requires-port@1.0.x, requires-port@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
-reselect@^2.5.4:
+reselect@2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/reselect/-/reselect-2.5.4.tgz#b7d23fdf00b83fa7ad0279546f8dbbbd765c7047"
@@ -6269,23 +6263,23 @@ ringcentral-client@^1.0.0-rc1:
form-data "^2.1.2"
isomorphic-fetch "^2.2.1"
-ringcentral-integration@^0.7.1:
- version "0.7.1"
- resolved "https://registry.yarnpkg.com/ringcentral-integration/-/ringcentral-integration-0.7.1.tgz#eead2056a8ddc6ad23df6b18c117d16e163cb566"
+ringcentral-integration@^0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/ringcentral-integration/-/ringcentral-integration-0.7.4.tgz#d089cc99c7265bf76ca3f0543b01682aea3be52b"
dependencies:
- file-loader "^0.10.1"
+ file-loader "^0.11.2"
json-mask "^0.3.8"
loganberry "^0.9.1"
phoneformat.js "^1.0.3"
ramda "^0.24.1"
redux "^3.5.2"
- reselect "^2.5.4"
- ringcentral-web-phone "^0.4.1"
+ reselect "2.5.4"
+ ringcentral-web-phone "^0.4.2"
url-loader "^0.5.8"
uuid "^3.0.1"
yards "^0.1.4"
-ringcentral-web-phone@^0.4.1:
+ringcentral-web-phone@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/ringcentral-web-phone/-/ringcentral-web-phone-0.4.2.tgz#6a854f4691472715fbbcb4f94b8ee1dc3a835c33"
dependencies: