Adds dial-out UI.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { Symbol } from '../base/react';
|
||||
|
||||
/**
|
||||
* The type of the action which signals a check for a dial-out phone number has
|
||||
* succeeded.
|
||||
*
|
||||
* {
|
||||
* type: PHONE_NUMBER_CHECKED,
|
||||
* response: Object
|
||||
* }
|
||||
*/
|
||||
export const PHONE_NUMBER_CHECKED
|
||||
= Symbol('PHONE_NUMBER_CHECKED');
|
||||
|
||||
/**
|
||||
* The type of the action which signals a cancel of the dial-out operation.
|
||||
*
|
||||
* {
|
||||
* type: DIAL_OUT_CANCELED,
|
||||
* response: Object
|
||||
* }
|
||||
*/
|
||||
export const DIAL_OUT_CANCELED
|
||||
= Symbol('DIAL_OUT_CANCELED');
|
||||
|
||||
/**
|
||||
* The type of the action which signals a request for dial-out country codes has
|
||||
* succeeded.
|
||||
*
|
||||
* {
|
||||
* type: DIAL_OUT_CODES_UPDATED,
|
||||
* response: Object
|
||||
* }
|
||||
*/
|
||||
export const DIAL_OUT_CODES_UPDATED
|
||||
= Symbol('DIAL_OUT_CODES_UPDATED');
|
||||
|
||||
/**
|
||||
* The type of the action which signals a failure in some of dial-out service
|
||||
* requests.
|
||||
*
|
||||
* {
|
||||
* type: DIAL_OUT_SERVICE_FAILED,
|
||||
* response: Object
|
||||
* }
|
||||
*/
|
||||
export const DIAL_OUT_SERVICE_FAILED
|
||||
= Symbol('DIAL_OUT_SERVICE_FAILED');
|
||||
@@ -0,0 +1,97 @@
|
||||
import { openDialog } from '../../features/base/dialog';
|
||||
|
||||
import {
|
||||
DIAL_OUT_CANCELED,
|
||||
DIAL_OUT_CODES_UPDATED,
|
||||
DIAL_OUT_SERVICE_FAILED,
|
||||
PHONE_NUMBER_CHECKED
|
||||
} from './actionTypes';
|
||||
|
||||
import { DialOutDialog } from './components';
|
||||
|
||||
declare var $: Function;
|
||||
declare var config: Object;
|
||||
|
||||
/**
|
||||
* Dials the given number.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function cancel() {
|
||||
return {
|
||||
type: DIAL_OUT_CANCELED
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dials the given number.
|
||||
*
|
||||
* @param {string} dialNumber - The number to dial.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function dial(dialNumber) {
|
||||
return (dispatch, getState) => {
|
||||
const { conference } = getState()['features/base/conference'];
|
||||
|
||||
conference.dial(dialNumber);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ajax request for dial-out country codes.
|
||||
*
|
||||
* @param {string} dialNumber - The dial number to check for validity.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function checkDialNumber(dialNumber) {
|
||||
return (dispatch, getState) => {
|
||||
const { dialOutAuthUrl } = getState()['features/base/config'];
|
||||
|
||||
const fullUrl = `${dialOutAuthUrl}?phone=${dialNumber}`;
|
||||
|
||||
$.getJSON(fullUrl)
|
||||
.success(response =>
|
||||
dispatch({
|
||||
type: PHONE_NUMBER_CHECKED,
|
||||
response
|
||||
}))
|
||||
.error(error =>
|
||||
dispatch({
|
||||
type: DIAL_OUT_SERVICE_FAILED,
|
||||
error
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens the dial-out dialog.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function openDialOutDialog() {
|
||||
return openDialog(DialOutDialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an ajax request for dial-out country codes.
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function updateDialOutCodes() {
|
||||
return (dispatch, getState) => {
|
||||
const { dialOutCodesUrl } = getState()['features/base/config'];
|
||||
|
||||
$.getJSON(dialOutCodesUrl)
|
||||
.success(response =>
|
||||
dispatch({
|
||||
type: DIAL_OUT_CODES_UPDATED,
|
||||
response
|
||||
}))
|
||||
.error(error =>
|
||||
dispatch({
|
||||
type: DIAL_OUT_SERVICE_FAILED,
|
||||
error
|
||||
}));
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
/**
|
||||
* Implements a React Component to render a country flag icon.
|
||||
*/
|
||||
class CountryIcon extends Component {
|
||||
/**
|
||||
* {@code CountryIcon}'s property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The css style class name.
|
||||
*/
|
||||
className: React.PropTypes.string,
|
||||
|
||||
/**
|
||||
* The 2-letter country code.
|
||||
*/
|
||||
countryCode: React.PropTypes.string
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const iconClassName
|
||||
= `flag-icon flag-icon-${this.props.countryCode}
|
||||
flag-icon-squared ${this.props.className}`;
|
||||
|
||||
return <span className = { iconClassName } />;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default CountryIcon;
|
||||
@@ -0,0 +1,226 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../base/i18n';
|
||||
import { Dialog } from '../../base/dialog';
|
||||
|
||||
import { cancel, checkDialNumber, dial } from '../actions';
|
||||
import DialOutNumbersForm from './DialOutNumbersForm';
|
||||
|
||||
/**
|
||||
* Implements a React Component which allows the user to dial out from the
|
||||
* conference.
|
||||
*/
|
||||
class DialOutDialog extends Component {
|
||||
|
||||
/**
|
||||
* {@code DialOutDialog} component's property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* Property indicating if a dial number is allowed.
|
||||
*/
|
||||
_isDialNumberAllowed: React.PropTypes.bool,
|
||||
|
||||
/**
|
||||
* The function performing the cancel action.
|
||||
*/
|
||||
cancel: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* The function performing the phone number validity check.
|
||||
*/
|
||||
checkDialNumber: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* The function performing the dial action.
|
||||
*/
|
||||
dial: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: React.PropTypes.func
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code DialOutNumbersForm} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
/**
|
||||
* The number to dial.
|
||||
*/
|
||||
dialNumber: '',
|
||||
|
||||
/**
|
||||
* Indicates if the dial input is currently empty.
|
||||
*/
|
||||
isDialInputEmpty: true
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onDialNumberChange = this._onDialNumberChange.bind(this);
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _isDialNumberAllowed } = this.props;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
okDisabled = { this.state.isDialInputEmpty
|
||||
|| !_isDialNumberAllowed }
|
||||
okTitleKey = 'dialOut.dial'
|
||||
onCancel = { this._onCancel }
|
||||
onSubmit = { this._onSubmit }
|
||||
titleKey = 'dialOut.dialOut'
|
||||
width = 'small'>
|
||||
{ this._renderContent() }
|
||||
</Dialog>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the dial number in a way to remove all non digital characters
|
||||
* from it (including spaces, brackets, dash, dot, etc.).
|
||||
*
|
||||
* @param {string} dialNumber - The phone number to format.
|
||||
* @private
|
||||
* @returns {string} - The formatted phone number.
|
||||
*/
|
||||
_formatDialNumber(dialNumber) {
|
||||
return dialNumber.replace(/\D/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the dialog content.
|
||||
*
|
||||
* @returns {XML}
|
||||
* @private
|
||||
*/
|
||||
_renderContent() {
|
||||
const { _isDialNumberAllowed } = this.props;
|
||||
|
||||
return (
|
||||
<div className = 'dial-out-content'>
|
||||
{ _isDialNumberAllowed ? '' : this._renderErrorMessage() }
|
||||
<DialOutNumbersForm
|
||||
onChange = { this._onDialNumberChange } />
|
||||
</div>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the error message to display if the dial phone number is not
|
||||
* allowed.
|
||||
*
|
||||
* @returns {XML}
|
||||
* @private
|
||||
*/
|
||||
_renderErrorMessage() {
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<div className = 'dial-out-error'>
|
||||
{ t('dialOut.phoneNotAllowed') }
|
||||
</div>);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the dial out.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean} - Returns true to indicate that the dialog should be
|
||||
* closed.
|
||||
*/
|
||||
_onCancel() {
|
||||
this.props.cancel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dials the number.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean} - Returns true to indicate that the dialog should be
|
||||
* closed.
|
||||
*/
|
||||
_onSubmit() {
|
||||
if (this.props._isDialNumberAllowed) {
|
||||
this.props.dial(this.state.dialNumber);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the dialNumber and check for validity.
|
||||
*
|
||||
* @param {string} dialCode - The dial code value.
|
||||
* @param {string} dialInput - The dial input value.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDialNumberChange(dialCode, dialInput) {
|
||||
// We remove all starting zeros from the dial input before attaching it
|
||||
// to the country code.
|
||||
const formattedDialInput = dialInput.replace(/^(0+)/, '');
|
||||
|
||||
const dialNumber = `${dialCode}${formattedDialInput}`;
|
||||
|
||||
const formattedNumber = this._formatDialNumber(dialNumber);
|
||||
|
||||
this.props.checkDialNumber(formattedNumber);
|
||||
|
||||
this.setState({
|
||||
dialNumber: formattedNumber,
|
||||
isDialInputEmpty: !formattedDialInput
|
||||
|| formattedDialInput.length === 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated
|
||||
* {@code DialOutDialog}'s props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _isDialNumberAllowed: React.PropTypes.bool
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const { isDialNumberAllowed } = state['features/dial-out'];
|
||||
|
||||
return {
|
||||
/**
|
||||
* Property indicating if a dial number is allowed.
|
||||
*
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
_isDialNumberAllowed: isDialNumberAllowed
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(
|
||||
connect(_mapStateToProps, {
|
||||
cancel,
|
||||
dial,
|
||||
checkDialNumber
|
||||
})(DialOutDialog));
|
||||
@@ -0,0 +1,346 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ExpandIcon from '@atlaskit/icon/glyph/expand';
|
||||
import { StatelessDropdownMenu } from '@atlaskit/dropdown-menu';
|
||||
|
||||
import { translate } from '../../base/i18n';
|
||||
import CountryIcon from './CountryIcon';
|
||||
import { updateDialOutCodes } from '../actions';
|
||||
|
||||
/**
|
||||
* The expand icon of the dropdown menu.
|
||||
*
|
||||
* @type {XML}
|
||||
*/
|
||||
const EXPAND_ICON = <ExpandIcon label = 'expand' />;
|
||||
|
||||
/**
|
||||
* The default value of the country if the fetch service is unavailable.
|
||||
*
|
||||
* @type {{name: string, dialCode: string, code: string}}
|
||||
*/
|
||||
const DEFAULT_COUNTRY = {
|
||||
name: 'United States',
|
||||
dialCode: '+1',
|
||||
code: 'US'
|
||||
};
|
||||
|
||||
/**
|
||||
* React {@code Component} responsible for fetching and displaying dial-out
|
||||
* country codes, as well as dialing a phone number.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class DialOutNumbersForm extends Component {
|
||||
/**
|
||||
* {@code DialOutNumbersForm}'s property types.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static propTypes = {
|
||||
/**
|
||||
* The redux state representing the list of dial-out codes.
|
||||
*/
|
||||
_dialOutCodes: React.PropTypes.array,
|
||||
|
||||
/**
|
||||
* The function called on every dial input change.
|
||||
*/
|
||||
onChange: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: React.PropTypes.func,
|
||||
|
||||
/**
|
||||
* Invoked to send an ajax request for dial-out codes.
|
||||
*/
|
||||
updateDialOutCodes: React.PropTypes.func
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@code DialOutNumbersForm} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
dialInput: '',
|
||||
|
||||
/**
|
||||
* Whether or not the dropdown should be open.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
isDropdownOpen: false,
|
||||
|
||||
/**
|
||||
* The selected country.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
selectedCountry: DEFAULT_COUNTRY
|
||||
};
|
||||
|
||||
/**
|
||||
* The internal reference to the DOM/HTML element backing the React
|
||||
* {@code Component} text input.
|
||||
*
|
||||
* @private
|
||||
* @type {HTMLInputElement}
|
||||
*/
|
||||
this._dialInputElem = null;
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
this._onInputChange = this._onInputChange.bind(this);
|
||||
this._onOpenChange = this._onOpenChange.bind(this);
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
this._setDialInputElement = this._setDialInputElement.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a request for dial out codes if not already present in the
|
||||
* redux store. If dial out codes are present, sets a default code to
|
||||
* display in the dropdown trigger.
|
||||
*
|
||||
* @inheritdoc
|
||||
* returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const dialOutCodes = this.props._dialOutCodes;
|
||||
|
||||
if (dialOutCodes) {
|
||||
this._setDefaultCode(dialOutCodes);
|
||||
} else {
|
||||
this.props.updateDialOutCodes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors for dial out code updates and sets a default code to display in
|
||||
* the dropdown trigger if not already set.
|
||||
*
|
||||
* @inheritdoc
|
||||
* returns {void}
|
||||
*/
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!this.state.selectedCountry && nextProps._dialOutCodes) {
|
||||
this._setDefaultCode(nextProps._dialOutCodes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { t, _dialOutCodes } = this.props;
|
||||
|
||||
const items
|
||||
= _dialOutCodes ? this._formatCountryCodes(_dialOutCodes) : [];
|
||||
|
||||
return (
|
||||
<div className = 'form-control'>
|
||||
{ this._createDropdownMenu(items) }
|
||||
<div className = 'dial-out-input'>
|
||||
<input
|
||||
autoFocus = { true }
|
||||
className = 'input-control'
|
||||
onChange = { this._onInputChange }
|
||||
placeholder = { t('dialOut.enterPhone') }
|
||||
ref = { this._setDialInputElement }
|
||||
type = 'text' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code StatelessDropdownMenu} instance.
|
||||
*
|
||||
* @param {Array} items - The content to display within the dropdown.
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_createDropdownMenu(items) {
|
||||
const { code, dialCode } = this.state.selectedCountry;
|
||||
|
||||
return (
|
||||
<StatelessDropdownMenu
|
||||
isOpen = { this.state.isDropdownOpen }
|
||||
items = { [ { items } ] }
|
||||
onItemActivated = { this._onSelect }
|
||||
onOpenChange = { this._onOpenChange }
|
||||
shouldFitContainer = { true }>
|
||||
{ this._createDropdownTrigger(dialCode, code) }
|
||||
</StatelessDropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a React {@code Component} with a readonly HTMLInputElement as a
|
||||
* trigger for displaying the dropdown menu. The {@code Component} will also
|
||||
* display the currently selected number.
|
||||
*
|
||||
* @param {string} dialCode - The +xx dial code.
|
||||
* @param {string} countryCode - The country 2 letter code.
|
||||
* @private
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_createDropdownTrigger(dialCode, countryCode) {
|
||||
return (
|
||||
<div className = 'dropdown'>
|
||||
<CountryIcon
|
||||
className = 'dial-out-flag-icon'
|
||||
countryCode = { `${countryCode}` } />
|
||||
<input
|
||||
className = 'input-control dial-out-code'
|
||||
readOnly = { true }
|
||||
type = 'text'
|
||||
value = { dialCode || '' } />
|
||||
<span className = 'dropdown-trigger-icon'>
|
||||
{ EXPAND_ICON }
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the passed in numbers object into an array of objects that can
|
||||
* be parsed by {@code StatelessDropdownMenu}.
|
||||
*
|
||||
* @param {Object} countryCodes - The list of country codes.
|
||||
* @private
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
_formatCountryCodes(countryCodes) {
|
||||
|
||||
return countryCodes.map(country => {
|
||||
const countryIcon
|
||||
= <CountryIcon countryCode = { `${country.code}` } />;
|
||||
|
||||
const countryElement
|
||||
= <span>{countryIcon} { country.name }</span>;
|
||||
|
||||
return {
|
||||
content: `${country.dialCode}`,
|
||||
elemBefore: countryElement,
|
||||
country
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the dialNumber when changes to the dial text or code happen.
|
||||
*
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDialNumberChange() {
|
||||
const { dialCode } = this.state.selectedCountry;
|
||||
|
||||
this.props.onChange(dialCode, this.state.dialInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the dialInput state when the input changes.
|
||||
*
|
||||
* @param {Object} e - The event notifying us of the change.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onInputChange(e) {
|
||||
this.setState({
|
||||
dialInput: e.target.value
|
||||
}, () => {
|
||||
this._onDialNumberChange();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal state to either open or close the dropdown. If the
|
||||
* dropdown is disabled, the state will always be set to false.
|
||||
*
|
||||
* @param {Object} dropdownEvent - The even returned from clicking on the
|
||||
* dropdown trigger.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onOpenChange(dropdownEvent) {
|
||||
this.setState({
|
||||
isDropdownOpen: dropdownEvent.isOpen
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the internal state of the currently selected country code.
|
||||
*
|
||||
* @param {Object} selection - Event from choosing an dropdown option.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSelect(selection) {
|
||||
this.setState({
|
||||
isDropdownOpen: false,
|
||||
selectedCountry: selection.item.country
|
||||
}, () => {
|
||||
this._onDialNumberChange();
|
||||
|
||||
this._dialInputElem.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the internal state of the currently selected number by defaulting
|
||||
* to the first available number.
|
||||
*
|
||||
* @param {Object} countryCodes - The list of country codes to choose from
|
||||
* for setting a default code.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_setDefaultCode(countryCodes) {
|
||||
this.setState({
|
||||
selectedCountry: countryCodes[0]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal reference to the DOM/HTML element backing the React
|
||||
* {@code Component} dial input.
|
||||
*
|
||||
* @param {HTMLInputElement} input - The DOM/HTML element for this
|
||||
* {@code Component}'s text input.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_setDialInputElement(input) {
|
||||
this._dialInputElem = input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps (parts of) the Redux state to the associated
|
||||
* {@code DialOutNumbersForm}'s props.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @private
|
||||
* @returns {{
|
||||
* _dialOutCodes: React.PropTypes.object
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
const { dialOutCodes } = state['features/dial-out'];
|
||||
|
||||
return {
|
||||
_dialOutCodes: dialOutCodes
|
||||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps,
|
||||
{ updateDialOutCodes })(DialOutNumbersForm));
|
||||
@@ -0,0 +1 @@
|
||||
export { default as DialOutDialog } from './DialOutDialog';
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './actions';
|
||||
export * from './components';
|
||||
|
||||
import './reducer';
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
ReducerRegistry
|
||||
} from '../base/redux';
|
||||
|
||||
import {
|
||||
DIAL_OUT_CANCELED,
|
||||
DIAL_OUT_CODES_UPDATED,
|
||||
DIAL_OUT_SERVICE_FAILED,
|
||||
PHONE_NUMBER_CHECKED
|
||||
} from './actionTypes';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
dialOutCodes: null,
|
||||
error: null,
|
||||
isDialNumberAllowed: true
|
||||
};
|
||||
|
||||
ReducerRegistry.register(
|
||||
'features/dial-out',
|
||||
(state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case DIAL_OUT_CANCELED: {
|
||||
return DEFAULT_STATE;
|
||||
}
|
||||
case DIAL_OUT_CODES_UPDATED: {
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
dialOutCodes: action.response
|
||||
};
|
||||
}
|
||||
case DIAL_OUT_SERVICE_FAILED: {
|
||||
return {
|
||||
...state,
|
||||
error: action.error
|
||||
};
|
||||
}
|
||||
case PHONE_NUMBER_CHECKED: {
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
isDialNumberAllowed: action.response.allow
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
||||
@@ -192,7 +192,7 @@ class DialInNumbersForm extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a React {@code Component} with a redonly HTMLInputElement as a
|
||||
* Creates a React {@code Component} with a readonly HTMLInputElement as a
|
||||
* trigger for displaying the dropdown menu. The {@code Component} will also
|
||||
* display the currently selected number.
|
||||
*
|
||||
@@ -269,7 +269,7 @@ class DialInNumbersForm extends Component {
|
||||
return [];
|
||||
}
|
||||
|
||||
const formattedNumbeers = phoneRegions.map(region => {
|
||||
const formattedNumbers = phoneRegions.map(region => {
|
||||
const numbers = dialInNumbers[region];
|
||||
|
||||
return numbers.map(number => {
|
||||
@@ -280,7 +280,7 @@ class DialInNumbersForm extends Component {
|
||||
});
|
||||
});
|
||||
|
||||
return Array.prototype.concat(...formattedNumbeers);
|
||||
return Array.prototype.concat(...formattedNumbers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -215,14 +215,15 @@ export function showSharedVideoButton(): Function {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows SIP call button if it's required and appropriate flag is passed.
|
||||
* Shows the dial out button if it's required and appropriate
|
||||
* flag is passed.
|
||||
*
|
||||
* @param {boolean} show - Flag showing whether to show button or not.
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function showSIPCallButton(show: boolean): Function {
|
||||
export function showDialOutButton(show: boolean): Function {
|
||||
return (dispatch: Dispatch<*>, getState: Function) => {
|
||||
const buttonName = 'sip';
|
||||
const buttonName = 'dialout';
|
||||
|
||||
if (show
|
||||
&& APP.conference.sipGatewayEnabled()
|
||||
|
||||
@@ -5,39 +5,11 @@ import React from 'react';
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
|
||||
import { openInviteDialog } from '../invite';
|
||||
import { openDialOutDialog } from '../dial-out';
|
||||
|
||||
declare var APP: Object;
|
||||
declare var config: Object;
|
||||
declare var JitsiMeetJS: Object;
|
||||
|
||||
/**
|
||||
* Shows SIP number dialog.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function _showSIPNumberInput() {
|
||||
const defaultNumber = config.defaultSipNumber || '';
|
||||
const msgString
|
||||
= `<input class="input-control" name="sipNumber" type="text" value="${
|
||||
defaultNumber}" autofocus>`;
|
||||
|
||||
APP.UI.messageHandler.openTwoButtonDialog({
|
||||
focus: ':input:first',
|
||||
leftButtonKey: 'dialog.Dial',
|
||||
msgString,
|
||||
titleKey: 'dialog.sipMsg',
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
submitFunction(event, value, message, formValues) {
|
||||
const { sipNumber } = formValues;
|
||||
|
||||
if (value && sipNumber) {
|
||||
APP.UI.emitEvent(UIEvents.SIP_DIAL, sipNumber);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* All toolbar buttons' descriptors.
|
||||
*/
|
||||
@@ -169,6 +141,23 @@ export default {
|
||||
tooltipKey: 'toolbar.sharescreen'
|
||||
},
|
||||
|
||||
/**
|
||||
* The descriptor of the dial out toolbar button.
|
||||
*/
|
||||
dialout: {
|
||||
classNames: [ 'button', 'icon-telephone' ],
|
||||
enabled: true,
|
||||
|
||||
// Will be displayed once the SIP calls functionality is detected.
|
||||
hidden: true,
|
||||
id: 'toolbar_button_dial_out',
|
||||
onClick() {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.sip.clicked');
|
||||
APP.store.dispatch(openDialOutDialog());
|
||||
},
|
||||
tooltipKey: 'dialOut.dialOut'
|
||||
},
|
||||
|
||||
/**
|
||||
* The descriptor of the dialpad toolbar button.
|
||||
*/
|
||||
@@ -395,22 +384,5 @@ export default {
|
||||
}
|
||||
],
|
||||
tooltipKey: 'toolbar.sharedvideo'
|
||||
},
|
||||
|
||||
/**
|
||||
* The descriptor of the SIP call toolbar button.
|
||||
*/
|
||||
sip: {
|
||||
classNames: [ 'button', 'icon-telephone' ],
|
||||
enabled: true,
|
||||
|
||||
// Will be displayed once the SIP calls functionality is detected.
|
||||
hidden: true,
|
||||
id: 'toolbar_button_sip',
|
||||
onClick() {
|
||||
JitsiMeetJS.analytics.sendEvent('toolbar.sip.clicked');
|
||||
_showSIPNumberInput();
|
||||
},
|
||||
tooltipKey: 'toolbar.sip'
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user