Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

DeepLinkingMobilePage.web.tsx 8.7KB

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