jiti-meet/react/features/deep-linking/components/DeepLinkingMobilePage.web.js

293 lines
9.2 KiB
JavaScript
Raw Normal View History

// @flow
2017-02-07 14:45:51 +00:00
2016-12-23 16:21:51 +00:00
import React, { Component } from 'react';
import type { Dispatch } from 'redux';
2017-01-13 22:37:53 +00:00
import { createDeepLinkingPageEvent, sendAnalytics } from '../../analytics';
import { isSupportedMobileBrowser } from '../../base/environment';
import { translate } from '../../base/i18n';
import { Platform } from '../../base/react';
2020-05-20 10:57:03 +00:00
import { connect } from '../../base/redux';
import { DialInSummary } from '../../invite';
import { openWebApp } from '../actions';
import { _TNS } from '../constants';
import { generateDeepLinkingURL } from '../functions';
2019-11-05 12:02:39 +00:00
import { renderPromotionalFooter } from '../renderPromotionalFooter';
declare var interfaceConfig: Object;
2017-03-01 02:55:12 +00:00
/**
* The namespace of the CSS styles of DeepLinkingMobilePage.
2017-03-01 02:55:12 +00:00
*
* @private
* @type {string}
*/
const _SNS = 'deep-linking-mobile';
2017-03-01 02:55:12 +00:00
2016-12-23 16:21:51 +00:00
/**
* The type of the React {@code Component} props of
* {@link DeepLinkingMobilePage}.
2016-12-23 16:21:51 +00:00
*/
type Props = {
2017-02-07 14:45:51 +00:00
/**
* Application download URL.
*/
_downloadUrl: ?string,
2017-01-25 22:11:44 +00:00
/**
* The name of the conference attempting to being joined.
2017-01-25 22:11:44 +00:00
*/
_room: string,
/**
* The page current url.
*/
_url: URL,
/**
* Used to dispatch actions from the buttons.
*/
dispatch: Dispatch<any>,
/**
* The function to translate human-readable text.
*/
t: Function
};
/**
* React component representing mobile browser page.
*
* @class DeepLinkingMobilePage
*/
class DeepLinkingMobilePage extends Component<Props> {
/**
* Initializes a new {@code DeepLinkingMobilePage} instance.
*
* @param {Object} props - The read-only React {@code Component} props with
* which the new instance is to be initialized.
*/
constructor(props: Props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onDownloadApp = this._onDownloadApp.bind(this);
this._onLaunchWeb = this._onLaunchWeb.bind(this);
this._onOpenApp = this._onOpenApp.bind(this);
}
/**
* Implements the Component's componentDidMount method.
*
* @inheritdoc
*/
componentDidMount() {
sendAnalytics(
createDeepLinkingPageEvent(
'displayed', 'DeepLinkingMobile', { isMobileBrowser: true }));
}
2016-12-23 16:21:51 +00:00
/**
2017-02-01 04:25:09 +00:00
* Implements React's {@link Component#render()}.
2016-12-23 16:21:51 +00:00
*
2017-02-01 04:25:09 +00:00
* @inheritdoc
2016-12-23 16:21:51 +00:00
* @returns {ReactElement}
*/
render() {
const { _downloadUrl, _room, t, _url } = this.props;
const { HIDE_DEEP_LINKING_LOGO, NATIVE_APP_NAME, SHOW_DEEP_LINKING_IMAGE } = interfaceConfig;
const downloadButtonClassName
2017-03-01 02:55:12 +00:00
= `${_SNS}__button ${_SNS}__button_primary`;
const onOpenLinkProperties = _downloadUrl
? {
// When opening a link to the download page, we want to let the
// OS itself handle intercepting and opening the appropriate
// app store. This avoids potential issues with browsers, such
// as iOS Chrome, not opening the store properly.
}
: {
// When falling back to another URL (Firebase) let the page be
// opened in a new window. This helps prevent the user getting
// trapped in an app-open-cycle where going back to the mobile
// browser re-triggers the app-open behavior.
target: '_blank',
rel: 'noopener noreferrer'
};
2016-12-23 16:21:51 +00:00
return (
2017-03-01 02:55:12 +00:00
<div className = { _SNS }>
<div className = 'header'>
{
HIDE_DEEP_LINKING_LOGO
? null
: <img
alt = { t('welcomepage.logo.logoDeepLinking') }
className = 'logo'
src = 'images/logo-deep-linking.png' />
}
</div>
<div className = { `${_SNS}__body` }>
{
SHOW_DEEP_LINKING_IMAGE
? <img
alt = { t('welcomepage.logo.logoDeepLinking') }
className = 'image'
src = 'images/deep-linking-image.png' />
: null
}
2017-03-01 02:55:12 +00:00
<p className = { `${_SNS}__text` }>
{ t(`${_TNS}.appNotInstalled`, { app: NATIVE_APP_NAME }) }
2016-12-23 16:21:51 +00:00
</p>
2020-05-14 21:45:00 +00:00
<p className = { `${_SNS}__text` }>
{ t(`${_TNS}.ifHaveApp`) }
</p>
<a
{ ...onOpenLinkProperties }
2020-05-14 21:45:00 +00:00
className = { `${_SNS}__href` }
href = { generateDeepLinkingURL() }
onClick = { this._onOpenApp }
target = '_top'>
2020-05-14 21:45:00 +00:00
<button className = { `${_SNS}__button ${_SNS}__button_primary` }>
{ t(`${_TNS}.joinInApp`) }
2017-02-01 04:25:09 +00:00
</button>
</a>
2020-05-14 21:45:00 +00:00
<p className = { `${_SNS}__text` }>
{ t(`${_TNS}.ifDoNotHaveApp`) }
</p>
<a
{ ...onOpenLinkProperties }
2020-05-14 21:45:00 +00:00
href = { this._generateDownloadURL() }
onClick = { this._onDownloadApp }
target = '_top'>
2020-05-14 21:45:00 +00:00
<button className = { downloadButtonClassName }>
{ t(`${_TNS}.downloadApp`) }
</button>
</a>
{
isSupportedMobileBrowser()
? (
<a
onClick = { this._onLaunchWeb }
target = '_top'>
<button className = { downloadButtonClassName }>
{ t(`${_TNS}.launchWebButton`) }
</button>
</a>
) : (
<b>
{ t(`${_TNS}.unsupportedBrowser`) }
</b>
)
}
2019-11-05 12:02:39 +00:00
{ renderPromotionalFooter() }
<DialInSummary
className = 'deep-linking-dial-in'
clickableNumbers = { true }
room = { _room }
url = { _url } />
2016-12-23 16:21:51 +00:00
</div>
</div>
);
}
/**
* Generates the URL for downloading the app.
*
* @private
* @returns {string} - The URL for downloading the app.
*/
_generateDownloadURL() {
const { _downloadUrl: url } = this.props;
if (url && typeof interfaceConfig.MOBILE_DYNAMIC_LINK === 'undefined') {
return url;
}
// For information about the properties of
// interfaceConfig.MOBILE_DYNAMIC_LINK check:
// https://firebase.google.com/docs/dynamic-links/create-manually
const {
APN = 'org.jitsi.meet',
APP_CODE = 'w2atb',
CUSTOM_DOMAIN = undefined,
IBI = 'com.atlassian.JitsiMeet.ios',
ISI = '1165103905'
} = interfaceConfig.MOBILE_DYNAMIC_LINK || {};
const domain = CUSTOM_DOMAIN ?? `https://${APP_CODE}.app.goo.gl`;
const IUS = interfaceConfig.APP_SCHEME || 'org.jitsi.meet';
return `${domain}/?link=${
encodeURIComponent(window.location.href)}&apn=${
APN}&ibi=${
IBI}&isi=${
ISI}&ius=${
IUS}&efr=1`;
}
2019-08-15 14:54:31 +00:00
_onDownloadApp: () => void;
/**
* Handles download app button clicks.
*
* @private
* @returns {void}
*/
_onDownloadApp() {
sendAnalytics(
createDeepLinkingPageEvent(
'clicked', 'downloadAppButton', { isMobileBrowser: true }));
}
_onLaunchWeb: () => void;
/**
* Handles launch web button clicks.
*
* @returns {void}
*/
_onLaunchWeb() {
sendAnalytics(
createDeepLinkingPageEvent(
'clicked', 'launchWebButton', { isMobileBrowser: true }));
this.props.dispatch(openWebApp());
}
2019-08-15 14:54:31 +00:00
_onOpenApp: () => void;
/**
* Handles open app button clicks.
*
* @private
* @returns {void}
*/
_onOpenApp() {
sendAnalytics(
createDeepLinkingPageEvent(
'clicked', 'openAppButton', { isMobileBrowser: true }));
}
2016-12-23 16:21:51 +00:00
}
/**
* Maps (parts of) the Redux state to the associated props for the
* {@code DeepLinkingMobilePage} component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
*/
function _mapStateToProps(state) {
const { locationURL = {} } = state['features/base/connection'];
return {
_downloadUrl: interfaceConfig[`MOBILE_DOWNLOAD_LINK_${Platform.OS.toUpperCase()}`],
_room: decodeURIComponent(state['features/base/conference'].room),
_url: locationURL
};
}
export default translate(connect(_mapStateToProps)(DeepLinkingMobilePage));