From ed5351d25023cc5cf95ef6a42254a0ff0266b0da Mon Sep 17 00:00:00 2001 From: Andrei Gavrilescu <51706180+andrei-gavrilescu@users.noreply.github.com> Date: Wed, 5 Feb 2020 20:10:57 +0200 Subject: [PATCH] Add dial-in link to no audio notification (#5026) * Add dial-in link to no audio notification * refactor react link component * fix tests --- lang/main.json | 6 +- .../components/info-dialog/web/InfoDialog.js | 25 +---- react/features/invite/functions.js | 23 ++++- .../no-audio-signal/components/DialInLink.js | 95 +++++++++++++++++++ react/features/no-audio-signal/middleware.js | 6 +- 5 files changed, 130 insertions(+), 25 deletions(-) create mode 100644 react/features/no-audio-signal/components/DialInLink.js diff --git a/lang/main.json b/lang/main.json index 616f37aca..82feb8a49 100644 --- a/lang/main.json +++ b/lang/main.json @@ -635,8 +635,10 @@ "moreActions": "More actions", "mute": "Mute / Unmute", "noAudioSignalTitle": "There is no input coming from your mic!", - "noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider changing the device.", - "noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider using the following device:", + "noAudioSignalDesc": "If you did not purposely mute it from system settings or hardware, consider switching the device.", + "noAudioSignalDescSuggestion": "If you did not purposely mute it from system settings or hardware, consider switching to the suggested device.", + "noAudioSignalDialInDesc": "You can also dial-in using:", + "noAudioSignalDialInLinkDesc" : "Dial-in numbers", "noisyAudioInputTitle": "Your microphone appears to be noisy!", "noisyAudioInputDesc": "Jitsi has detected noise coming from your microphone, please consider muting or changing the device.", "openChat": "Open chat", diff --git a/react/features/invite/components/info-dialog/web/InfoDialog.js b/react/features/invite/components/info-dialog/web/InfoDialog.js index 6f9bdae2c..5215a2024 100644 --- a/react/features/invite/components/info-dialog/web/InfoDialog.js +++ b/react/features/invite/components/info-dialog/web/InfoDialog.js @@ -17,7 +17,8 @@ import { import { _decodeRoomURI, _getDefaultPhoneNumber, - getDialInfoPageURL + getDialInfoPageURL, + shouldDisplayDialIn } from '../../../functions'; import logger from '../../../logger'; import DialInNumber from './DialInNumber'; @@ -316,7 +317,6 @@ class InfoDialog extends Component { */ _getTextToCopy() { const { _localParticipant, liveStreamViewURL, t } = this.props; - const shouldDisplayDialIn = this._shouldDisplayDialIn(); const _inviteURL = _decodeRoomURI(this.props._inviteURL); let invite = _localParticipant && _localParticipant.name @@ -335,7 +335,7 @@ class InfoDialog extends Component { invite = `${invite}\n${liveStream}`; } - if (shouldDisplayDialIn) { + if (shouldDisplayDialIn(this.props.dialIn)) { const dial = t('info.invitePhone', { number: this.state.phoneNumber, conferenceID: this.props.dialIn.conferenceID @@ -480,7 +480,7 @@ class InfoDialog extends Component { * @returns {null|ReactElement} */ _renderDialInDisplay() { - if (!this._shouldDisplayDialIn()) { + if (!shouldDisplayDialIn(this.props.dialIn)) { return null; } @@ -571,23 +571,6 @@ class InfoDialog extends Component { ); } - /** - * Returns whether or not dial-in related UI should be displayed. - * - * @private - * @returns {boolean} - */ - _shouldDisplayDialIn() { - const { conferenceID, numbers, numbersEnabled } = this.props.dialIn; - const { phoneNumber } = this.state; - - return Boolean( - conferenceID - && numbers - && numbersEnabled - && phoneNumber); - } - _setCopyElement: () => void; /** diff --git a/react/features/invite/functions.js b/react/features/invite/functions.js index bdfe3e2b8..1e58959a2 100644 --- a/react/features/invite/functions.js +++ b/react/features/invite/functions.js @@ -524,6 +524,23 @@ export function getDialInfoPageURLForURIString( return `${protocol}//${host}${contextRoot}static/dialInInfo.html?room=${room}`; } +/** + * Returns whether or not dial-in related UI should be displayed. + * + * @param {Object} dialIn - Dial in information. + * @returns {boolean} + */ +export function shouldDisplayDialIn(dialIn: Object) { + const { conferenceID, numbers, numbersEnabled } = dialIn; + const phoneNumber = _getDefaultPhoneNumber(numbers); + + return Boolean( + conferenceID + && numbers + && numbersEnabled + && phoneNumber); +} + /** * Sets the internal state of which dial-in number to display. * @@ -533,7 +550,11 @@ export function getDialInfoPageURLForURIString( * @returns {string|null} */ export function _getDefaultPhoneNumber( - dialInNumbers: Object): ?string { + dialInNumbers: ?Object): ?string { + + if (!dialInNumbers) { + return null; + } if (Array.isArray(dialInNumbers)) { // new syntax follows diff --git a/react/features/no-audio-signal/components/DialInLink.js b/react/features/no-audio-signal/components/DialInLink.js new file mode 100644 index 000000000..90c8429a2 --- /dev/null +++ b/react/features/no-audio-signal/components/DialInLink.js @@ -0,0 +1,95 @@ +// @flow + +import React, { Component } from 'react'; + +import { connect } from '../../base/redux'; +import { translate } from '../../base/i18n'; +import { getDialInfoPageURL, shouldDisplayDialIn } from '../../invite'; + +/** + * The type of the React {@code Component} props of {@link DialInLink}. + */ +type Props = { + + /** + * The name of the current conference. + */ + _room: string, + + /** + * The current location url of the conference. + */ + _locationURL: string, + + + /** + * The redux state representing the dial-in numbers feature. + */ + _dialIn: Object, + + /** + * Invoked to obtain translated strings. + */ + t: Function +}; + +/** + * React {@code Component} responsible for displaying a telephone number and + * conference ID for dialing into a conference. + * + * @extends Component + */ +class DialInLink extends Component { + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {ReactElement} + */ + render() { + const { _room, _locationURL, _dialIn, t } = this.props; + + if (!shouldDisplayDialIn(_dialIn)) { + return null; + } + + return ( +
{t('toolbar.noAudioSignalDialInDesc')}  + + {t('toolbar.noAudioSignalDialInLinkDesc')} + +
+ ); + } +} + +/** + * Maps (parts of) the Redux state to the associated props for the + * {@code DialInLink} component. + * + * @param {Object} state - The Redux state. + * @private + * @returns {{ + * _room: string, + * _locationURL: string, + * _dialIn: Object, + * }} + */ +function _mapStateToProps(state) { + + return { + _room: state['features/base/conference'].room, + _locationURL: state['features/base/connection'].locationURL, + _dialIn: state['features/invite'] + }; +} + +export default translate(connect(_mapStateToProps)(DialInLink)); diff --git a/react/features/no-audio-signal/middleware.js b/react/features/no-audio-signal/middleware.js index 148e9fa7c..f8b4332c0 100644 --- a/react/features/no-audio-signal/middleware.js +++ b/react/features/no-audio-signal/middleware.js @@ -1,5 +1,7 @@ // @flow +import React from 'react'; + import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; import { CONFERENCE_JOINED } from '../base/conference'; import { @@ -13,6 +15,7 @@ import { playSound, registerSound, unregisterSound } from '../base/sounds'; import { hideNotification, showNotification } from '../notifications'; import { setNoAudioSignalNotificationUid } from './actions'; +import DialInLink from './components/DialInLink'; import { NO_AUDIO_SIGNAL_SOUND_ID } from './constants'; import { NO_AUDIO_SIGNAL_SOUND_FILE } from './sounds'; @@ -91,7 +94,7 @@ async function _handleNoAudioSignalNotification({ dispatch, getState }, action) // at the point of the implementation the showNotification function only supports doing that for // the description. // TODO Add support for arguments to showNotification title and customAction strings. - customActionNameKey = `Use ${formatDeviceLabel(activeDevice.deviceLabel)}`; + customActionNameKey = `Switch to ${formatDeviceLabel(activeDevice.deviceLabel)}`; customActionHandler = () => { // Select device callback dispatch( @@ -107,6 +110,7 @@ async function _handleNoAudioSignalNotification({ dispatch, getState }, action) const notification = showNotification({ titleKey: 'toolbar.noAudioSignalTitle', + description: , descriptionKey, customActionNameKey, customActionHandler