From 241dc3b14716679c452cdbbc7b5f5f14e0453ccb Mon Sep 17 00:00:00 2001 From: Lyubo Marinov Date: Mon, 18 Sep 2017 02:09:43 -0500 Subject: [PATCH] [RN] Support XMPP authentication --- lang/main.json | 2 +- modules/UI/authentication/AuthHandler.js | 53 +++-- modules/UI/authentication/LoginDialog.js | 39 ++-- react/features/app/components/App.native.js | 2 +- react/features/authentication/actionTypes.js | 47 ++-- react/features/authentication/actions.js | 219 ++++++++---------- .../components/LoginDialog.native.js | 174 +++++++------- .../components/WaitForOwnerDialog.native.js | 97 ++++---- .../authentication/components/styles.js | 60 +++-- react/features/authentication/functions.js | 74 ------ react/features/authentication/index.js | 3 +- react/features/authentication/middleware.js | 205 ++++++++-------- react/features/authentication/reducer.js | 46 ++-- react/features/base/conference/actions.js | 6 +- .../base/connection/actions.native.js | 9 +- react/features/base/connection/functions.js | 24 +- 16 files changed, 494 insertions(+), 566 deletions(-) delete mode 100644 react/features/authentication/functions.js diff --git a/lang/main.json b/lang/main.json index de572067e..bdb6b4344 100644 --- a/lang/main.json +++ b/lang/main.json @@ -264,7 +264,7 @@ "removeSharedVideoMsg": "Are you sure you would like to remove your shared video?", "alreadySharedVideoMsg": "Another member is already sharing video. This conference allows only one shared video at a time.", "WaitingForHost": "Waiting for the host ...", - "WaitForHostMsg": "The conference '__room__' has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.", + "WaitForHostMsg": "The conference __room__ has not yet started. If you are the host then please authenticate. Otherwise, please wait for the host to arrive.", "IamHost": "I am the host", "Cancel": "Cancel", "Submit": "Submit", diff --git a/modules/UI/authentication/AuthHandler.js b/modules/UI/authentication/AuthHandler.js index fd9c1b664..6510a58f3 100644 --- a/modules/UI/authentication/AuthHandler.js +++ b/modules/UI/authentication/AuthHandler.js @@ -139,38 +139,41 @@ function initJWTTokenListener(room) { * @param {JitsiConference} room * @param {string} [lockPassword] password to use if the conference is locked */ -function doXmppAuth (room, lockPassword) { - const loginDialog = LoginDialog.showAuthDialog(function (id, password) { - const authConnection = room.createAuthenticationConnection(); - - authConnection.authenticateAndUpgradeRole({ +function doXmppAuth(room, lockPassword) { + const loginDialog = LoginDialog.showAuthDialog( + /* successCallback */ (id, password) => { + room.authenticateAndUpgradeRole({ id, password, roomPassword: lockPassword, - onLoginSuccessful: () => { /* Called when XMPP login succeeds */ + + /** Called when the XMPP login succeeds. */ + onLoginSuccessful() { loginDialog.displayConnectionStatus( 'connection.FETCH_SESSION_ID'); } }) - .then(() => { - loginDialog.displayConnectionStatus( - 'connection.GOT_SESSION_ID'); - loginDialog.close(); - }) - .catch(error => { - logger.error('authenticateAndUpgradeRole failed', error); - if (error.authenticationError) { - loginDialog.displayError( - 'connection.GET_SESSION_ID_ERROR', { - msg: error.authenticationError - }); - } else { - loginDialog.displayError(error.connectionError); - } - }); - }, function () { - loginDialog.close(); - }); + .then( + /* onFulfilled */ () => { + loginDialog.displayConnectionStatus( + 'connection.GOT_SESSION_ID'); + loginDialog.close(); + }, + /* onRejected */ error => { + logger.error('authenticateAndUpgradeRole failed', error); + + const { authenticationError, connectionError } = error; + + if (authenticationError) { + loginDialog.displayError( + 'connection.GET_SESSION_ID_ERROR', + { msg: authenticationError }); + } else if (connectionError) { + loginDialog.displayError(connectionError); + } + }); + }, + /* cancelCallback */ () => loginDialog.close()); } /** diff --git a/modules/UI/authentication/LoginDialog.js b/modules/UI/authentication/LoginDialog.js index 1e1426214..63fabb327 100644 --- a/modules/UI/authentication/LoginDialog.js +++ b/modules/UI/authentication/LoginDialog.js @@ -1,4 +1,5 @@ /* global $, APP, config, JitsiMeetJS */ + import { toJid } from '../../../react/features/base/connection'; const ConnectionErrors = JitsiMeetJS.errors.connection; @@ -196,34 +197,38 @@ export default { }, /** - * Show notification that authentication is required - * to create the conference, so he should authenticate or wait for a host. - * @param {string} roomName name of the conference - * @param {function} onAuthNow callback to invoke if - * user want to authenticate. + * Shows a notification that authentication is required to create the + * conference, so the local participant should authenticate or wait for a + * host. + * + * @param {string} room - The name of the conference. + * @param {function} onAuthNow - The callback to invoke if the local + * participant wants to authenticate. * @returns dialog */ - showAuthRequiredDialog: function (roomName, onAuthNow) { - var msg = APP.translation.generateTranslationHTML( - "dialog.WaitForHostMsg", {room: roomName} + showAuthRequiredDialog(room, onAuthNow) { + const msg = APP.translation.generateTranslationHTML( + '[html]dialog.WaitForHostMsg', + { room } ); - - var buttonTxt = APP.translation.generateTranslationHTML( - "dialog.IamHost" + const buttonTxt = APP.translation.generateTranslationHTML( + 'dialog.IamHost' ); - var buttons = [{title: buttonTxt, value: "authNow"}]; + const buttons = [{ + title: buttonTxt, + value: 'authNow' + }]; return APP.UI.messageHandler.openDialog( - "dialog.WaitingForHost", + 'dialog.WaitingForHost', msg, true, buttons, - function (e, submitValue) { - - // Do not close the dialog yet + (e, submitValue) => { + // Do not close the dialog yet. e.preventDefault(); - // Open login popup + // Open login popup. if (submitValue === 'authNow') { onAuthNow(); } diff --git a/react/features/app/components/App.native.js b/react/features/app/components/App.native.js index 6a5ac264f..30d544a68 100644 --- a/react/features/app/components/App.native.js +++ b/react/features/app/components/App.native.js @@ -4,6 +4,7 @@ import React from 'react'; import { Linking } from 'react-native'; import '../../analytics'; +import '../../authentication'; import { Platform } from '../../base/react'; import '../../mobile/audio-mode'; import '../../mobile/background'; @@ -15,7 +16,6 @@ import '../../mobile/proximity'; import '../../mobile/wake-lock'; import { AbstractApp } from './AbstractApp'; -import '../../authentication'; /** * Root application component. diff --git a/react/features/authentication/actionTypes.js b/react/features/authentication/actionTypes.js index db93e681e..2d2aa9f18 100644 --- a/react/features/authentication/actionTypes.js +++ b/react/features/authentication/actionTypes.js @@ -28,48 +28,41 @@ export const CANCEL_WAIT_FOR_OWNER = Symbol('CANCEL_WAIT_FOR_OWNER'); */ export const STOP_WAIT_FOR_OWNER = Symbol('STOP_WAIT_FOR_OWNER'); +/** + * The type of (redux) action which informs that the authentication and role + * upgrade process has finished either with success or with a specific error. + * If error is undefined, then the process succeeded; + * otherwise, it failed. Refer to + * {@link JitsiConference#authenticateAndUpgradeRole} in lib-jitsi-meet for the + * error details. + * + * { + * type: UPGRADE_ROLE_FINISHED, + * error: Object + * } + */ +export const UPGRADE_ROLE_FINISHED = Symbol('UPGRADE_ROLE_FINISHED'); + /** * The type of (redux) action which signals that the process of authenticating - * and upgrading the current conference user's role has been started. + * and upgrading the local participant's role has been started. * * { * type: UPGRADE_ROLE_STARTED, - * authConnection: JitsiAuthConnection + * thenableWithCancel: Object * } */ export const UPGRADE_ROLE_STARTED = Symbol('UPGRADE_ROLE_STARTED'); -/** - * The type of (redux) action which informs that the authentication and role - * upgrade process has been completed successfully. - * - * { - * type: UPGRADE_ROLE_SUCCESS - * } - */ -export const UPGRADE_ROLE_SUCCESS = Symbol('UPGRADE_ROLE_SUCCESS'); - -/** - * The type of (redux) action which informs that the authentication and role - * upgrade process has failed with an error. Check the docs of - * {@link JitsiAuthConnection} for more details about the error structure. - * - * { - * type: UPGRADE_ROLE_SUCCESS, - * error: Object - * } - */ -export const UPGRADE_ROLE_FAILED = Symbol('UPGRADE_ROLE_FAILED'); - /** * The type of (redux) action that sets delayed handler which will check if * the conference has been created and it's now possible to join from anonymous * connection. * * { - * type: WAIT_FOR_OWNER, - * handler: Function, - * timeoutMs: number + * type: WAIT_FOR_OWNER, + * handler: Function, + * timeoutMs: number * } */ export const WAIT_FOR_OWNER = Symbol('WAIT_FOR_OWNER'); diff --git a/react/features/authentication/actions.js b/react/features/authentication/actions.js index 1f6f8bac1..694178378 100644 --- a/react/features/authentication/actions.js +++ b/react/features/authentication/actions.js @@ -1,53 +1,57 @@ -import { openDialog } from '../base/dialog/actions'; -import { checkIfCanJoin } from '../base/conference/actions'; +/* @flow */ + +import { checkIfCanJoin } from '../base/conference'; +import { openDialog } from '../base/dialog'; + import { CANCEL_LOGIN, CANCEL_WAIT_FOR_OWNER, STOP_WAIT_FOR_OWNER, - UPGRADE_ROLE_FAILED, + UPGRADE_ROLE_FINISHED, UPGRADE_ROLE_STARTED, - UPGRADE_ROLE_SUCCESS, WAIT_FOR_OWNER } from './actionTypes'; import { LoginDialog, WaitForOwnerDialog } from './components'; +const logger = require('jitsi-meet-logger').getLogger(__filename); + /** - * Instantiates new {@link JitsiAuthConnection} and uses it to authenticate and - * upgrade role of the current conference user to moderator which will allow to - * create and join new conference on XMPP password + guest access configuration. - * See {@link LoginDialog} description for more info. + * Initiates authenticating and upgrading the role of the local participant to + * moderator which will allow to create and join a new conference on an XMPP + * password + guest access configuration. Refer to {@link LoginDialog} for more + * info. * - * @param {string} id - XMPP user's id eg. user@domain.com. - * @param {string} userPassword - The user's password. - * @param {JitsiConference} conference - The conference for which user's role - * will be upgraded. - * @returns {function({dispatch: Function, getState: Function})} + * @param {string} id - The XMPP user's ID (e.g. user@domain.com). + * @param {string} password - The XMPP user's password. + * @param {JitsiConference} conference - The conference for which the local + * participant's role will be upgraded. + * @returns {function({ dispatch: Dispatch, getState: Function })} */ -export function authenticateAndUpgradeRole(id, userPassword, conference) { - return (dispatch, getState) => { - const authConnection = conference.createAuthenticationConnection(); - - dispatch(_upgradeRoleStarted(authConnection)); - +export function authenticateAndUpgradeRole( + id: string, + password: string, + conference: Object) { + return (dispatch: Dispatch, getState: Function) => { const { password: roomPassword } = getState()['features/base/conference']; + const process + = conference.authenticateAndUpgradeRole({ + id, + password, + roomPassword + }); - authConnection.authenticateAndUpgradeRole({ - id, - password: userPassword, - roomPassword - }) - .then(() => { - dispatch(_upgradeRoleSuccess()); - }) - .catch(error => { - // Lack of error means the operation was canceled, so no need to log - // that on error level. - if (error.error) { - console.error('upgradeRoleFailed', error); - } - dispatch(_upgradeRoleFailed(error)); - }); + dispatch(_upgradeRoleStarted(process)); + process.then( + /* onFulfilled */ () => dispatch(_upgradeRoleFinished()), + /* onRejected */ error => { + // The lack of an error signals a cancellation. + if (error.authenticationError || error.connectionError) { + logger.error('authenticateAndUpgradeRole failed', error); + } + + dispatch(_upgradeRoleFinished(error)); + }); }; } @@ -55,7 +59,7 @@ export function authenticateAndUpgradeRole(id, userPassword, conference) { * Cancels {@ink LoginDialog}. * * @returns {{ - * type: CANCEL_LOGIN + * type: CANCEL_LOGIN * }} */ export function cancelLogin() { @@ -68,7 +72,7 @@ export function cancelLogin() { * Cancels {@link WaitForOwnerDialog}. Will navigate back to the welcome page. * * @returns {{ - * type: CANCEL_WAIT_FOR_OWNER + * type: CANCEL_WAIT_FOR_OWNER * }} */ export function cancelWaitForOwner() { @@ -78,118 +82,77 @@ export function cancelWaitForOwner() { } /** - * Stops waiting for conference owner and clears any pending timeout. + * Opens {@link LoginDialog} which will ask to enter username and password + * for the current conference. + * + * @protected + * @returns {Action} + */ +export function _openLoginDialog() { + return openDialog(LoginDialog); +} + +/** + * Opens {@link WaitForOnwerDialog}. + * + * @protected + * @returns {Action} + */ +export function _openWaitForOwnerDialog() { + return openDialog(WaitForOwnerDialog); +} + +/** + * Stops waiting for the conference owner. * * @returns {{ - * type: STOP_WAIT_FOR_OWNER + * type: STOP_WAIT_FOR_OWNER * }} */ -export function clearWaitForOwnerTimeout() { +export function stopWaitForOwner() { return { type: STOP_WAIT_FOR_OWNER }; } /** - * Sets a delayed "wait for owner" handler function. - * - * @param {Function} handler - The "wait for owner" handler function. - * @param {number} waitMs - The delay in milliseconds. + * Signals that the process of authenticating and upgrading the local + * participant's role has finished either with success or with a specific error. * + * @param {Object} error - If undefined, then the process of + * authenticating and upgrading the local participant's role has succeeded; + * otherwise, it has failed with the specified error. Refer to + * {@link JitsiConference#authenticateAndUpgradeRole} in lib-jitsi-meet for the + * error details. * @private * @returns {{ - * type: WAIT_FOR_OWNER, - * handler: Function, - * timeoutMs: number + * type: UPGRADE_ROLE_FINISHED, + * error: Object * }} */ -function _setWaitForOwnerTimeout(handler, waitMs) { +function _upgradeRoleFinished(error) { return { - type: WAIT_FOR_OWNER, - handler, - timeoutMs: waitMs - }; -} - -/** - * Displays {@link LoginDialog} which will ask to enter username and password - * for the current conference. - * - * @protected - * @returns {{ - * type: OPEN_DIALOG, - * component: LoginDialog, - * props: React.PropTypes - * }} - */ -export function _showLoginDialog() { - return openDialog(LoginDialog, { }); -} - -/** - * Displays {@link WaitForOnwerDialog}. - * - * @protected - * @returns {{ - * type: OPEN_DIALOG, - * component: WaitForOwnerDialog, - * props: React.PropTypes - * }} - */ -export function _showWaitForOwnerDialog() { - return openDialog(WaitForOwnerDialog, { }); -} - -/** - * Emits an error which occurred during {@link authenticateAndUpgradeRole}. - * - * @param {Object} error - Check the docs of {@link JitsiAuthConnection} in - * lib-jitsi-meet for more details about the error's structure. - * - * @private - * @returns {{ - * type: UPGRADE_ROLE_FAILED, - * error: Object - * }} - */ -function _upgradeRoleFailed(error) { - return { - type: UPGRADE_ROLE_FAILED, + type: UPGRADE_ROLE_FINISHED, error }; } /** - * Signals that the role upgrade process has been started using given - * {@link JitsiAuthConnection} instance. - * - * @param {JitsiAuthConnection} authenticationConnection - The authentication - * connection instance that can be used to cancel the process. + * Signals that a process of authenticating and upgrading the local + * participant's role has started. * + * @param {Object} thenableWithCancel - The process of authenticating and + * upgrading the local participant's role. * @private * @returns {{ - * type: UPGRADE_ROLE_STARTED, - * authConnection: JitsiAuthConnection + * type: UPGRADE_ROLE_STARTED, + * thenableWithCancel: Object * }} */ -function _upgradeRoleStarted(authenticationConnection) { +function _upgradeRoleStarted(thenableWithCancel) { return { type: UPGRADE_ROLE_STARTED, - authConnection: authenticationConnection - }; -} - -/** - * Signals that the role upgrade process has been completed successfully. - * - * @private - * @returns {{ - * type: UPGRADE_ROLE_SUCCESS - * }} - */ -function _upgradeRoleSuccess() { - return { - type: UPGRADE_ROLE_SUCCESS + thenableWithCancel }; } @@ -198,13 +161,13 @@ function _upgradeRoleSuccess() { * start the process of "waiting for the owner" by periodically trying to join * the room every five seconds. * - * @returns {function({ dispatch: Function})} + * @returns {function({ dispatch: Dispatch })} */ export function waitForOwner() { - return dispatch => { - dispatch( - _setWaitForOwnerTimeout( - () => dispatch(checkIfCanJoin()), - 5000)); - }; + return (dispatch: Dispatch) => + dispatch({ + type: WAIT_FOR_OWNER, + handler: () => dispatch(checkIfCanJoin()), + timeoutMs: 5000 + }); } diff --git a/react/features/authentication/components/LoginDialog.native.js b/react/features/authentication/components/LoginDialog.native.js index 9a4f0652d..4252d0498 100644 --- a/react/features/authentication/components/LoginDialog.native.js +++ b/react/features/authentication/components/LoginDialog.native.js @@ -1,22 +1,14 @@ +import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import { Text, TextInput, View } from 'react-native'; import { connect as reduxConnect } from 'react-redux'; -import { - Button, - Modal, - Text, - TextInput, - View -} from 'react-native'; -import { - authenticateAndUpgradeRole, - cancelLogin -} from '../actions'; -import { - connect, - toJid -} from '../../base/connection'; + +import { connect, toJid } from '../../base/connection'; +import { Dialog } from '../../base/dialog'; import { translate } from '../../base/i18n'; import { JitsiConnectionErrors } from '../../base/lib-jitsi-meet'; + +import { authenticateAndUpgradeRole, cancelLogin } from '../actions'; import styles from './styles'; /** @@ -36,15 +28,15 @@ import styles from './styles'; * yet, Jicofo will not allow to start new conference. This will trigger * 'CONFERENCE_FAILED' action with JitsiConferenceErrors.AUTHENTICATION_REQUIRED * error and 'authRequired' value of 'features/base/conference' will hold - * the {@link JitsiConference} instance. If user decides to authenticate a new - * {@link JitsiAuthConnection} will be created from which separate XMPP - * connection is established and authentication is performed. In case it - * succeeds Jicofo will assign new session ID which then can be used from - * the anonymous domain connection to create and join the room. This part is - * done by {@link JitsiAuthConnection} from lib-jitsi-meet. + * the {@link JitsiConference} instance. If user decides to authenticate, a + * new/separate XMPP connection is established and authentication is performed. + * In case it succeeds, Jicofo will assign new session ID which then can be used + * from the anonymous domain connection to create and join the room. This part + * is done by {@link JitsiConference#authenticateAndUpgradeRole} in + * lib-jitsi-meet. * - * See https://github.com/jitsi/jicofo#secure-domain for configuration - * parameters description. + * See {@link https://github.com/jitsi/jicofo#secure-domain} for a description + * of the configuration parameters. */ class LoginDialog extends Component { /** @@ -57,37 +49,37 @@ class LoginDialog extends Component { * {@link JitsiConference} that needs authentication - will hold a valid * value in XMPP login + guest access mode. */ - conference: React.PropTypes.object, + _conference: PropTypes.object, /** * */ - configHosts: React.PropTypes.object, + _configHosts: PropTypes.object, /** * Indicates if the dialog should display "connecting" status message. */ - connecting: React.PropTypes.bool, - - /** - * Redux store dispatch method. - */ - dispatch: React.PropTypes.func, + _connecting: PropTypes.bool, /** * The error which occurred during login/authentication. */ - error: React.PropTypes.string, + _error: PropTypes.string, /** * Any extra details about the error provided by lib-jitsi-meet. */ - errorDetails: React.PropTypes.string, + _errorDetails: PropTypes.string, + + /** + * Redux store dispatch method. + */ + dispatch: PropTypes.func, /** * Invoked to obtain translated strings. */ - t: React.PropTypes.func + t: PropTypes.func }; /** @@ -99,16 +91,16 @@ class LoginDialog extends Component { constructor(props) { super(props); - // Bind event handlers so they are only bound once for every instance. - this._onCancel = this._onCancel.bind(this); - this._onLogin = this._onLogin.bind(this); - this._onUsernameChange = this._onUsernameChange.bind(this); - this._onPasswordChange = this._onPasswordChange.bind(this); - this.state = { username: '', password: '' }; + + // Bind event handlers so they are only bound once per instance. + this._onCancel = this._onCancel.bind(this); + this._onLogin = this._onLogin.bind(this); + this._onPasswordChange = this._onPasswordChange.bind(this); + this._onUsernameChange = this._onUsernameChange.bind(this); } /** @@ -119,56 +111,51 @@ class LoginDialog extends Component { */ render() { const { - error, - errorDetails, - connecting, + _connecting: connecting, + _error: error, + _errorDetails: errorDetails, t } = this.props; let messageKey = ''; - const messageOptions = { }; + const messageOptions = {}; if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) { messageKey = 'dialog.incorrectPassword'; } else if (error) { messageKey = 'dialog.connectErrorWithMsg'; - messageOptions.msg = `${error} ${errorDetails}`; } return ( - - - Username: + + - Password: - - {error ? t(messageKey, messageOptions) : ''} - {connecting && !error - ? t('connection.CONNECTING') : ''} + + { + error + ? t(messageKey, messageOptions) + : connecting + ? t('connection.CONNECTING') + : '' + } - ); } @@ -216,9 +203,9 @@ class LoginDialog extends Component { * @returns {void} */ _onLogin() { - const conference = this.props.conference; + const { _conference: conference } = this.props; const { username, password } = this.state; - const jid = toJid(username, this.props.configHosts); + const jid = toJid(username, this.props._configHosts); // If there's a conference it means that the connection has succeeded, // but authentication is required in order to join the room. @@ -238,42 +225,45 @@ class LoginDialog extends Component { * @param {Object} state - The Redux state. * @private * @returns {{ - * configHosts: Object, - * connecting: boolean, - * error: string, - * errorDetails: string, - * conference: JitsiConference + * _conference: JitsiConference, + * _configHosts: Object, + * _connecting: boolean, + * _error: string, + * _errorDetails: string * }} */ function _mapStateToProps(state) { + const { + upgradeRoleError, + upgradeRoleInProgress + } = state['features/authentication']; + const { authRequired } = state['features/base/conference']; const { hosts: configHosts } = state['features/base/config']; const { connecting, error: connectionError, errorMessage: connectionErrorMessage } = state['features/base/connection']; - const { - authRequired - } = state['features/base/conference']; - const { - upgradeRoleError, - upgradeRoleInProgress - } = state['features/authentication']; - const error - = connectionError - || (upgradeRoleError - && (upgradeRoleError.connectionError - || upgradeRoleError.authenticationError)); + let error; + let errorDetails; + + if (connectionError) { + error = connectionError; + errorDetails = connectionErrorMessage; + } else if (upgradeRoleError) { + error + = upgradeRoleError.connectionError + || upgradeRoleError.authenticationError; + errorDetails = upgradeRoleError.message; + } return { - configHosts, - connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress), - error, - errorDetails: - (connectionError && connectionErrorMessage) - || (upgradeRoleError && upgradeRoleError.message), - conference: authRequired + _conference: authRequired, + _configHosts: configHosts, + _connecting: Boolean(connecting) || Boolean(upgradeRoleInProgress), + _error: error, + _errorDetails: errorDetails }; } diff --git a/react/features/authentication/components/WaitForOwnerDialog.native.js b/react/features/authentication/components/WaitForOwnerDialog.native.js index 0fc62105a..a1fe6d9a1 100644 --- a/react/features/authentication/components/WaitForOwnerDialog.native.js +++ b/react/features/authentication/components/WaitForOwnerDialog.native.js @@ -1,9 +1,12 @@ +import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import { Text } from 'react-native'; import { connect } from 'react-redux'; -import { Button, Modal, Text, View } from 'react-native'; +import { Dialog } from '../../base/dialog'; import { translate } from '../../base/i18n'; -import { _showLoginDialog, cancelWaitForOwner } from '../actions'; + +import { cancelWaitForOwner, _openLoginDialog } from '../actions'; import styles from './styles'; /** @@ -19,20 +22,20 @@ class WaitForOwnerDialog extends Component { * @static */ static propTypes = { - /** - * Redux store dispatch function. - */ - dispatch: React.PropTypes.func, - /** * The name of the conference room (without the domain part). */ - roomName: React.PropTypes.string, + _room: PropTypes.string, + + /** + * Redux store dispatch function. + */ + dispatch: PropTypes.func, /** * Invoked to obtain translated strings. */ - t: React.PropTypes.func + t: PropTypes.func }; /** @@ -44,8 +47,9 @@ class WaitForOwnerDialog extends Component { constructor(props) { super(props); - this._onLogin = this._onLogin.bind(this); + // Bind event handlers so they are only bound once per instance. this._onCancel = this._onCancel.bind(this); + this._onLogin = this._onLogin.bind(this); } /** @@ -56,43 +60,25 @@ class WaitForOwnerDialog extends Component { */ render() { const { - roomName, + _room: room, t } = this.props; return ( - - - - { t( - 'dialog.WaitForHostMsg', - { room: roomName }) - } - -