You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DeepLinkingMobilePage.web.tsx 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* eslint-disable lines-around-comment */
  2. import { Theme } from '@mui/material';
  3. import React, { useCallback, useEffect, useMemo } from 'react';
  4. import { WithTranslation } from 'react-i18next';
  5. import { useDispatch, useSelector } from 'react-redux';
  6. import { makeStyles } from 'tss-react/mui';
  7. import { createDeepLinkingPageEvent } from '../../analytics/AnalyticsEvents';
  8. import { sendAnalytics } from '../../analytics/functions';
  9. import { IReduxState } from '../../app/types';
  10. import { IDeeplinkingConfig, IDeeplinkingMobileConfig } from '../../base/config/configType';
  11. import { isSupportedMobileBrowser } from '../../base/environment/environment';
  12. import { translate } from '../../base/i18n/functions';
  13. import Platform from '../../base/react/Platform.web';
  14. import { withPixelLineHeight } from '../../base/styles/functions.web';
  15. import Button from '../../base/ui/components/web/Button';
  16. // @ts-ignore
  17. import DialInSummary from '../../invite/components/dial-in-summary/web/DialInSummary';
  18. import { openWebApp } from '../actions';
  19. // @ts-ignore
  20. import { _TNS } from '../constants';
  21. // @ts-ignore
  22. import { generateDeepLinkingURL } from '../functions';
  23. const PADDINGS = {
  24. topBottom: 24,
  25. leftRight: 40
  26. };
  27. const useStyles = makeStyles()((theme: Theme) => {
  28. return {
  29. container: {
  30. background: '#1E1E1E',
  31. width: '100vw',
  32. height: '100vh',
  33. overflowX: 'hidden',
  34. overflowY: 'auto',
  35. justifyContent: 'center',
  36. display: 'flex',
  37. '& a': {
  38. textDecoration: 'none'
  39. }
  40. },
  41. contentPane: {
  42. display: 'flex',
  43. alignItems: 'center',
  44. flexDirection: 'column',
  45. padding: `${PADDINGS.topBottom}px ${PADDINGS.leftRight}px`,
  46. maxWidth: 410,
  47. color: theme.palette.text01
  48. },
  49. launchingMeetingLabel: {
  50. marginTop: 24,
  51. textAlign: 'center',
  52. marginBottom: 32,
  53. ...withPixelLineHeight(theme.typography.heading5)
  54. },
  55. roomNameLabel: {
  56. ...withPixelLineHeight(theme.typography.bodyLongRegularLarge)
  57. },
  58. joinMeetWrapper: {
  59. marginTop: 24,
  60. width: '100%'
  61. },
  62. labelDescription: {
  63. textAlign: 'center',
  64. marginTop: 16,
  65. ...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
  66. },
  67. linkWrapper: {
  68. display: 'flex',
  69. justifyContent: 'center',
  70. alignItems: 'center',
  71. marginTop: 8,
  72. width: '100%'
  73. },
  74. linkLabel: {
  75. color: theme.palette.link01,
  76. ...withPixelLineHeight(theme.typography.bodyLongBoldLarge)
  77. },
  78. supportedBrowserContent: {
  79. marginTop: 16,
  80. display: 'flex',
  81. flexDirection: 'column',
  82. alignItems: 'center',
  83. justifyContent: 'center'
  84. },
  85. labelOr: {
  86. ...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
  87. },
  88. separator: {
  89. marginTop: '32px',
  90. height: 1,
  91. width: `calc(100% + ${2 * PADDINGS.leftRight}px)`,
  92. background: theme.palette.ui03
  93. }
  94. };
  95. });
  96. const DeepLinkingMobilePage: React.FC<WithTranslation> = ({ t }) => {
  97. const deeplinkingCfg = useSelector((state: IReduxState) =>
  98. state['features/base/config']?.deeplinking || {} as IDeeplinkingConfig);
  99. const { hideLogo } = deeplinkingCfg;
  100. const deepLinkingUrl: string = useSelector(generateDeepLinkingURL);
  101. const room = useSelector((state: IReduxState) => decodeURIComponent(state['features/base/conference'].room || ''));
  102. const url = useSelector((state: IReduxState) => state['features/base/connection'] || {});
  103. const dispatch = useDispatch();
  104. const { classes: styles } = useStyles();
  105. const generateDownloadURL = useCallback(() => {
  106. const { downloadLink, dynamicLink, appScheme }
  107. = (deeplinkingCfg?.[Platform.OS as keyof typeof deeplinkingCfg] || {}) as IDeeplinkingMobileConfig;
  108. if (downloadLink && typeof dynamicLink === 'undefined') {
  109. return downloadLink;
  110. }
  111. const {
  112. apn,
  113. appCode,
  114. customDomain,
  115. ibi,
  116. isi
  117. } = dynamicLink || {};
  118. const domain = customDomain ?? `https://${appCode}.app.goo.gl`;
  119. return `${domain}/?link=${
  120. encodeURIComponent(window.location.href)}&apn=${
  121. apn}&ibi=${
  122. ibi}&isi=${
  123. isi}&ius=${
  124. appScheme}&efr=1`;
  125. }, [ deeplinkingCfg ]);
  126. const onDownloadApp = useCallback(() => {
  127. sendAnalytics(
  128. createDeepLinkingPageEvent(
  129. 'clicked', 'downloadAppButton', { isMobileBrowser: true }));
  130. }, []);
  131. const onLaunchWeb = useCallback(() => {
  132. sendAnalytics(
  133. createDeepLinkingPageEvent(
  134. 'clicked', 'launchWebButton', { isMobileBrowser: true }));
  135. dispatch(openWebApp());
  136. }, []);
  137. const onOpenApp = useCallback(() => {
  138. sendAnalytics(
  139. createDeepLinkingPageEvent(
  140. 'clicked', 'openAppButton', { isMobileBrowser: true }));
  141. }, []);
  142. const onOpenLinkProperties = useMemo(() => {
  143. const { downloadLink }
  144. = (deeplinkingCfg?.[Platform.OS as keyof typeof deeplinkingCfg] || {}) as IDeeplinkingMobileConfig;
  145. if (downloadLink) {
  146. return {
  147. // When opening a link to the download page, we want to let the
  148. // OS itself handle intercepting and opening the appropriate
  149. // app store. This avoids potential issues with browsers, such
  150. // as iOS Chrome, not opening the store properly.
  151. };
  152. }
  153. return {
  154. // When falling back to another URL (Firebase) let the page be
  155. // opened in a new window. This helps prevent the user getting
  156. // trapped in an app-open-cycle where going back to the mobile
  157. // browser re-triggers the app-open behavior.
  158. target: '_blank',
  159. rel: 'noopener noreferrer'
  160. };
  161. }, [ deeplinkingCfg ]);
  162. useEffect(() => {
  163. sendAnalytics(
  164. createDeepLinkingPageEvent(
  165. 'displayed', 'DeepLinkingMobile', { isMobileBrowser: true }));
  166. }, []);
  167. return (
  168. <div className = { styles.container }>
  169. <div className = { styles.contentPane }>
  170. {!hideLogo && (<img
  171. alt = { t('welcomepage.logo.logoDeepLinking') }
  172. src = 'images/logo-deep-linking-mobile.png' />
  173. )}
  174. <div className = { styles.launchingMeetingLabel }>{ t(`${_TNS}.launchMeetingLabel`) }</div>
  175. <div className = ''>{room}</div>
  176. <a
  177. { ...onOpenLinkProperties }
  178. className = { styles.joinMeetWrapper }
  179. href = { deepLinkingUrl }
  180. onClick = { onOpenApp }
  181. target = '_top'>
  182. <Button
  183. fullWidth = { true }
  184. label = { t(`${_TNS}.joinInAppNew`) } />
  185. </a>
  186. <div className = { styles.labelDescription }>{ t(`${_TNS}.noMobileApp`) }</div>
  187. <a
  188. { ...onOpenLinkProperties }
  189. className = { styles.linkWrapper }
  190. href = { generateDownloadURL() }
  191. onClick = { onDownloadApp }
  192. target = '_top'>
  193. <div className = { styles.linkLabel }>{ t(`${_TNS}.downloadMobileApp`) }</div>
  194. </a>
  195. {isSupportedMobileBrowser() ? (
  196. <div className = { styles.supportedBrowserContent }>
  197. <div className = { styles.labelOr }>OR</div>
  198. <a
  199. className = { styles.linkWrapper }
  200. onClick = { onLaunchWeb }
  201. target = '_top'>
  202. <div className = { styles.linkLabel }>{ t(`${_TNS}.joinInBrowser`) }</div>
  203. </a>
  204. </div>
  205. ) : (
  206. <div className = { styles.labelDescription }>
  207. {t(`${_TNS}.unsupportedBrowser`)}
  208. </div>
  209. )}
  210. <div className = { styles.separator } />
  211. <DialInSummary
  212. className = 'deep-linking-dial-in'
  213. clickableNumbers = { true }
  214. room = { room }
  215. url = { url } />
  216. </div>
  217. </div>
  218. );
  219. };
  220. export default translate(DeepLinkingMobilePage);