jitsi-meet/react/features/welcome/components/AbstractWelcomePage.js
Lyubo Marinov a7ee632f43 [RN] LocalVideoTrackUnderlay
Implement a React Component which displays children as an overlay of
local video. The WelcomePage implemented such a component inside of it
among other WelcomePage-specific logic so I split
LocalVideoTrackUnderlay out of it. The new Component is used on the
BlankPage which may be displayed in the future not only when the
WelcomePage is disabled but also when there are long running network
requests, for example.
2017-09-05 17:45:20 -05:00

197 lines
5.3 KiB
JavaScript

import PropTypes from 'prop-types';
import { Component } from 'react';
import { appNavigate } from '../../app';
import { isRoomValid } from '../../base/conference';
import { generateRoomWithoutSeparator } from '../functions';
/**
* Base (abstract) class for container component rendering the welcome page.
*
* @abstract
*/
export class AbstractWelcomePage extends Component {
/**
* {@code AbstractWelcomePage}'s React {@code Component} prop types.
*
* @static
*/
static propTypes = {
_room: PropTypes.string,
dispatch: PropTypes.func
};
/**
* Initializes a new {@code AbstractWelcomePage} instance.
*
* @param {Object} props - The React {@code Component} props to initialize
* the new {@code AbstractWelcomePage} instance with.
*/
constructor(props) {
super(props);
/**
* Save room name into component's local state.
*
* @type {Object}
* @property {number|null} animateTimeoutId - Identifier of the letter
* animation timeout.
* @property {string} generatedRoomname - Automatically generated
* room name.
* @property {string} room - Room name.
* @property {string} roomPlaceholder - Room placeholder
* that's used as a placeholder for input.
* @property {nubmer|null} updateTimeoutId - Identifier of the timeout
* updating the generated room name.
*/
this.state = {
animateTimeoutId: null,
generatedRoomname: '',
room: '',
roomPlaceholder: '',
updateTimeoutId: null
};
// Bind event handlers so they are only bound once per instance.
this._animateRoomnameChanging
= this._animateRoomnameChanging.bind(this);
this._onJoin = this._onJoin.bind(this);
this._onRoomChange = this._onRoomChange.bind(this);
this._updateRoomname = this._updateRoomname.bind(this);
}
/**
* This method is executed when component receives new properties.
*
* @inheritdoc
* @param {Object} nextProps - New props component will receive.
*/
componentWillReceiveProps(nextProps) {
this.setState({ room: nextProps._room });
}
/**
* This method is executed when method will be unmounted from DOM.
*
* @inheritdoc
*/
componentWillUnmount() {
this._clearTimeouts();
}
/**
* Animates the changing of the room name.
*
* @param {string} word - The part of room name that should be added to
* placeholder.
* @private
* @returns {void}
*/
_animateRoomnameChanging(word) {
let animateTimeoutId = null;
const roomPlaceholder = this.state.roomPlaceholder + word.substr(0, 1);
if (word.length > 1) {
animateTimeoutId
= setTimeout(
() => {
this._animateRoomnameChanging(
word.substring(1, word.length));
},
70);
}
this.setState({
animateTimeoutId,
roomPlaceholder
});
}
/**
* Method that clears timeouts for animations and updates of room name.
*
* @private
* @returns {void}
*/
_clearTimeouts() {
clearTimeout(this.state.animateTimeoutId);
clearTimeout(this.state.updateTimeoutId);
}
/**
* Determines whether the 'Join' button is (to be) disabled i.e. there's no
* valid room name typed into the respective text input field.
*
* @protected
* @returns {boolean} If the 'Join' button is (to be) disabled, true;
* otherwise, false.
*/
_isJoinDisabled() {
return !isRoomValid(this.state.room);
}
/**
* Handles joining. Either by clicking on 'Join' button
* or by pressing 'Enter' in room name input field.
*
* @protected
* @returns {void}
*/
_onJoin() {
const room = this.state.room || this.state.generatedRoomname;
room && this.props.dispatch(appNavigate(room));
}
/**
* Handles 'change' event for the room name text input field.
*
* @param {string} value - The text typed into the respective text input
* field.
* @protected
* @returns {void}
*/
_onRoomChange(value) {
this.setState({ room: value });
}
/**
* Triggers the generation of a new room name and initiates an animation of
* its changing.
*
* @protected
* @returns {void}
*/
_updateRoomname() {
const generatedRoomname = generateRoomWithoutSeparator();
const roomPlaceholder = '';
const updateTimeoutId = setTimeout(this._updateRoomname, 10000);
this._clearTimeouts();
this.setState(
{
generatedRoomname,
roomPlaceholder,
updateTimeoutId
},
() => this._animateRoomnameChanging(generatedRoomname));
}
}
/**
* Maps (parts of) the redux state to the React {@code Component} props of
* {@code AbstractWelcomePage}.
*
* @param {Object} state - The redux state.
* @protected
* @returns {{
* _room: string
* }}
*/
export function _mapStateToProps(state) {
return {
_room: state['features/base/conference'].room
};
}