From 61470c0d24277ff896b41fc548bd35e51c271a1c Mon Sep 17 00:00:00 2001 From: damencho Date: Mon, 6 Mar 2017 21:43:41 -0600 Subject: [PATCH] Moves web password required dialog to react. --- conference.js | 4 - modules/UI/invite/Invite.js | 23 --- modules/UI/invite/RequirePasswordDialog.js | 162 ------------------ modules/UI/invite/RoomLocker.js | 29 ---- package.json | 1 + react/features/app/components/App.web.js | 2 + react/features/room-lock/actions.js | 18 ++ .../components/PasswordRequiredPrompt.web.js | 127 ++++++++++++++ .../components/RoomLockPrompt.web.js | 0 react/features/room-lock/components/index.js | 1 + react/features/room-lock/index.js | 1 + react/features/room-lock/middleware.js | 36 ++++ service/UI/UIEvents.js | 5 - 13 files changed, 186 insertions(+), 223 deletions(-) delete mode 100644 modules/UI/invite/RequirePasswordDialog.js create mode 100644 react/features/room-lock/components/PasswordRequiredPrompt.web.js create mode 100644 react/features/room-lock/components/RoomLockPrompt.web.js create mode 100644 react/features/room-lock/middleware.js diff --git a/conference.js b/conference.js index 94d3cef151..ae035ace19 100644 --- a/conference.js +++ b/conference.js @@ -387,10 +387,6 @@ class ConferenceConnector { logger.error('CONFERENCE FAILED:', err, ...params); APP.UI.hideRingOverLay(); switch (err) { - // room is locked by the password - case ConferenceErrors.PASSWORD_REQUIRED: - APP.UI.emitEvent(UIEvents.PASSWORD_REQUIRED); - break; case ConferenceErrors.CONNECTION_ERROR: { diff --git a/modules/UI/invite/Invite.js b/modules/UI/invite/Invite.js index baa4015810..b5127d7b69 100644 --- a/modules/UI/invite/Invite.js +++ b/modules/UI/invite/Invite.js @@ -47,31 +47,8 @@ class Invite { } }); - this.conference.on(ConferenceEvents.CONFERENCE_JOINED, () => { - let roomLocker = this.getRoomLocker(); - roomLocker.hideRequirePasswordDialog(); - }); - APP.UI.addListener( UIEvents.INVITE_CLICKED, () => { this.openLinkDialog(); }); - - APP.UI.addListener( UIEvents.PASSWORD_REQUIRED, - () => { - let roomLocker = this.getRoomLocker(); - this.setLockedFromElsewhere(true); - roomLocker.requirePassword().then(() => { - let pass = roomLocker.password; - // we received that password is required, but user is trying - // anyway to login without a password, mark room as not - // locked in case he succeeds (maybe someone removed the - // password meanwhile), if it is still locked another - // password required will be received and the room again - // will be marked as locked. - if (!pass) - this.setLockedFromElsewhere(false); - this.conference.join(pass); - }); - }); } /** diff --git a/modules/UI/invite/RequirePasswordDialog.js b/modules/UI/invite/RequirePasswordDialog.js deleted file mode 100644 index 5fe12eb889..0000000000 --- a/modules/UI/invite/RequirePasswordDialog.js +++ /dev/null @@ -1,162 +0,0 @@ -/* global APP */ - -import UIUtil from '../util/UIUtil'; - -/** - * Show dialog which asks for required conference password. - * @returns {Promise} password or nothing if user canceled - */ -export default class RequirePasswordDialog { - constructor() { - this.titleKey = 'dialog.passwordRequired'; - this.labelKey = 'dialog.passwordLabel'; - this.errorKey = 'dialog.incorrectPassword'; - this.errorId = 'passwordRequiredError'; - this.inputId = 'passwordRequiredInput'; - this.inputErrorClass = 'error'; - this.isOpened = false; - } - - /** - * Registering dialog listeners - * @private - */ - _registerListeners() { - let el = document.getElementById(this.inputId); - el.addEventListener('keypress', this._hideError.bind(this)); - } - - /** - * Helper method returning dialog body - * @returns {string} - * @private - */ - _getBodyMessage() { - return ( - `
- - -

-
` - ); - } - - /** - * Asking for a password - * @returns {Promise} - */ - askForPassword() { - if (!this.isOpened) { - return this.open(); - } - - return new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; - this._showError(); - }); - } - - /** - * Opens the dialog - * @returns {Promise} - */ - open() { - let { titleKey } = this; - let msgString = this._getBodyMessage(); - - return new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; - let submitFunction = this._submitFunction.bind(this); - let closeFunction = this._closeFunction.bind(this); - - this._dialog = APP.UI.messageHandler.openTwoButtonDialog({ - titleKey, - msgString, - leftButtonKey: "dialog.Ok", - submitFunction, - closeFunction, - focus: ':input:first' - }); - - this._registerListeners(); - this.isOpened = true; - }); - } - - /** - * Submit dialog callback - * @param e - event - * @param v - value - * @param m - message - * @param f - form - * @private - */ - _submitFunction(e, v, m, f) { - e.preventDefault(); - this._processInput(v, f); - } - - /** - * Processing input in dialog - * @param v - value - * @param f - form - * @private - */ - _processInput(v, f) { - if (v && f.lockKey) { - this.resolve(UIUtil.escapeHtml(f.lockKey)); - } else { - this.reject(APP.UI.messageHandler.CANCEL); - } - } - - /** - * Close dialog callback - * @private - */ - _closeFunction(e, v, m, f) { - this._processInput(v, f); - this._hideError(); - this.close(); - } - - /** - * Method showing error hint - * @private - */ - _showError() { - let className = this.inputErrorClass; - let input = document.getElementById(this.inputId); - document.getElementById(this.errorId).classList.remove('hide'); - input.classList.add(className); - input.select(); - } - - /** - * Method hiding error hint - * @private - */ - _hideError() { - let className = this.inputErrorClass; - document.getElementById(this.errorId).classList.add('hide'); - document.getElementById(this.inputId).classList.remove(className); - } - - /** - * Close the dialog - */ - close() { - if (this._dialog) { - this._dialog.close(); - } - this.isOpened = false; - } -} \ No newline at end of file diff --git a/modules/UI/invite/RoomLocker.js b/modules/UI/invite/RoomLocker.js index da5c0e2350..59f43e3317 100644 --- a/modules/UI/invite/RoomLocker.js +++ b/modules/UI/invite/RoomLocker.js @@ -1,8 +1,6 @@ /* global APP, JitsiMeetJS */ const logger = require("jitsi-meet-logger").getLogger(__filename); -import RequirePasswordDialog from './RequirePasswordDialog'; - /** * Show notification that user cannot set password for the conference * because server doesn't support that. @@ -33,7 +31,6 @@ const ConferenceErrors = JitsiMeetJS.errors.conference; */ export default function createRoomLocker (room) { let password; - let requirePasswordDialog = new RequirePasswordDialog(); /** * If the room was locked from someone other than us, we indicate it with * this property in order to have correct roomLocker state of isLocked. @@ -102,31 +99,5 @@ export default function createRoomLocker (room) { password = null; }, - /** - * Asks user for required conference password. - */ - requirePassword () { - return requirePasswordDialog.askForPassword().then( - newPass => { password = newPass; } - ).catch( - reason => { - // user canceled, no pass was entered. - // clear, as if we use the same instance several times - // pass stays between attempts - password = null; - if (reason !== APP.UI.messageHandler.CANCEL) - logger.error(reason); - } - ); - }, - - /** - * Hides require password dialog - */ - hideRequirePasswordDialog() { - if (requirePasswordDialog.isOpened) { - requirePasswordDialog.close(); - } - } }; } diff --git a/package.json b/package.json index f9b17fd3ce..92b0e53343 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@atlassian/aui": "6.0.6", "@atlaskit/button": "1.0.3", "@atlaskit/button-group": "1.0.0", + "@atlaskit/field-text": "2.0.3", "@atlaskit/modal-dialog": "1.2.4", "async": "0.9.0", "autosize": "1.18.13", diff --git a/react/features/app/components/App.web.js b/react/features/app/components/App.web.js index c2dc8d129b..574e8156e9 100644 --- a/react/features/app/components/App.web.js +++ b/react/features/app/components/App.web.js @@ -1,6 +1,8 @@ import { appInit } from '../actions'; import { AbstractApp } from './AbstractApp'; +import '../../room-lock'; + /** * Root application component. * diff --git a/react/features/room-lock/actions.js b/react/features/room-lock/actions.js index 7d6c7bba1e..0d06dc4a49 100644 --- a/react/features/room-lock/actions.js +++ b/react/features/room-lock/actions.js @@ -1,4 +1,6 @@ import { setPassword } from '../base/conference'; +import { openDialog } from '../base/dialog'; +import { PasswordRequiredPrompt } from './components'; import { BEGIN_ROOM_LOCK_REQUEST, END_ROOM_LOCK_REQUEST } from './actionTypes'; @@ -53,3 +55,19 @@ export function endRoomLockRequest(conference, password) { setPassword_.then(endRoomLockRequest_, endRoomLockRequest_); }; } + +/** + * Begins a request to enter password for a specific conference/room. + * + * @param {JitsiConference} conference - The JitsiConference + * requesting password. + * @protected + * @returns {{ + * type: BEGIN_DIALOG_REQUEST, + * component: Component, + * props: React.PropTypes + * }} + */ +export function _showPasswordDialog(conference) { + return openDialog(PasswordRequiredPrompt, { conference }); +} diff --git a/react/features/room-lock/components/PasswordRequiredPrompt.web.js b/react/features/room-lock/components/PasswordRequiredPrompt.web.js new file mode 100644 index 0000000000..0d42014f94 --- /dev/null +++ b/react/features/room-lock/components/PasswordRequiredPrompt.web.js @@ -0,0 +1,127 @@ +/* global APP */ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import AKFieldText from '@atlaskit/field-text'; + +import { setPassword } from '../../base/conference'; +import { Dialog } from '../../base/dialog'; +import { translate } from '../../base/i18n'; + +/** + * Implements a React Component which prompts the user when a password is + * required to join a conference. + */ +class PasswordRequiredPrompt extends Component { + /** + * PasswordRequiredPrompt component's property types. + * + * @static + */ + static propTypes = { + /** + * The JitsiConference which requires a password. + * + * @type {JitsiConference} + */ + conference: React.PropTypes.object, + dispatch: React.PropTypes.func, + t: React.PropTypes.func + } + + /** + * Initializes a new PasswordRequiredPrompt instance. + * + * @param {Object} props - The read-only properties with which the new + * instance is to be initialized. + */ + constructor(props) { + super(props); + + this.state = { password: '' }; + + this._onPasswordChanged = this._onPasswordChanged.bind(this); + this._onSubmit = this._onSubmit.bind(this); + } + + /** + * Implements React's {@link Component#render()}. + * + * @inheritdoc + * @returns {ReactElement} + */ + render() { + return ( + + { this._renderBody() } + ); + } + + /** + * Display component in dialog body. + * + * @returns {ReactElement} + * @protected + */ + _renderBody() { + const { t } = this.props; + + return ( +
+ +
); + } + + /** + * Notifies this dialog that password has changed. + * + * @param {Object} event - The details of the notification/event. + * @private + * @returns {void} + */ + _onPasswordChanged(event) { + this.setState({ password: event.target.value }); + } + + /** + * Dispatches action to submit value from thus dialog. + * + * @private + * @returns {void} + */ + _onSubmit() { + const conference = this.props.conference; + + // we received that password is required, but user is trying + // anyway to login without a password, mark room as not + // locked in case he succeeds (maybe someone removed the + // password meanwhile), if it is still locked another + // password required will be received and the room again + // will be marked as locked. + if (!this.state.password || this.state.password === '') { + // XXX temporary solution till we move the whole invite logic + // in react + APP.conference.invite.setLockedFromElsewhere(false); + } + + this.props.dispatch(setPassword( + conference, conference.join, this.state.password)); + + // we have used the password lets clean it + this.setState({ password: undefined }); + + return true; + } +} + +export default translate(connect()(PasswordRequiredPrompt)); diff --git a/react/features/room-lock/components/RoomLockPrompt.web.js b/react/features/room-lock/components/RoomLockPrompt.web.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/react/features/room-lock/components/index.js b/react/features/room-lock/components/index.js index a67f1c4db4..0119e86823 100644 --- a/react/features/room-lock/components/index.js +++ b/react/features/room-lock/components/index.js @@ -1 +1,2 @@ export { default as RoomLockPrompt } from './RoomLockPrompt'; +export { default as PasswordRequiredPrompt } from './PasswordRequiredPrompt'; diff --git a/react/features/room-lock/index.js b/react/features/room-lock/index.js index 582e1f9dd4..7f0ef0251d 100644 --- a/react/features/room-lock/index.js +++ b/react/features/room-lock/index.js @@ -1,4 +1,5 @@ export * from './actions'; export * from './components'; +import './middleware'; import './reducer'; diff --git a/react/features/room-lock/middleware.js b/react/features/room-lock/middleware.js new file mode 100644 index 0000000000..10a8fb6e56 --- /dev/null +++ b/react/features/room-lock/middleware.js @@ -0,0 +1,36 @@ +/* global APP */ +import JitsiMeetJS from '../base/lib-jitsi-meet'; + +import { CONFERENCE_FAILED } from '../base/conference'; +import { MiddlewareRegistry } from '../base/redux'; +import { _showPasswordDialog } from './actions'; + +/** + * Middleware that captures conference failed and checks for password required + * error and requests a dialog for user to enter password. + * + * @param {Store} store - Redux store. + * @returns {Function} + */ +MiddlewareRegistry.register(store => next => action => { + + switch (action.type) { + case CONFERENCE_FAILED: { + const JitsiConferenceErrors = JitsiMeetJS.errors.conference; + + if (action.conference + && JitsiConferenceErrors.PASSWORD_REQUIRED === action.error) { + // XXX temporary solution till we move the whole invite + // logic in react + if (typeof APP !== 'undefined') { + APP.conference.invite.setLockedFromElsewhere(true); + } + + store.dispatch(_showPasswordDialog(action.conference)); + } + break; + } + } + + return next(action); +}); diff --git a/service/UI/UIEvents.js b/service/UI/UIEvents.js index 8994363747..a17f11ed00 100644 --- a/service/UI/UIEvents.js +++ b/service/UI/UIEvents.js @@ -150,11 +150,6 @@ export default { */ DISPLAY_NAME_CHANGED: "UI.display_name_changed", - /** - * Indicates that a password is required for the call. - */ - PASSWORD_REQUIRED: "UI.password_required", - /** * Show custom popup/tooltip for a specified button. */