Implement Landing component
This commit is contained in:
parent
0c851934fb
commit
58a4f59fd8
|
@ -10,6 +10,10 @@
|
|||
max-width: 40em;
|
||||
text-align: center;
|
||||
color: $landingTextColor;
|
||||
|
||||
a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
|
@ -31,7 +35,7 @@
|
|||
|
||||
&__logo {
|
||||
width: 77px;
|
||||
height: auto;
|
||||
height: 108px;
|
||||
}
|
||||
|
||||
&__button {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!--#include virtual="base.html" -->
|
||||
<script>
|
||||
window.indexLoadedTime = window.performance.now();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { isRoomValid } from '../base/conference';
|
||||
import { RouteRegistry } from '../base/navigator';
|
||||
|
||||
import { Conference } from '../conference';
|
||||
import { WelcomePage } from '../welcome';
|
||||
|
||||
|
@ -85,8 +86,8 @@ export function _getRoomAndDomainFromUrlString(url) {
|
|||
export function _getRouteToRender(stateOrGetState) {
|
||||
const state
|
||||
= typeof stateOrGetState === 'function'
|
||||
? stateOrGetState()
|
||||
: stateOrGetState;
|
||||
? stateOrGetState()
|
||||
: stateOrGetState;
|
||||
const room = state['features/base/conference'].room;
|
||||
const component = isRoomValid(room) ? Conference : WelcomePage;
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Returns true if user agent is run on Android.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function detectAndroid() {
|
||||
return Boolean(navigator.userAgent.match(/Android/i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if user agent is run on iOS.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function detectIOS() {
|
||||
if (navigator.userAgent.match(/iPhone/i)
|
||||
|| navigator.userAgent.match(/iPad/i)
|
||||
|| navigator.userAgent.match(/iPod/i)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms hash map with parameters to query string.
|
||||
*
|
||||
* @param {Object} params - Hash map to be processed into query string.
|
||||
* @returns {string}
|
||||
*/
|
||||
export function serializeQuery(params) {
|
||||
return Object.keys(params).reduce((str, key, index) => {
|
||||
const encodedKey = encodeURIComponent(key);
|
||||
const encodedValue = encodeURIComponent(params[key]);
|
||||
let separator = '&';
|
||||
|
||||
if (index === 0) {
|
||||
separator = '?';
|
||||
}
|
||||
|
||||
return `${str}${separator}${encodedKey}=${encodedValue}`;
|
||||
}, '');
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
export * from './loadScript';
|
||||
export * from './roomnameGenerator';
|
||||
export * from './detectDevices';
|
||||
|
|
|
@ -5,7 +5,7 @@ import HttpConfigFetch from '../../../modules/config/HttpConfigFetch';
|
|||
import ConferenceUrl from '../../../modules/URL/ConferenceUrl';
|
||||
|
||||
import { RouteRegistry } from '../base/navigator';
|
||||
|
||||
import { detectIOS, detectAndroid, serializeQuery } from '../base/util';
|
||||
import { Conference } from './components';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { Symbol } from '../base/react';
|
||||
|
||||
/**
|
||||
* The type of the actions which signals that a mobile landing is shown.
|
||||
*
|
||||
* {
|
||||
* type: LANDING_IS_SHOWN
|
||||
* }
|
||||
*/
|
||||
export const LANDING_IS_SHOWN = Symbol('LANDING_IS_SHOWN');
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { LANDING_IS_SHOWN } from './actionTypes';
|
||||
import './reducer';
|
||||
|
||||
/**
|
||||
* Returns an action that mobile landing is shown
|
||||
* and there is no need to show it on other pages.
|
||||
*
|
||||
* @returns {{
|
||||
* type: LANDING_IS_SHOWN
|
||||
* }}
|
||||
*/
|
||||
export function landingIsShown() {
|
||||
return {
|
||||
type: LANDING_IS_SHOWN
|
||||
};
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
import { landingIsShown } from '../actions';
|
||||
|
||||
const links = {
|
||||
'android': 'https://play.google.com/store/apps/details?id=org.jitsi.meet',
|
||||
'ios': ''
|
||||
};
|
||||
|
||||
/**
|
||||
* React component representing mobile landing page.
|
||||
*
|
||||
* @class Landing
|
||||
*/
|
||||
class Landing extends Component {
|
||||
/**
|
||||
* React lifecycle method triggered after
|
||||
* component is mount.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
this.props.dispatch(landingIsShown());
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
dispatch: React.PropTypes.func,
|
||||
location: React.PropTypes.object
|
||||
};
|
||||
|
||||
/**
|
||||
* React lifecycle method triggered before
|
||||
* component will mount.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
componentWillMount() {
|
||||
const { query } = this.props.location;
|
||||
const { conferenceName, platform } = query;
|
||||
let btnText;
|
||||
let link = '/';
|
||||
|
||||
if (conferenceName) {
|
||||
btnText = 'Join the conversation';
|
||||
link += conferenceName;
|
||||
} else {
|
||||
btnText = 'Start a conference';
|
||||
}
|
||||
|
||||
this.setState({
|
||||
btnText,
|
||||
link,
|
||||
platform
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders landing component.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { btnText, link, platform } = this.state;
|
||||
const primaryButtonClasses = 'landing__button landing__button_primary';
|
||||
|
||||
return (
|
||||
<div className = 'landing'>
|
||||
<div className = 'landing__body'>
|
||||
<img
|
||||
className = 'landing__logo'
|
||||
src = '/images/logo-blue.svg' />
|
||||
<p className = 'landing__text'>
|
||||
You need <strong>Meet Jitsi</strong>
|
||||
to join a conversation on your mobile
|
||||
</p>
|
||||
<a href = { links[platform] }>
|
||||
<button
|
||||
className = { primaryButtonClasses }>
|
||||
Download the App
|
||||
</button>
|
||||
</a>
|
||||
<p className = 'landing__text landing__text_small'>
|
||||
or if you already have it
|
||||
<br /><strong>then</strong>
|
||||
</p>
|
||||
<Link to = { link }>
|
||||
<button
|
||||
className = 'landing__button'>{ btnText }</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(Landing);
|
|
@ -0,0 +1 @@
|
|||
export { default as Landing } from './Landing';
|
|
@ -0,0 +1,4 @@
|
|||
import './route';
|
||||
|
||||
export * from './actions';
|
||||
export * from './components';
|
|
@ -0,0 +1,21 @@
|
|||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import { LANDING_IS_SHOWN } from './actionTypes';
|
||||
|
||||
ReducerRegistry.register('features/landing', (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case LANDING_IS_SHOWN:
|
||||
return {
|
||||
...state,
|
||||
|
||||
/**
|
||||
* Flag that shows that mobile landing shown shown.
|
||||
*
|
||||
* @type {App}
|
||||
*/
|
||||
landingIsShown: true
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import { RouteRegistry } from '../base/navigator';
|
||||
import { Landing } from './components';
|
||||
|
||||
RouteRegistry.register({
|
||||
component: Landing,
|
||||
path: '/mobile-app',
|
||||
onEnter: store => () => {
|
||||
const state = store.getState();
|
||||
const { landingIsShown } = state;
|
||||
|
||||
if (landingIsShown) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue