diff --git a/.well-known/apple-app-site-association b/.well-known/apple-app-site-association
index d6da0232f2fc..1e63fdcb2d52 100644
--- a/.well-known/apple-app-site-association
+++ b/.well-known/apple-app-site-association
@@ -79,6 +79,10 @@
{
"/": "/search/*",
"comment": "Search"
+ },
+ {
+ "/": "/money2020/*",
+ "comment": "Money 2020"
}
]
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index d823324f50bf..7419d5b1e1a7 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -70,6 +70,7 @@
+
@@ -87,6 +88,7 @@
+
diff --git a/src/CONST.ts b/src/CONST.ts
index 0a86aaf7648a..d1d9bb1dede9 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -2718,6 +2718,7 @@ const CONST = {
DEMO_PAGES: {
SAASTR: 'SaaStrDemoSetup',
SBE: 'SbeDemoSetup',
+ MONEY2020: 'Money2020DemoSetup',
},
MAPBOX: {
diff --git a/src/Expensify.js b/src/Expensify.js
index 642b8ceb456c..6010824cf275 100644
--- a/src/Expensify.js
+++ b/src/Expensify.js
@@ -29,6 +29,7 @@ import SplashScreenHider from './components/SplashScreenHider';
import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
import EmojiPicker from './components/EmojiPicker/EmojiPicker';
import * as EmojiPickerAction from './libs/actions/EmojiPickerAction';
+import * as DemoActions from './libs/actions/DemoActions';
import DeeplinkWrapper from './components/DeeplinkWrapper';
// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
@@ -167,11 +168,13 @@ function Expensify(props) {
// If the app is opened from a deep link, get the reportID (if exists) from the deep link and navigate to the chat report
Linking.getInitialURL().then((url) => {
+ DemoActions.runDemoByURL(url);
Report.openReportFromDeepLink(url, isAuthenticated);
});
// Open chat report from a deep link (only mobile native)
Linking.addEventListener('url', (state) => {
+ DemoActions.runDemoByURL(state.url);
Report.openReportFromDeepLink(state.url, isAuthenticated);
});
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 7127c1483c26..398b9ac6ba4f 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -337,9 +337,10 @@ export default {
getRoute: (policyID: string) => `workspace/${policyID}/members`,
},
- // These are some on-off routes that will be removed once they're no longer needed (see GH issues for details)
+ // These are some one-off routes that will be removed once they're no longer needed (see GH issues for details)
SAASTR: 'saastr',
SBE: 'sbe',
+ MONEY2020: 'money2020',
// Iframe screens from olddot
HOME_OLDDOT: 'home',
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 0869306bb491..a4d934faec43 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -117,6 +117,13 @@ const propTypes = {
/** The last Onyx update ID was applied to the client */
lastUpdateIDAppliedToClient: PropTypes.number,
+ /** Information about any currently running demos */
+ demoInfo: PropTypes.shape({
+ money2020: PropTypes.shape({
+ isBeginningDemo: PropTypes.bool,
+ }),
+ }),
+
...windowDimensionsPropTypes,
};
@@ -127,6 +134,7 @@ const defaultProps = {
},
lastOpenedPublicRoomID: null,
lastUpdateIDAppliedToClient: null,
+ demoInfo: {},
};
class AuthScreens extends React.Component {
@@ -169,6 +177,10 @@ class AuthScreens extends React.Component {
App.setUpPoliciesAndNavigate(this.props.session, !this.props.isSmallScreenWidth);
App.redirectThirdPartyDesktopSignIn();
+ // Check if we should be running any demos immediately after signing in.
+ if (lodashGet(this.props.demoInfo, 'money2020.isBeginningDemo', false)) {
+ Navigation.navigate(ROUTES.MONEY2020, CONST.NAVIGATION.TYPE.FORCED_UP);
+ }
if (this.props.lastOpenedPublicRoomID) {
// Re-open the last opened public room if the user logged in from a public room link
Report.openLastOpenedPublicRoom(this.props.lastOpenedPublicRoomID);
@@ -299,6 +311,11 @@ class AuthScreens extends React.Component {
options={defaultScreenOptions}
component={DemoSetupPage}
/>
+
{
+ currentUserEmail = lodashGet(val, 'email', '');
+ },
+});
+
+function runMoney2020Demo() {
+ // Try to navigate to existing demo chat if it exists in Onyx
+ const money2020AccountID = Number(Config ? Config.EXPENSIFY_ACCOUNT_ID_MONEY2020 : 15864555);
+ const existingChatReport = ReportUtils.getChatByParticipants([money2020AccountID]);
+ if (existingChatReport) {
+ // We must call goBack() to remove the demo route from nav history
+ Navigation.goBack();
+ Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(existingChatReport.reportID));
+ return;
+ }
+
+ // We use makeRequestWithSideEffects here because we need to get the chat report ID to navigate to it after it's created
+ // eslint-disable-next-line rulesdir/no-api-side-effects-method
+ API.makeRequestWithSideEffects('CreateChatReport', {
+ emailList: `${currentUserEmail},money2020@expensify.com`,
+ activationConference: 'money2020',
+ }).then((response) => {
+ // If there's no response or no reportID in the response, navigate the user home so user doesn't get stuck.
+ if (!response || !response.reportID) {
+ Navigation.goBack();
+ Navigation.navigate(ROUTES.HOME);
+ return;
+ }
+
+ // Get reportID & navigate to it
+ // Note: We must call goBack() to remove the demo route from history
+ const chatReportID = response.reportID;
+ Navigation.goBack();
+ Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(chatReportID));
+ });
+}
+
+/**
+ * Runs code for specific demos, based on the provided URL
+ *
+ * @param {String} url - URL user is navigating to via deep link (or regular link in web)
+ */
+function runDemoByURL(url = '') {
+ const cleanUrl = (url || '').toLowerCase();
+
+ if (cleanUrl.endsWith(ROUTES.MONEY2020)) {
+ Onyx.set(ONYXKEYS.DEMO_INFO, {
+ money2020: {
+ isBeginningDemo: true,
+ },
+ });
+ } else {
+ // No demo is being run, so clear out demo info
+ Onyx.set(ONYXKEYS.DEMO_INFO, null);
+ }
+}
+
+export {runMoney2020Demo, runDemoByURL};
diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js
index 5d4b99a0daf9..5432bea0c806 100644
--- a/src/pages/DemoSetupPage.js
+++ b/src/pages/DemoSetupPage.js
@@ -1,9 +1,11 @@
-import React from 'react';
+import React, {useCallback} from 'react';
import PropTypes from 'prop-types';
import {useFocusEffect} from '@react-navigation/native';
import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
import Navigation from '../libs/Navigation/Navigation';
import ROUTES from '../ROUTES';
+import CONST from '../CONST';
+import * as DemoActions from '../libs/actions/DemoActions';
const propTypes = {
/** Navigation route context info provided by react navigation */
@@ -18,12 +20,16 @@ const propTypes = {
* route that led the user here. Now, it's just used to route the user home so we
* don't show them a "Hmm... It's not here" message (which looks broken).
*/
-function DemoSetupPage() {
- useFocusEffect(() => {
- Navigation.isNavigationReady().then(() => {
- Navigation.goBack(ROUTES.HOME);
- });
- });
+function DemoSetupPage(props) {
+ useFocusEffect(
+ useCallback(() => {
+ if (props.route.name === CONST.DEMO_PAGES.MONEY2020) {
+ DemoActions.runMoney2020Demo();
+ } else {
+ Navigation.goBack(ROUTES.HOME);
+ }
+ }, [props.route.name]),
+ );
return ;
}
diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
index 80fd1d39239d..c87d4f06e1f4 100644
--- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
+++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
@@ -62,6 +62,13 @@ const propTypes = {
/** Forwarded ref to FloatingActionButtonAndPopover */
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
+
+ /** Information about any currently running demos */
+ demoInfo: PropTypes.shape({
+ money2020: PropTypes.shape({
+ isBeginningDemo: PropTypes.bool,
+ }),
+ }),
};
const defaultProps = {
onHideCreateMenu: () => {},
@@ -70,6 +77,7 @@ const defaultProps = {
betas: [],
isLoading: false,
innerRef: null,
+ demoInfo: {},
};
/**
@@ -152,6 +160,9 @@ function FloatingActionButtonAndPopover(props) {
if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) {
return;
}
+ if (lodashGet(props.demoInfo, 'money2020.isBeginningDemo', false)) {
+ return;
+ }
Welcome.show({routes, showCreateMenu});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.isLoading]);
@@ -262,6 +273,9 @@ export default compose(
isLoading: {
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
},
+ demoInfo: {
+ key: ONYXKEYS.DEMO_INFO,
+ },
}),
)(
forwardRef((props, ref) => (