From 093254d948fbcc67afbe339840bf93f7564980ae Mon Sep 17 00:00:00 2001 From: Mihai Uscat Date: Wed, 24 Jun 2020 15:12:23 +0300 Subject: [PATCH] fix(AddPeopleDialog): Improve contact invite form - Disables the invite buttons while invites are ongoing - Adds a keyboard shortcut (Enter) to send out invites - Closes AddPeopleDialog upon successful invites sent - Fixes the SecurityDialog closing when trying to set E2EE key via Enter shortcut - Removes superfluous separator from SecurityDialog --- css/modals/invite/_invite_more.scss | 6 ++++ css/modals/security/_security.scss | 6 +--- react/features/e2ee/components/E2EESection.js | 15 ++++++++++ react/features/invite/actionTypes.js | 5 ++++ react/features/invite/actions.any.js | 15 ++++++++++ .../web/InviteContactsForm.js | 29 +++++++++++++++++-- react/features/invite/middleware.web.js | 25 ++++++++++++++-- .../lobby/components/web/LobbySection.js | 23 ++++++++------- .../security-dialog/SecurityDialog.js | 1 - 9 files changed, 104 insertions(+), 21 deletions(-) diff --git a/css/modals/invite/_invite_more.scss b/css/modals/invite/_invite_more.scss index 1b815322a..824ed7f6b 100644 --- a/css/modals/invite/_invite_more.scss +++ b/css/modals/invite/_invite_more.scss @@ -208,6 +208,12 @@ padding: 8px 16px; background: #0376DA; } + + &.disabled { + & > a { + pointer-events: none; + } + } } &.stream { diff --git a/css/modals/security/_security.scss b/css/modals/security/_security.scss index 2543dac5d..704a2c274 100644 --- a/css/modals/security/_security.scss +++ b/css/modals/security/_security.scss @@ -21,15 +21,11 @@ font-size: 14px; color: #6FB1EA; } - - &>a+a { - margin-left: 24px; - } } } } - &> :first-child:not(:last-child) { + & > :first-child:not(:last-child) { margin-right: 24px; } diff --git a/react/features/e2ee/components/E2EESection.js b/react/features/e2ee/components/E2EESection.js index aca7236c5..0457172cf 100644 --- a/react/features/e2ee/components/E2EESection.js +++ b/react/features/e2ee/components/E2EESection.js @@ -109,6 +109,7 @@ class E2EESection extends Component { disabled = { !editing } name = 'e2eeKey' onChange = { this._onKeyChange } + onKeyDown = { this._onKeyDown } placeholder = { t('dialog.e2eeNoKey') } ref = { this.fieldRef } type = 'password' @@ -137,6 +138,20 @@ class E2EESection extends Component { this.setState({ key: event.target.value.trim() }); } + _onKeyDown: (Object) => void; + + /** + * Handler for the keydown event on the form, preventing the closing of the dialog. + * + * @param {Object} event - The DOM event triggered by keydown events. + * @returns {void} + */ + _onKeyDown(event) { + if (event.key === 'Enter') { + event.preventDefault(); + } + } + _onSet: () => void; /** diff --git a/react/features/invite/actionTypes.js b/react/features/invite/actionTypes.js index 0ac2d750b..cb59c7f30 100644 --- a/react/features/invite/actionTypes.js +++ b/react/features/invite/actionTypes.js @@ -41,6 +41,11 @@ export const REMOVE_PENDING_INVITE_REQUESTS */ export const SET_CALLEE_INFO_VISIBLE = 'SET_CALLEE_INFO_VISIBLE'; +/** + * The type of redux action to signal that the {@code AddPeopleDialog} should close. + */ +export const HIDE_ADD_PEOPLE_DIALOG = 'HIDE_ADD_PEOPLE_DIALOG'; + /** * The type of the action which signals an error occurred while requesting dial- * in numbers. diff --git a/react/features/invite/actions.any.js b/react/features/invite/actions.any.js index 96255fce0..5accc320a 100644 --- a/react/features/invite/actions.any.js +++ b/react/features/invite/actions.any.js @@ -9,6 +9,7 @@ import { inviteVideoRooms } from '../videosipgw'; import { ADD_PENDING_INVITE_REQUEST, BEGIN_ADD_PEOPLE, + HIDE_ADD_PEOPLE_DIALOG, REMOVE_PENDING_INVITE_REQUESTS, SET_CALLEE_INFO_VISIBLE, UPDATE_DIAL_IN_NUMBERS_FAILED, @@ -36,6 +37,20 @@ export function beginAddPeople() { }; } +/** + * Creates a (redux) action to signal that the {@code AddPeopleDialog} + * should close. + * + * @returns {{ + * type: HIDE_ADD_PEOPLE_DIALOG + * }} + */ +export function hideAddPeopleDialog() { + return { + type: HIDE_ADD_PEOPLE_DIALOG + }; +} + /** * Invites (i.e. Sends invites to) an array of invitees (which may be a diff --git a/react/features/invite/components/add-people-dialog/web/InviteContactsForm.js b/react/features/invite/components/add-people-dialog/web/InviteContactsForm.js index dc9220f2d..72ae039f3 100644 --- a/react/features/invite/components/add-people-dialog/web/InviteContactsForm.js +++ b/react/features/invite/components/add-people-dialog/web/InviteContactsForm.js @@ -10,6 +10,7 @@ import { Icon, IconPhone } from '../../../../base/icons'; import { getLocalParticipant } from '../../../../base/participants'; import { MultiSelectAutocomplete } from '../../../../base/react'; import { connect } from '../../../../base/redux'; +import { hideAddPeopleDialog } from '../../../actions'; import AbstractAddPeopleDialog, { type Props as AbstractProps, type State, @@ -72,6 +73,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog { this._parseQueryResults = this._parseQueryResults.bind(this); this._setMultiSelectElement = this._setMultiSelectElement.bind(this); this._renderFooterText = this._renderFooterText.bind(this); + this._onKeyDown = this._onKeyDown.bind(this); this._resourceClient = { makeQuery: this._query, @@ -135,7 +137,9 @@ class InviteContactsForm extends AbstractAddPeopleDialog { } return ( -
+
{ this._renderErrorMessage() } { this._multiselect.setSelectedItems(itemsToSelect); } } else { - // Do nothing. + this.props.dispatch(hideAddPeopleDialog()); } }); } + _onKeyDown: (Object) => void; + + /** + * Handles 'Enter' key in the form to trigger the invite. + * + * @param {Object} event - The key event. + * @returns {void} + */ + _onKeyDown(event) { + const { inviteItems } = this.state; + + if (event.key === 'Enter') { + event.preventDefault(); + if (!this._isAddDisabled() && inviteItems.length) { + this._onSubmit(); + } + } + } + _parseQueryResults: (?Array) => Array; /** @@ -380,7 +403,7 @@ class InviteContactsForm extends AbstractAddPeopleDialog { } return ( -
+
diff --git a/react/features/invite/middleware.web.js b/react/features/invite/middleware.web.js index d67008b24..2abb43327 100644 --- a/react/features/invite/middleware.web.js +++ b/react/features/invite/middleware.web.js @@ -1,9 +1,9 @@ // @flow -import { openDialog } from '../base/dialog'; +import { hideDialog, openDialog } from '../base/dialog'; import { MiddlewareRegistry } from '../base/redux'; -import { BEGIN_ADD_PEOPLE } from './actionTypes'; +import { BEGIN_ADD_PEOPLE, HIDE_ADD_PEOPLE_DIALOG } from './actionTypes'; import { AddPeopleDialog } from './components'; import './middleware.any'; @@ -17,6 +17,8 @@ MiddlewareRegistry.register(store => next => action => { switch (action.type) { case BEGIN_ADD_PEOPLE: return _beginAddPeople(store, next, action); + case HIDE_ADD_PEOPLE_DIALOG: + return _hideAddPeopleDialog(store, next, action); } return next(action); @@ -42,3 +44,22 @@ function _beginAddPeople({ dispatch }, next, action) { return result; } + +/** + * Notifies the feature invite that the action {@link HIDE_ADD_PEOPLE_DIALOG} is being + * dispatched within a specific redux {@code store}. + * + * @param {Store} store - The redux store in which the specified {@code action} + * is being dispatched. + * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the + * specified {@code action} to the specified {@code store}. + * @param {Action} action - The redux action {@code HIDE_ADD_PEOPLE_DIALOG} which is + * being dispatched in the specified {@code store}. + * @private + * @returns {*} The value returned by {@code next(action)}. + */ +function _hideAddPeopleDialog({ dispatch }, next, action) { + dispatch(hideDialog(AddPeopleDialog)); + + return next(action); +} diff --git a/react/features/lobby/components/web/LobbySection.js b/react/features/lobby/components/web/LobbySection.js index 52772f022..c0fc9ee13 100644 --- a/react/features/lobby/components/web/LobbySection.js +++ b/react/features/lobby/components/web/LobbySection.js @@ -86,17 +86,20 @@ class LobbySection extends PureComponent { } return ( -
- { t('lobby.enableDialogText') } -
- - + <> +
+ { t('lobby.enableDialogText') } +
+ + +
-
+
+ ); } diff --git a/react/features/security/components/security-dialog/SecurityDialog.js b/react/features/security/components/security-dialog/SecurityDialog.js index 29ad89cd6..4d24cb837 100644 --- a/react/features/security/components/security-dialog/SecurityDialog.js +++ b/react/features/security/components/security-dialog/SecurityDialog.js @@ -89,7 +89,6 @@ function SecurityDialog({ width = { 'small' }>
-