Comply w/ coding style

This commit is contained in:
Lyubomir Marinov 2017-02-18 18:42:11 -06:00
parent 92d0589a37
commit 538af01bf5
16 changed files with 413 additions and 315 deletions

View File

@ -21,6 +21,9 @@ import analytics from './modules/analytics/analytics';
import EventEmitter from "events"; import EventEmitter from "events";
import { conferenceFailed } from './react/features/base/conference'; import { conferenceFailed } from './react/features/base/conference';
import {
isFatalJitsiConnectionError
} from './react/features/base/lib-jitsi-meet';
import { import {
mediaPermissionPromptVisibilityChanged, mediaPermissionPromptVisibilityChanged,
suspendDetected suspendDetected
@ -475,21 +478,18 @@ function disconnect() {
/** /**
* Handles CONNECTION_FAILED events from lib-jitsi-meet. * Handles CONNECTION_FAILED events from lib-jitsi-meet.
* @param {JitsiMeetJS.connection.error} error the error reported. *
* @param {JitsiMeetJS.connection.error} error - The reported error.
* @returns {void} * @returns {void}
* @private * @private
*/ */
function _connectionFailedHandler (error) { function _connectionFailedHandler(error) {
switch (error) { if (isFatalJitsiConnectionError(error)) {
case ConnectionErrors.CONNECTION_DROPPED_ERROR: APP.connection.removeEventListener(
case ConnectionErrors.OTHER_ERROR: ConnectionEvents.CONNECTION_FAILED,
case ConnectionErrors.SERVER_ERROR: {
APP.connection.removeEventListener( ConnectionEvents.CONNECTION_FAILED,
_connectionFailedHandler); _connectionFailedHandler);
if (room) if (room)
room.leave(); room.leave();
break;
}
} }
} }

View File

@ -8,6 +8,9 @@ import {
connectionEstablished, connectionEstablished,
connectionFailed connectionFailed
} from './react/features/base/connection'; } from './react/features/base/connection';
import {
isFatalJitsiConnectionError
} from './react/features/base/lib-jitsi-meet';
const ConnectionEvents = JitsiMeetJS.events.connection; const ConnectionEvents = JitsiMeetJS.events.connection;
const ConnectionErrors = JitsiMeetJS.errors.connection; const ConnectionErrors = JitsiMeetJS.errors.connection;
@ -75,18 +78,13 @@ function connect(id, password, roomName) {
connection.addEventListener( connection.addEventListener(
ConnectionEvents.CONNECTION_FAILED, connectionFailedHandler); ConnectionEvents.CONNECTION_FAILED, connectionFailedHandler);
function connectionFailedHandler (error, errMsg) { function connectionFailedHandler(error, errMsg) {
APP.store.dispatch(connectionFailed(connection, error, errMsg)); APP.store.dispatch(connectionFailed(connection, error, errMsg));
switch (error) { if (isFatalJitsiConnectionError(error)) {
case ConnectionErrors.CONNECTION_DROPPED_ERROR:
case ConnectionErrors.OTHER_ERROR:
case ConnectionErrors.SERVER_ERROR: {
connection.removeEventListener( connection.removeEventListener(
ConnectionEvents.CONNECTION_FAILED, ConnectionEvents.CONNECTION_FAILED,
connectionFailedHandler); connectionFailedHandler);
break;
}
} }
} }

View File

@ -1,6 +1,7 @@
/* global APP, JitsiMeetJS, loggingConfig */ /* global APP, loggingConfig */
import { isRoomValid } from '../base/conference'; import { isRoomValid } from '../base/conference';
import JitsiMeetJS from '../base/lib-jitsi-meet';
import { RouteRegistry } from '../base/react'; import { RouteRegistry } from '../base/react';
import { interceptComponent } from '../base/util'; import { interceptComponent } from '../base/util';
import { Conference } from '../conference'; import { Conference } from '../conference';

View File

@ -1,5 +1,31 @@
import { loadScript } from '../../base/util'; import { loadScript } from '../../base/util';
import JitsiMeetJS from './_';
declare var APP: Object;
const JitsiConnectionErrors = JitsiMeetJS.errors.connection;
/**
* Determines whether a specific JitsiConnectionErrors instance indicates a
* fatal JitsiConnection error.
*
* FIXME Figure out the category of errors defined by the fucntion and describe
* that category. I've currently named the category fatal because it appears to
* be used in the cases of unrecoverable errors that necessitate a reload.
*
* @param {string} error - The JitsiConnectionErrors instance to
* categorize/classify.
* @returns {boolean} True if the specified JitsiConnectionErrors instance
* indicates a fatal JitsiConnection error; otherwise, false.
*/
export function isFatalJitsiConnectionError(error: string) {
return (
error === JitsiConnectionErrors.CONNECTION_DROPPED_ERROR
|| error === JitsiConnectionErrors.OTHER_ERROR
|| error === JitsiConnectionErrors.SERVER_ERROR);
}
/** /**
* Loads config.js file from remote server. * Loads config.js file from remote server.
* *
@ -7,7 +33,7 @@ import { loadScript } from '../../base/util';
* @param {string} path='/config.js' - Relative pah to config.js file. * @param {string} path='/config.js' - Relative pah to config.js file.
* @returns {Promise<Object>} * @returns {Promise<Object>}
*/ */
export function loadConfig(host, path = '/config.js') { export function loadConfig(host: string, path: string = '/config.js') {
// Returns config.js file from global scope. We can't use the version that's // Returns config.js file from global scope. We can't use the version that's
// being used for the React Native app because the old/current Web app uses // being used for the React Native app because the old/current Web app uses
// config from the global scope. // config from the global scope.

View File

@ -1,3 +1,4 @@
export * from './interceptComponent'; export * from './interceptComponent';
export * from './loadScript'; export * from './loadScript';
export * from './randomUtil';
export * from './roomnameGenerator'; export * from './roomnameGenerator';

View File

@ -6,7 +6,6 @@ import { connect as reactReduxConnect } from 'react-redux';
import { connect, disconnect } from '../../base/connection'; import { connect, disconnect } from '../../base/connection';
import { Watermarks } from '../../base/react'; import { Watermarks } from '../../base/react';
import { FeedbackButton } from '../../feedback'; import { FeedbackButton } from '../../feedback';
import { OverlayContainer } from '../../overlay'; import { OverlayContainer } from '../../overlay';
/** /**
@ -164,6 +163,7 @@ class Conference extends Component {
</div> </div>
</div> </div>
</div> </div>
<OverlayContainer /> <OverlayContainer />
</div> </div>
); );

View File

@ -1,15 +1,5 @@
import { Symbol } from '../base/react'; import { Symbol } from '../base/react';
/**
* The type of the Redux action which signals that a suspend was detected.
*
* {
* type: SUSPEND_DETECTED
* }
* @public
*/
export const SUSPEND_DETECTED = Symbol('SUSPEND_DETECTED');
/** /**
* The type of the Redux action which signals that the prompt for media * The type of the Redux action which signals that the prompt for media
* permission is visible or not. * permission is visible or not.
@ -23,3 +13,13 @@ export const SUSPEND_DETECTED = Symbol('SUSPEND_DETECTED');
*/ */
export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
= Symbol('MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED'); = Symbol('MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED');
/**
* The type of the Redux action which signals that a suspend was detected.
*
* {
* type: SUSPEND_DETECTED
* }
* @public
*/
export const SUSPEND_DETECTED = Symbol('SUSPEND_DETECTED');

View File

@ -1,8 +1,28 @@
import { import {
SUSPEND_DETECTED, MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED SUSPEND_DETECTED
} from './actionTypes'; } from './actionTypes';
import './reducer';
/**
* Signals that the prompt for media permission is visible or not.
*
* @param {boolean} isVisible - If the value is true - the prompt for media
* permission is visible otherwise the value is false/undefined.
* @param {string} browser - The name of the current browser.
* @returns {{
* type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
* browser: {string},
* isVisible: {boolean}
* }}
* @public
*/
export function mediaPermissionPromptVisibilityChanged(isVisible, browser) {
return {
type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
browser,
isVisible
};
}
/** /**
* Signals that suspend was detected. * Signals that suspend was detected.
@ -17,24 +37,3 @@ export function suspendDetected() {
type: SUSPEND_DETECTED type: SUSPEND_DETECTED
}; };
} }
/**
* Signals that the prompt for media permission is visible or not.
*
* @param {boolean} isVisible - If the value is true - the prompt for media
* permission is visible otherwise the value is false/undefined.
* @param {string} browser - The name of the current browser.
* @returns {{
* type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
* isVisible: {boolean},
* browser: {string}
* }}
* @public
*/
export function mediaPermissionPromptVisibilityChanged(isVisible, browser) {
return {
type: MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
isVisible,
browser
};
}

View File

@ -3,8 +3,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
/** /**
* Implements an abstract React Component for overlay - the components which * Implements an abstract React Component for overlay - the components which are
* are displayed on top of the application covering the whole screen. * displayed on top of the application covering the whole screen.
* *
* @abstract * @abstract
*/ */
@ -21,25 +21,15 @@ export default class AbstractOverlay extends Component {
this.state = { this.state = {
/** /**
* Indicates the css style of the overlay. if true - lighter and * Indicates the CSS style of the overlay. If true, then ighter;
* darker otherwise. * darker, otherwise.
*
* @type {boolean} * @type {boolean}
*/ */
isLightOverlay: false isLightOverlay: false
}; };
} }
/**
* Abstract method which should be used by subclasses to provide the overlay
* content.
*
* @returns {ReactElement|null}
* @protected
*/
_renderOverlayContent() {
return null;
}
/** /**
* This method is executed when comonent is mounted. * This method is executed when comonent is mounted.
* *
@ -51,6 +41,31 @@ export default class AbstractOverlay extends Component {
APP.translation.translateElement($('#overlay')); APP.translation.translateElement($('#overlay'));
} }
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement|null}
*/
render() {
const containerClass
= this.state.isLightOverlay
? 'overlay__container-light'
: 'overlay__container';
return (
<div
className = { containerClass }
id = 'overlay'>
<div className = 'overlay__content'>
{
this._renderOverlayContent()
}
</div>
</div>
);
}
/** /**
* Reloads the page. * Reloads the page.
* *
@ -64,23 +79,13 @@ export default class AbstractOverlay extends Component {
} }
/** /**
* Implements React's {@link Component#render()}. * Abstract method which should be used by subclasses to provide the overlay
* content.
* *
* @inheritdoc
* @returns {ReactElement|null} * @returns {ReactElement|null}
* @protected
*/ */
render() { _renderOverlayContent() {
const containerClass = this.state.isLightOverlay return null;
? 'overlay__container-light' : 'overlay__container';
return (
<div
className = { containerClass }
id = 'overlay'>
<div className = 'overlay__content'>
{ this._renderOverlayContent() }
</div>
</div>
);
} }
} }

View File

@ -20,16 +20,20 @@ class OverlayContainer extends Component {
static propTypes = { static propTypes = {
/** /**
* The browser which is used currently. * The browser which is used currently.
*
* NOTE: Used by UserMediaPermissionsOverlay only. * NOTE: Used by UserMediaPermissionsOverlay only.
*
* @private * @private
* @type {string} * @type {string}
*/ */
_browser: React.PropTypes.string, _browser: React.PropTypes.string,
/** /**
* The indicator which determines whether the status of * The indicator which determines whether the status of the
* JitsiConnection object has been "established" or not. * JitsiConnection object has been "established" or not.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
@ -38,7 +42,9 @@ class OverlayContainer extends Component {
/** /**
* The indicator which determines whether a critical error for reload * The indicator which determines whether a critical error for reload
* has been received. * has been received.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
@ -47,16 +53,20 @@ class OverlayContainer extends Component {
/** /**
* The indicator which determines whether the reload was caused by * The indicator which determines whether the reload was caused by
* network failure. * network failure.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
_isNetworkFailure: React.PropTypes.bool, _isNetworkFailure: React.PropTypes.bool,
/** /**
* The indicator which determines whether the GUM permissions prompt * The indicator which determines whether the GUM permissions prompt is
* is displayed or not. * displayed or not.
*
* NOTE: Used by UserMediaPermissionsOverlay only. * NOTE: Used by UserMediaPermissionsOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
@ -64,16 +74,20 @@ class OverlayContainer extends Component {
/** /**
* The reason for the error that will cause the reload. * The reason for the error that will cause the reload.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {string} * @type {string}
*/ */
_reason: React.PropTypes.string, _reason: React.PropTypes.string,
/** /**
* The indicator which determines whether the GUM permissions prompt * The indicator which determines whether the GUM permissions prompt is
* is displayed or not. * displayed or not.
*
* NOTE: Used by SuspendedOverlay only. * NOTE: Used by SuspendedOverlay only.
*
* @private * @private
* @type {string} * @type {string}
*/ */
@ -91,8 +105,8 @@ class OverlayContainer extends Component {
// FIXME: Temporary workaround until everything is moved to react. // FIXME: Temporary workaround until everything is moved to react.
APP.UI.overlayVisible APP.UI.overlayVisible
= (this.props._connectionEstablished && this.props._haveToReload) = (this.props._connectionEstablished && this.props._haveToReload)
|| this.props._suspendDetected || this.props._suspendDetected
|| this.props._mediaPermissionPromptVisible; || this.props._mediaPermissionPromptVisible;
} }
/** /**
@ -133,80 +147,95 @@ class OverlayContainer extends Component {
* *
* @param {Object} state - The Redux state. * @param {Object} state - The Redux state.
* @returns {{ * @returns {{
* _browser: string, * _browser: string,
* _connectionEstablished: bool, * _connectionEstablished: bool,
* _haveToReload: bool, * _haveToReload: bool,
* _isNetworkFailure: bool, * _isNetworkFailure: bool,
* _mediaPermissionPromptVisible: bool, * _mediaPermissionPromptVisible: bool,
* _reason: string, * _reason: string,
* _suspendDetected: bool * _suspendDetected: bool
* }} * }}
* @private * @private
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state) {
const stateFeaturesOverlay = state['features/overlay'];
return { return {
/** /**
* The browser which is used currently. * The browser which is used currently.
*
* NOTE: Used by UserMediaPermissionsOverlay only. * NOTE: Used by UserMediaPermissionsOverlay only.
*
* @private * @private
* @type {string} * @type {string}
*/ */
_browser: state['features/overlay'].browser, _browser: stateFeaturesOverlay.browser,
/** /**
* The indicator which determines whether the status of * The indicator which determines whether the status of the
* JitsiConnection object has been "established" or not. * JitsiConnection object has been "established" or not.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
_connectionEstablished: _connectionEstablished: stateFeaturesOverlay.connectionEstablished,
state['features/overlay'].connectionEstablished,
/** /**
* The indicator which determines whether a critical error for reload * The indicator which determines whether a critical error for reload
* has been received. * has been received.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
_haveToReload: state['features/overlay'].haveToReload, _haveToReload: stateFeaturesOverlay.haveToReload,
/** /**
* The indicator which determines whether the reload was caused by * The indicator which determines whether the reload was caused by
* network failure. * network failure.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
_isNetworkFailure: state['features/overlay'].isNetworkFailure, _isNetworkFailure: stateFeaturesOverlay.isNetworkFailure,
/** /**
* The indicator which determines whether the GUM permissions prompt * The indicator which determines whether the GUM permissions prompt is
* is displayed or not. * displayed or not.
*
* NOTE: Used by UserMediaPermissionsOverlay only. * NOTE: Used by UserMediaPermissionsOverlay only.
*
* @private * @private
* @type {boolean} * @type {boolean}
*/ */
_mediaPermissionPromptVisible: _mediaPermissionPromptVisible:
state['features/overlay'].mediaPermissionPromptVisible, stateFeaturesOverlay.mediaPermissionPromptVisible,
/** /**
* The reason for the error that will cause the reload. * The reason for the error that will cause the reload.
*
* NOTE: Used by PageReloadOverlay only. * NOTE: Used by PageReloadOverlay only.
*
* @private * @private
* @type {string} * @type {string}
*/ */
_reason: state['features/overlay'].reason, _reason: stateFeaturesOverlay.reason,
/** /**
* The indicator which determines whether the GUM permissions prompt * The indicator which determines whether the GUM permissions prompt is
* is displayed or not. * displayed or not.
*
* NOTE: Used by SuspendedOverlay only. * NOTE: Used by SuspendedOverlay only.
*
* @private * @private
* @type {string} * @type {string}
*/ */
_suspendDetected: state['features/overlay'].suspendDetected _suspendDetected: stateFeaturesOverlay.suspendDetected
}; };
} }

View File

@ -1,141 +1,18 @@
/* global APP, AJS */ import React from 'react';
import React, { Component } from 'react'; import { randomInt } from '../../base/util';
import { randomInt } from '../../base/util/randomUtil';
import AbstractOverlay from './AbstractOverlay'; import AbstractOverlay from './AbstractOverlay';
import ReloadTimer from './ReloadTimer';
declare var APP: Object;
const logger = require('jitsi-meet-logger').getLogger(__filename); const logger = require('jitsi-meet-logger').getLogger(__filename);
/** /**
* Implements a React Component for the reload timer. Starts counter from * Implements a React Component for page reload overlay. Shown before the
* props.start, adds props.step to the current value on every props.interval * conference is reloaded. Shows a warning message and counts down towards the
* seconds until the current value reaches props.end. Also displays progress * reload.
* bar.
*/
class ReloadTimer extends Component {
/**
* ReloadTimer component's property types.
*
* @static
*/
static propTypes = {
/**
* The end of the timer. When this.state.current reaches this
* value the timer will stop and call onFinish function.
* @public
* @type {number}
*/
end: React.PropTypes.number,
/**
* The interval in sec for adding this.state.step to this.state.current
* @public
* @type {number}
*/
interval: React.PropTypes.number,
/**
* The function that will be executed when timer finish (when
* this.state.current === this.props.end)
*/
onFinish: React.PropTypes.func,
/**
* The start of the timer. The initial value for this.state.current.
* @public
* @type {number}
*/
start: React.PropTypes.number,
/**
* The value which will be added to this.state.current on every step.
* @public
* @type {number}
*/
step: React.PropTypes.number
}
/**
* Initializes a new ReloadTimer instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
* @public
*/
constructor(props) {
super(props);
this.state = {
current: this.props.start,
time: Math.abs(this.props.end - this.props.start)
};
}
/**
* React Component method that executes once component is mounted.
*
* @inheritdoc
* @returns {void}
* @protected
*/
componentDidMount() {
AJS.progressBars.update('#reloadProgressBar', 0);
const intervalId = setInterval(() => {
if (this.state.current === this.props.end) {
clearInterval(intervalId);
this.props.onFinish();
return;
}
this.setState((prevState, props) => {
return { current: prevState.current + props.step };
});
}, Math.abs(this.props.interval) * 1000);
}
/**
* React Component method that executes once component is updated.
*
* @inheritdoc
* @returns {void}
* @protected
*/
componentDidUpdate() {
AJS.progressBars.update('#reloadProgressBar',
Math.abs(this.state.current - this.props.start) / this.state.time);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement|null}
* @public
*/
render() {
return (
<div>
<div
className = 'aui-progress-indicator'
id = 'reloadProgressBar'>
<span className = 'aui-progress-indicator-value' />
</div>
<span
className = 'reload_overlay_text'
id = 'reloadSeconds'>
{ this.state.current }
<span data-i18n = 'dialog.conferenceReloadTimeLeft' />
</span>
</div>
);
}
}
/**
* Implements a React Component for page reload overlay. Shown before
* the conference is reloaded. Shows a warning message and counts down towards
* the reload.
*/ */
export default class PageReloadOverlay extends AbstractOverlay { export default class PageReloadOverlay extends AbstractOverlay {
/** /**
@ -172,8 +49,8 @@ export default class PageReloadOverlay extends AbstractOverlay {
super(props); super(props);
/** /**
* How long the overlay dialog will be * How long the overlay dialog will be displayed, before the conference
* displayed, before the conference will be reloaded. * will be reloaded.
* @type {number} * @type {number}
*/ */
const timeoutSeconds = 10 + randomInt(0, 20); const timeoutSeconds = 10 + randomInt(0, 20);
@ -194,33 +71,59 @@ export default class PageReloadOverlay extends AbstractOverlay {
...this.state, ...this.state,
/** /**
* Indicates the css style of the overlay. if true - lighter and * Indicates the css style of the overlay. If true, then lighter;
* darker otherwise. * darker, otherwise.
*
* @type {boolean} * @type {boolean}
*/ */
isLightOverlay, isLightOverlay,
/** /**
* The translation key for the title of the overlay * The translation key for the title of the overlay.
*
* @type {string} * @type {string}
*/ */
message, message,
/** /**
* How long the overlay dialog will be * How long the overlay dialog will be displayed before the
* displayed, before the conference will be reloaded. * conference will be reloaded.
*
* @type {number} * @type {number}
*/ */
timeoutSeconds, timeoutSeconds,
/** /**
* The translation key for the title of the overlay * The translation key for the title of the overlay.
*
* @type {string} * @type {string}
*/ */
title title
}; };
} }
/**
* This method is executed when comonent is mounted.
*
* @inheritdoc
* @returns {void}
*/
componentDidMount() {
super.componentDidMount();
// FIXME (CallStats - issue) This event will not make it to CallStats
// because the log queue is not flushed before "fabric terminated" is
// sent to the backed.
// FIXME: We should dispatch action for this.
APP.conference.logEvent(
'page.reload',
/* value */ undefined,
/* label */ this.props.reason);
logger.info(
'The conference will be reloaded after '
+ `${this.state.timeoutSeconds} seconds.`);
}
/** /**
* Renders the button for relaod the page if necessary. * Renders the button for relaod the page if necessary.
* *
@ -229,18 +132,21 @@ export default class PageReloadOverlay extends AbstractOverlay {
*/ */
_renderButton() { _renderButton() {
if (this.props.isNetworkFailure) { if (this.props.isNetworkFailure) {
const cName = 'button-control button-control_primary ' const className
+ 'button-control_center'; = 'button-control button-control_primary button-control_center';
/* eslint-disable react/jsx-handler-names */ /* eslint-disable react/jsx-handler-names */
return ( return (
<button <button
className = { cName } className = { className }
data-i18n = 'dialog.reconnectNow' data-i18n = 'dialog.reconnectNow'
id = 'reconnectNow' id = 'reconnectNow'
onClick = { this._reconnectNow } /> onClick = { this._reconnectNow } />
); );
/* eslint-enable react/jsx-handler-names */
} }
return null; return null;
@ -275,24 +181,7 @@ export default class PageReloadOverlay extends AbstractOverlay {
{ this._renderButton() } { this._renderButton() }
</div> </div>
); );
}
/** /* eslint-enable react/jsx-handler-names */
* This method is executed when comonent is mounted.
*
* @inheritdoc
* @returns {void}
*/
componentDidMount() {
super.componentDidMount();
// FIXME (CallStats - issue) this event will not make it to
// the CallStats, because the log queue is not flushed, before
// "fabric terminated" is sent to the backed
// FIXME: We should dispatch action for this
APP.conference.logEvent('page.reload', undefined /* value */,
this.props.reason /* label */);
logger.info(`The conference will be reloaded after
${this.state.timeoutSeconds} seconds.`);
} }
} }

View File

@ -0,0 +1,141 @@
import React, { Component } from 'react';
declare var AJS: Object;
/**
* Implements a React Component for the reload timer. Starts counter from
* props.start, adds props.step to the current value on every props.interval
* seconds until the current value reaches props.end. Also displays progress
* bar.
*/
export default class ReloadTimer extends Component {
/**
* ReloadTimer component's property types.
*
* @static
*/
static propTypes = {
/**
* The end of the timer. When this.state.current reaches this value the
* timer will stop and call onFinish function.
*
* @public
* @type {number}
*/
end: React.PropTypes.number,
/**
* The interval in sec for adding this.state.step to this.state.current.
*
* @public
* @type {number}
*/
interval: React.PropTypes.number,
/**
* The function that will be executed when timer finish (when
* this.state.current === this.props.end)
*/
onFinish: React.PropTypes.func,
/**
* The start of the timer. The initial value for this.state.current.
*
* @public
* @type {number}
*/
start: React.PropTypes.number,
/**
* The value which will be added to this.state.current on every step.
*
* @public
* @type {number}
*/
step: React.PropTypes.number
}
/**
* Initializes a new ReloadTimer instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
* @public
*/
constructor(props) {
super(props);
this.state = {
current: this.props.start,
time: Math.abs(this.props.end - this.props.start)
};
}
/**
* React Component method that executes once component is mounted.
*
* @inheritdoc
* @returns {void}
* @protected
*/
componentDidMount() {
AJS.progressBars.update('#reloadProgressBar', 0);
const intervalId
= setInterval(
() => {
if (this.state.current === this.props.end) {
clearInterval(intervalId);
this.props.onFinish();
} else {
this.setState((prevState, props) => {
return {
current: prevState.current + props.step
};
});
}
},
Math.abs(this.props.interval) * 1000);
}
/**
* React Component method that executes once component is updated.
*
* @inheritdoc
* @returns {void}
* @protected
*/
componentDidUpdate() {
AJS.progressBars.update(
'#reloadProgressBar',
Math.abs(this.state.current - this.props.start)
/ this.state.time);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement|null}
* @public
*/
render() {
return (
<div>
<div
className = 'aui-progress-indicator'
id = 'reloadProgressBar'>
<span className = 'aui-progress-indicator-value' />
</div>
<span
className = 'reload_overlay_text'
id = 'reloadSeconds'>
{
this.state.current
}
<span data-i18n = 'dialog.conferenceReloadTimeLeft' />
</span>
</div>
);
}
}

View File

@ -3,8 +3,8 @@ import React from 'react';
import AbstractOverlay from './AbstractOverlay'; import AbstractOverlay from './AbstractOverlay';
/** /**
* Implements a React Component for suspended overlay. Shown when suspended * Implements a React Component for suspended overlay. Shown when a suspend is
* is detected. * detected.
*/ */
export default class SuspendedOverlay extends AbstractOverlay { export default class SuspendedOverlay extends AbstractOverlay {
/** /**
@ -33,5 +33,7 @@ export default class SuspendedOverlay extends AbstractOverlay {
onClick = { this._reconnectNow } /> onClick = { this._reconnectNow } />
</div> </div>
); );
/* eslint-enable react/jsx-handler-names */
} }
} }

View File

@ -18,6 +18,7 @@ export default class UserMediaPermissionsOverlay extends AbstractOverlay {
/** /**
* The browser which is used currently. The text is different for every * The browser which is used currently. The text is different for every
* browser. * browser.
*
* @public * @public
* @type {string} * @type {string}
*/ */
@ -37,6 +38,7 @@ export default class UserMediaPermissionsOverlay extends AbstractOverlay {
this.state = { this.state = {
/** /**
* The src value of the image for the policy logo. * The src value of the image for the policy logo.
*
* @type {string} * @type {string}
*/ */
policyLogoSrc: interfaceConfig.POLICY_LOGO policyLogoSrc: interfaceConfig.POLICY_LOGO
@ -72,7 +74,9 @@ export default class UserMediaPermissionsOverlay extends AbstractOverlay {
<p <p
className = 'policy__text' className = 'policy__text'
data-i18n = '[html]startupoverlay.policyText' /> data-i18n = '[html]startupoverlay.policyText' />
{ this._renderPolicyLogo() } {
this._renderPolicyLogo()
}
</div> </div>
</div> </div>
); );
@ -85,10 +89,12 @@ export default class UserMediaPermissionsOverlay extends AbstractOverlay {
* @private * @private
*/ */
_renderPolicyLogo() { _renderPolicyLogo() {
if (this.state.policyLogoSrc) { const { policyLogoSrc } = this.state;
if (policyLogoSrc) {
return ( return (
<div className = 'policy__logo'> <div className = 'policy__logo'>
<img src = { this.state.policyLogoSrc } /> <img src = { policyLogoSrc } />
</div> </div>
); );
} }

View File

@ -1,2 +1,4 @@
export * from './components';
export * from './actions'; export * from './actions';
export * from './components';
import './reducer';

View File

@ -1,14 +1,15 @@
/* global JitsiMeetJS */
import { CONFERENCE_FAILED } from '../base/conference'; import { CONFERENCE_FAILED } from '../base/conference';
import { import {
CONNECTION_ESTABLISHED, CONNECTION_ESTABLISHED,
CONNECTION_FAILED CONNECTION_FAILED
} from '../base/connection'; } from '../base/connection';
import JitsiMeetJS, {
isFatalJitsiConnectionError
} from '../base/lib-jitsi-meet';
import { import {
ReducerRegistry, ReducerRegistry,
setStateProperty, setStateProperties,
setStateProperties setStateProperty
} from '../base/redux'; } from '../base/redux';
import { import {
@ -16,6 +17,8 @@ import {
SUSPEND_DETECTED SUSPEND_DETECTED
} from './actionTypes'; } from './actionTypes';
const JitsiConferenceErrors = JitsiMeetJS.errors.conference;
const JitsiConnectionErrors = JitsiMeetJS.errors.connection;
const logger = require('jitsi-meet-logger').getLogger(__filename); const logger = require('jitsi-meet-logger').getLogger(__filename);
/** /**
@ -43,20 +46,19 @@ ReducerRegistry.register('features/overlay', (state = {}, action) => {
}); });
/** /**
* Reduces a specific Redux action CONFERENCE_FAILED of the feature * Reduces a specific Redux action CONFERENCE_FAILED of the feature overlay.
* overlay.
* *
* @param {Object} state - The Redux state of the feature overlay. * @param {Object} state - The Redux state of the feature overlay.
* @param {Action} action - The Redux action CONFERENCE_FAILED to reduce. * @param {Action} action - The Redux action CONFERENCE_FAILED to reduce.
* @returns {Object} The new state of the feature base/connection after the * @returns {Object} The new state of the feature overlay after the reduction of
* reduction of the specified action. * the specified action.
* @private * @private
*/ */
function _conferenceFailed(state, action) { function _conferenceFailed(state, action) {
const ConferenceErrors = JitsiMeetJS.errors.conference; const error = action.error;
if (action.error === ConferenceErrors.FOCUS_LEFT if (error === JitsiConferenceErrors.FOCUS_LEFT
|| action.error === ConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE) { || error === JitsiConferenceErrors.VIDEOBRIDGE_NOT_AVAILABLE) {
return setStateProperties(state, { return setStateProperties(state, {
haveToReload: true, haveToReload: true,
isNetworkFailure: false, isNetworkFailure: false,
@ -72,8 +74,8 @@ function _conferenceFailed(state, action) {
* overlay. * overlay.
* *
* @param {Object} state - The Redux state of the feature overlay. * @param {Object} state - The Redux state of the feature overlay.
* @returns {Object} The new state of the feature overlay after the * @returns {Object} The new state of the feature overlay after the reduction of
* reduction of the specified action. * the specified action.
* @private * @private
*/ */
function _connectionEstablished(state) { function _connectionEstablished(state) {
@ -81,63 +83,60 @@ function _connectionEstablished(state) {
} }
/** /**
* Reduces a specific Redux action CONNECTION_FAILED of the feature * Reduces a specific Redux action CONNECTION_FAILED of the feature overlay.
* overlay.
* *
* @param {Object} state - The Redux state of the feature overlay. * @param {Object} state - The Redux state of the feature overlay.
* @param {Action} action - The Redux action CONNECTION_FAILED to reduce. * @param {Action} action - The Redux action CONNECTION_FAILED to reduce.
* @returns {Object} The new state of the feature overlay after the * @returns {Object} The new state of the feature overlay after the reduction of
* reduction of the specified action. * the specified action.
* @private * @private
*/ */
function _connectionFailed(state, action) { function _connectionFailed(state, action) {
const ConnectionErrors = JitsiMeetJS.errors.connection; const error = action.error;
switch (action.error) { if (isFatalJitsiConnectionError(error)) {
case ConnectionErrors.CONNECTION_DROPPED_ERROR: const errorMessage = action.errorMessage;
case ConnectionErrors.OTHER_ERROR:
case ConnectionErrors.SERVER_ERROR: { logger.error(`XMPP connection error: ${errorMessage}`);
logger.error(`XMPP connection error: ${action.errorMessage}`);
// From all of the cases above only CONNECTION_DROPPED_ERROR
// is considered a network type of failure
return setStateProperties(state, { return setStateProperties(state, {
haveToReload: true, haveToReload: true,
// From all of the cases above only CONNECTION_DROPPED_ERROR is
// considered a network type of failure.
isNetworkFailure: isNetworkFailure:
action.error === ConnectionErrors.CONNECTION_DROPPED_ERROR, error === JitsiConnectionErrors.CONNECTION_DROPPED_ERROR,
reason: `xmpp-conn-dropped: ${action.errorMessage}` reason: `xmpp-conn-dropped: ${errorMessage}`
}); });
} }
}
return state; return state;
} }
/** /**
* Reduces a specific Redux action MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED * Reduces a specific Redux action MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED of
* of the feature overlay. * the feature overlay.
* *
* @param {Object} state - The Redux state of the feature overlay. * @param {Object} state - The Redux state of the feature overlay.
* @param {Action} action - The Redux action to reduce. * @param {Action} action - The Redux action to reduce.
* @returns {Object} The new state of the feature overlay after the * @returns {Object} The new state of the feature overlay after the reduction of
* reduction of the specified action. * the specified action.
* @private * @private
*/ */
function _mediaPermissionPromptVisibilityChanged(state, action) { function _mediaPermissionPromptVisibilityChanged(state, action) {
return setStateProperties(state, { return setStateProperties(state, {
mediaPermissionPromptVisible: action.isVisible, browser: action.browser,
browser: action.browser mediaPermissionPromptVisible: action.isVisible
}); });
} }
/** /**
* Reduces a specific Redux action SUSPEND_DETECTED of the feature * Reduces a specific Redux action SUSPEND_DETECTED of the feature overlay.
* overlay.
* *
* @param {Object} state - The Redux state of the feature overlay. * @param {Object} state - The Redux state of the feature overlay.
* @returns {Object} The new state of the feature overlay after the * @returns {Object} The new state of the feature overlay after the reduction of
* reduction of the specified action. * the specified action.
* @private * @private
*/ */
function _suspendDetected(state) { function _suspendDetected(state) {