Clean up routing logic

This commit is contained in:
Ilya Daynatovich 2017-01-18 14:21:30 +02:00 committed by Lyubomir Marinov
parent 62bafcaf63
commit 57ba702dda
5 changed files with 81 additions and 58 deletions

View File

@ -1,16 +1,24 @@
import { setRoom } from '../base/conference'; import { setRoom } from '../base/conference';
import { getDomain, setDomain } from '../base/connection'; import { getDomain, setDomain } from '../base/connection';
import { loadConfig, setConfig } from '../base/lib-jitsi-meet'; import { loadConfig, setConfig } from '../base/lib-jitsi-meet';
import { Platform } from '../base/react';
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes'; import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
import { import {
_getRoomAndDomainFromUrlString, _getRoomAndDomainFromUrlString,
_getRouteToRender, _getRouteToRender,
areRoutesEqual,
init init
} from './functions'; } from './functions';
import './reducer'; import './reducer';
/**
* Variable saving current route of the app. Later it will be extracted as
* a property of the class with Router specific logic.
*
* @type {Object}
*/
let currentRoute = {};
/** /**
* Temporary solution. Should dispatch actions related to initial settings of * Temporary solution. Should dispatch actions related to initial settings of
* the app like setting log levels, reading the config parameters from query * the app like setting log levels, reading the config parameters from query
@ -42,9 +50,7 @@ export function appNavigate(urlOrRoom) {
// current conference and start a new one with the new room name or // current conference and start a new one with the new room name or
// domain. // domain.
if (room === 'mobile-app') { if (typeof domain === 'undefined' || oldDomain === domain) {
return;
} else if (typeof domain === 'undefined' || oldDomain === domain) {
// If both domain and room vars became undefined, that means we're // If both domain and room vars became undefined, that means we're
// actually dealing with just room name and not with URL. // actually dealing with just room name and not with URL.
dispatch( dispatch(
@ -63,7 +69,15 @@ export function appNavigate(urlOrRoom) {
loadConfig(`https://${domain}`) loadConfig(`https://${domain}`)
.then( .then(
config => configLoaded(/* err */ undefined, config), config => configLoaded(/* err */ undefined, config),
err => configLoaded(err, /* config */ undefined)); err => configLoaded(err, /* config */ undefined))
.then(() => {
const link = typeof room === 'undefined'
&& typeof domain === 'undefined'
? urlOrRoom
: room;
dispatch(_setRoomAndNavigate(link));
});
} }
/** /**
@ -87,9 +101,6 @@ export function appNavigate(urlOrRoom) {
return; return;
} }
// We set room name only here to prevent race conditions on app
// start to not make app re-render conference page for two times.
dispatch(setRoom(room));
dispatch(setConfig(config)); dispatch(setConfig(config));
} }
}; };
@ -127,20 +138,6 @@ export function appWillUnmount(app) {
}; };
} }
/**
* Navigates to route corresponding to current room name.
*
* @param {Object} state - Redux state.
* @private
* @returns {void}
*/
function _navigate(state) {
const app = state['features/app'].app;
const routeToRender = _getRouteToRender(state);
app._navigate(routeToRender);
}
/** /**
* Sets room and navigates to new route if needed. * Sets room and navigates to new route if needed.
* *
@ -150,21 +147,15 @@ function _navigate(state) {
*/ */
function _setRoomAndNavigate(newRoom) { function _setRoomAndNavigate(newRoom) {
return (dispatch, getState) => { return (dispatch, getState) => {
const oldRoom = getState()['features/base/conference'].room;
dispatch(setRoom(newRoom)); dispatch(setRoom(newRoom));
const state = getState(); const state = getState();
const { room } = state['features/base/conference']; const { app } = state['features/app'];
const { landingIsShown } = state['features/unsupported-browser']; const newRoute = _getRouteToRender(state);
// If the user agent is a mobile browser and landing hasn't been shown if (!areRoutesEqual(newRoute, currentRoute)) {
// yet, we should recheck which component to render. currentRoute = newRoute;
const OS = Platform.OS; app._navigate(newRoute);
if (((OS === 'android' || OS === 'ios') && !landingIsShown)
|| room !== oldRoom) {
_navigate(state);
} }
}; };
} }

View File

@ -35,17 +35,33 @@ export function _getRouteToRender(stateOrGetState) {
// If landing was shown, there is no need to show it again. // If landing was shown, there is no need to show it again.
const { landingIsShown } = state['features/unsupported-browser']; const { landingIsShown } = state['features/unsupported-browser'];
let component; const { room } = state['features/base/conference'];
const component = isRoomValid(room) ? Conference : WelcomePage;
// We're using spread operator here to create copy of the route registered
// in registry. If we overwrite some of its properties (like 'component')
// they will stay unchanged in the registry.
const route = { ...RouteRegistry.getRouteByComponent(component) };
if ((OS === 'android' || OS === 'ios') && !landingIsShown) { if ((OS === 'android' || OS === 'ios') && !landingIsShown) {
component = Landing; route.component = Landing;
} else {
const { room } = state['features/base/conference'];
component = isRoomValid(room) ? Conference : WelcomePage;
} }
return RouteRegistry.getRouteByComponent(component); return route;
}
/**
* Method checking whether route objects are equal by value. Returns true if
* and only if key values of the first object are equal to key values of
* the second one.
*
* @param {Object} newRoute - New route object to be compared.
* @param {Object} oldRoute - Old route object to be compared.
* @returns {boolean}
*/
export function areRoutesEqual(newRoute, oldRoute) {
return Object.keys(newRoute)
.every(key => newRoute[key] === oldRoute[key]);
} }
/** /**

View File

@ -1,9 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Link } from 'react-router';
import { Platform } from '../../base/react'; import { Platform } from '../../base/react';
import { appNavigate } from '../../app';
import { landingIsShown } from '../actions'; import { landingIsShown } from '../actions';
/** /**
@ -21,6 +21,20 @@ const URLS = {
* @class Landing * @class Landing
*/ */
class Landing extends Component { class Landing extends Component {
/**
* Constructor of Landing component.
*
* @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized.
*/
constructor(props) {
super(props);
// Bind methods
this._onClickJoin = this._onClickJoin.bind(this);
}
/** /**
* Landing component's property types. * Landing component's property types.
* *
@ -48,7 +62,7 @@ class Landing extends Component {
componentWillMount() { componentWillMount() {
const { room } = this.props; const { room } = this.props;
let btnText; let btnText;
let link = '/'; let link = '';
if (room) { if (room) {
btnText = 'Join the conversation'; btnText = 'Join the conversation';
@ -63,13 +77,25 @@ class Landing extends Component {
}); });
} }
/**
* Navigates to the next state of the app.
*
* @returns {void}
* @private
*/
_onClickJoin() {
const { link } = this.state;
this.props.dispatch(appNavigate(link));
}
/** /**
* Renders landing component. * Renders landing component.
* *
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { btnText, link } = this.state; const { btnText } = this.state;
const primaryButtonClasses = 'landing__button landing__button_primary'; const primaryButtonClasses = 'landing__button landing__button_primary';
return ( return (
@ -92,11 +118,11 @@ class Landing extends Component {
<br /> <br />
<strong>then</strong> <strong>then</strong>
</p> </p>
<Link to = { link }> <button
<button className = 'landing__button'> className = 'landing__button'
{ btnText } onClick = { this._onClickJoin }>
</button> { btnText }
</Link> </button>
</div> </div>
</div> </div>
); );

View File

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

View File

@ -1,8 +0,0 @@
import { RouteRegistry } from '../base/navigator';
import { Landing } from './components';
RouteRegistry.register({
component: Landing,
path: '/mobile-app'
});