-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17452 from ntdiary/clean-up-deep-link-code
clean up the deep link code
- Loading branch information
Showing
19 changed files
with
192 additions
and
206 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,157 +1,42 @@ | ||
import PropTypes from 'prop-types'; | ||
import React, {PureComponent} from 'react'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import FullScreenLoadingIndicator from '../FullscreenLoadingIndicator'; | ||
import styles from '../../styles/styles'; | ||
import {PureComponent} from 'react'; | ||
import Str from 'expensify-common/lib/str'; | ||
import * as Browser from '../../libs/Browser'; | ||
import ROUTES from '../../ROUTES'; | ||
import * as App from '../../libs/actions/App'; | ||
import CONST from '../../CONST'; | ||
import CONFIG from '../../CONFIG'; | ||
import * as Browser from '../../libs/Browser'; | ||
import ONYXKEYS from '../../ONYXKEYS'; | ||
import * as Authentication from '../../libs/Authentication'; | ||
import DeeplinkRedirectLoadingIndicator from './DeeplinkRedirectLoadingIndicator'; | ||
import * as Session from '../../libs/actions/Session'; | ||
|
||
const propTypes = { | ||
/** Children to render. */ | ||
children: PropTypes.node.isRequired, | ||
|
||
/** Session info for the currently logged-in user. */ | ||
session: PropTypes.shape({ | ||
/** Currently logged-in user email */ | ||
email: PropTypes.string, | ||
|
||
/** Currently logged-in user authToken */ | ||
authToken: PropTypes.string, | ||
}), | ||
}; | ||
|
||
const defaultProps = { | ||
session: { | ||
email: '', | ||
authToken: '', | ||
}, | ||
}; | ||
|
||
class DeeplinkWrapper extends PureComponent { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
appInstallationCheckStatus: | ||
this.isMacOSWeb() && CONFIG.ENVIRONMENT !== CONST.ENVIRONMENT.DEV ? CONST.DESKTOP_DEEPLINK_APP_STATE.CHECKING : CONST.DESKTOP_DEEPLINK_APP_STATE.NOT_INSTALLED, | ||
shouldOpenLinkInBrowser: false, | ||
}; | ||
this.focused = true; | ||
this.openLinkInBrowser = this.openLinkInBrowser.bind(this); | ||
} | ||
|
||
componentDidMount() { | ||
if (!this.isMacOSWeb() || CONFIG.ENVIRONMENT === CONST.ENVIRONMENT.DEV) { | ||
return; | ||
} | ||
|
||
window.addEventListener('blur', () => { | ||
this.focused = false; | ||
}); | ||
|
||
const expensifyUrl = new URL(CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL); | ||
const params = new URLSearchParams(); | ||
params.set('exitTo', `${window.location.pathname}${window.location.search}${window.location.hash}`); | ||
if (!this.props.session.authToken) { | ||
const expensifyDeeplinkUrl = `${CONST.DEEPLINK_BASE_URL}${expensifyUrl.host}/transition?${params.toString()}`; | ||
this.openRouteInDesktopApp(expensifyDeeplinkUrl); | ||
return; | ||
} | ||
|
||
// There's no support for anonymous users on desktop | ||
if (Session.isAnonymousUser()) { | ||
// If the current url path is /transition..., meaning it was opened from oldDot, during this transition period: | ||
// 1. The user session may not exist, because sign-in has not been completed yet. | ||
// 2. There may be non-idempotent operations (e.g. create a new workspace), which obviously should not be executed again in the desktop app. | ||
// So we need to wait until after sign-in and navigation are complete before starting the deeplink redirect. | ||
if (Str.startsWith(window.location.pathname, Str.normalizeUrl(ROUTES.TRANSITION_BETWEEN_APPS))) { | ||
App.beginDeepLinkRedirectAfterTransition(); | ||
return; | ||
} | ||
|
||
Authentication.getShortLivedAuthToken() | ||
.then((shortLivedAuthToken) => { | ||
params.set('email', this.props.session.email); | ||
params.set('shortLivedAuthToken', `${shortLivedAuthToken}`); | ||
const expensifyDeeplinkUrl = `${CONST.DEEPLINK_BASE_URL}${expensifyUrl.host}/transition?${params.toString()}`; | ||
this.openRouteInDesktopApp(expensifyDeeplinkUrl); | ||
}) | ||
.catch(() => { | ||
// If the request is successful, we call the updateAppInstallationCheckStatus before the prompt pops up. | ||
// If not, we only need to make sure that the state will be updated. | ||
this.updateAppInstallationCheckStatus(); | ||
}); | ||
} | ||
|
||
updateAppInstallationCheckStatus() { | ||
setTimeout(() => { | ||
if (!this.focused) { | ||
this.setState({appInstallationCheckStatus: CONST.DESKTOP_DEEPLINK_APP_STATE.INSTALLED}); | ||
} else { | ||
this.setState({appInstallationCheckStatus: CONST.DESKTOP_DEEPLINK_APP_STATE.NOT_INSTALLED}); | ||
} | ||
}, 500); | ||
} | ||
|
||
openRouteInDesktopApp(expensifyDeeplinkUrl) { | ||
this.updateAppInstallationCheckStatus(); | ||
|
||
const browser = Browser.getBrowser(); | ||
|
||
// This check is necessary for Safari, otherwise, if the user | ||
// does NOT have the Expensify desktop app installed, it's gonna | ||
// show an error in the page saying that the address is invalid | ||
// It is also necessary for Firefox, otherwise the window.location.href redirect | ||
// will abort the fetch request from NetInfo, which will cause the app to go offline temporarily. | ||
if (browser === CONST.BROWSER.SAFARI || browser === CONST.BROWSER.FIREFOX) { | ||
const iframe = document.createElement('iframe'); | ||
iframe.style.display = 'none'; | ||
document.body.appendChild(iframe); | ||
iframe.contentWindow.location.href = expensifyDeeplinkUrl; | ||
|
||
// Since we're creating an iframe for Safari to handle | ||
// deeplink we need to give this iframe some time for | ||
// it to do what it needs to do. After that we can just | ||
// remove the iframe. | ||
setTimeout(() => { | ||
if (!iframe.parentNode) { | ||
return; | ||
} | ||
|
||
iframe.parentNode.removeChild(iframe); | ||
}, 100); | ||
} else { | ||
window.location.href = expensifyDeeplinkUrl; | ||
} | ||
App.beginDeepLinkRedirect(); | ||
} | ||
|
||
isMacOSWeb() { | ||
return !Browser.isMobile() && typeof navigator === 'object' && typeof navigator.userAgent === 'string' && /Mac/i.test(navigator.userAgent) && !/Electron/i.test(navigator.userAgent); | ||
} | ||
|
||
openLinkInBrowser() { | ||
this.setState({shouldOpenLinkInBrowser: true}); | ||
} | ||
|
||
shouldShowDeeplinkLoadingIndicator() { | ||
const routeRegex = new RegExp(CONST.REGEX.ROUTES.VALIDATE_LOGIN); | ||
return routeRegex.test(window.location.pathname); | ||
} | ||
|
||
render() { | ||
if (this.state.appInstallationCheckStatus === CONST.DESKTOP_DEEPLINK_APP_STATE.CHECKING) { | ||
return <FullScreenLoadingIndicator style={styles.flex1} />; | ||
} | ||
|
||
if (this.state.appInstallationCheckStatus === CONST.DESKTOP_DEEPLINK_APP_STATE.INSTALLED && this.shouldShowDeeplinkLoadingIndicator() && !this.state.shouldOpenLinkInBrowser) { | ||
return <DeeplinkRedirectLoadingIndicator openLinkInBrowser={this.openLinkInBrowser} />; | ||
} | ||
|
||
return this.props.children; | ||
} | ||
} | ||
|
||
DeeplinkWrapper.propTypes = propTypes; | ||
DeeplinkWrapper.defaultProps = defaultProps; | ||
export default withOnyx({ | ||
session: {key: ONYXKEYS.SESSION}, | ||
})(DeeplinkWrapper); | ||
export default DeeplinkWrapper; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.