-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
index.website.js
150 lines (128 loc) · 5.77 KB
/
index.website.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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 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';
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;
}
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;
}
}
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);