mirror of https://github.com/jitsi/jitsi-meet
parent
0c851934fb
commit
58a4f59fd8
@ -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'; |
||||
|
@ -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