From 70b6f38e7e002cddaac0501379b5815d97fda95a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 14 Aug 2023 14:53:51 +0300 Subject: [PATCH 01/29] Start creating new demo page route --- src/CONST.js | 3 ++ src/ROUTES.js | 3 ++ .../Navigators/CentralPaneNavigator.js | 10 +++++ src/libs/Navigation/linkingConfig.js | 1 + src/pages/DemoSetupPage.js | 43 +++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 src/pages/DemoSetupPage.js diff --git a/src/CONST.js b/src/CONST.js index 4c19965837d9..fe0013b3e94b 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2534,6 +2534,9 @@ const CONST = { DISTANCE: 'distance', }, STATUS_TEXT_MAX_LENGTH: 100, + DEMO_PAGES: { + SAASTR: 'SaaStrDemoSetup', + }, }; export default CONST; diff --git a/src/ROUTES.js b/src/ROUTES.js index 6c0365e40568..7f9e76a99338 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -173,6 +173,9 @@ export default { getWorkspaceTravelRoute: (policyID) => `workspace/${policyID}/travel`, getWorkspaceMembersRoute: (policyID) => `workspace/${policyID}/members`, + // These are some on-off routes that will be removed once they're no longer needed (see GH issues for details) + SAASTR: 'saastr', + /** * @param {String} route * @returns {Object} diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js index 64eadcbe06c3..47880ba14470 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js @@ -2,9 +2,11 @@ import React from 'react'; import {createStackNavigator} from '@react-navigation/stack'; import SCREENS from '../../../../SCREENS'; import ReportScreenWrapper from '../ReportScreenWrapper'; +import DemoSetupPage from '../../../../pages/DemoSetupPage'; import getCurrentUrl from '../../currentUrl'; import styles from '../../../../styles/styles'; import FreezeWrapper from '../../FreezeWrapper'; +import CONST from '../../../../CONST'; const Stack = createStackNavigator(); @@ -28,6 +30,14 @@ function CentralPaneNavigator() { }} component={ReportScreenWrapper} /> + ); diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index dcc4f77fde73..1a2bcc164bd0 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -23,6 +23,7 @@ export default { [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: { screens: { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID, + [CONST.DEMO_PAGES.SAASTR]: ROUTES.SAASTR }, }, [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js new file mode 100644 index 000000000000..d512eaff6cad --- /dev/null +++ b/src/pages/DemoSetupPage.js @@ -0,0 +1,43 @@ +import _ from 'underscore'; +import React from 'react'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import {useFocusEffect} from '@react-navigation/native'; +import ONYXKEYS from '../ONYXKEYS'; +import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; +import CONST from '../CONST'; + +const propTypes = { + /** Navigation route context info provided by react navigation */ + route: PropTypes.shape({ + /** The exact route name used to get to this screen */ + name: PropTypes.string.isRequired, + }).isRequired, +}; + +/* + * This is a "utility page", that does this: + * - Looks at the current route + * - Determines if there's a demo command we need to call + * - If not, routes back to home + */ +function DemoSetupPage(props) { + console.log('DEMO props', props); + useFocusEffect(() => { + if (props.route.name === CONST.DEMO_PAGES.SAASTR) { + // Do SaaStr demo setup here + console.log('HERE') + } + }); + + return ; +} + +DemoSetupPage.propTypes = propTypes; +DemoSetupPage.displayName = 'DemoSetupPage'; + +export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, +})(DemoSetupPage); From 69da9ad36565b0948bfcc1ee815d43857e9e4d07 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 14 Aug 2023 16:31:24 +0300 Subject: [PATCH 02/29] Add new saastr email --- .env.example | 1 + src/CONST.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.env.example b/.env.example index 944da2aa9296..d3bc11ec3024 100644 --- a/.env.example +++ b/.env.example @@ -26,5 +26,6 @@ EXPENSIFY_ACCOUNT_ID_QA=-1 EXPENSIFY_ACCOUNT_ID_QA_TRAVIS=-1 EXPENSIFY_ACCOUNT_ID_RECEIPTS=-1 EXPENSIFY_ACCOUNT_ID_REWARDS=-1 +EXPENSIFY_ACCOUNT_ID_SAASTR=-1 EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR=-1 EXPENSIFY_ACCOUNT_ID_SVFG=-1 diff --git a/src/CONST.js b/src/CONST.js index fe0013b3e94b..c1125708d7f7 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -844,6 +844,7 @@ const CONST = { QA: 'qa@expensify.com', QA_TRAVIS: 'qa+travisreceipts@expensify.com', RECEIPTS: 'receipts@expensify.com', + SAASTR: 'saastr@expensify.com', STUDENT_AMBASSADOR: 'studentambassadors@expensify.com', SVFG: 'svfg@expensify.com', }, @@ -863,6 +864,7 @@ const CONST = { QA_TRAVIS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA_TRAVIS', 8595733)), RECEIPTS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1)), REWARDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767)), // rewards@expensify.com + SAASTR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SAASTR', -1)), STUDENT_AMBASSADOR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956)), SVFG: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843)), }, From e805fdc56fcb428a698abd1c4630683af74bcd55 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 14 Aug 2023 16:47:49 +0300 Subject: [PATCH 03/29] Set up a new workspace, note todos --- src/libs/actions/DemoActions.js | 235 ++++++++++++++++++++++++++++++++ src/pages/DemoSetupPage.js | 6 +- 2 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/libs/actions/DemoActions.js diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js new file mode 100644 index 000000000000..a8529e9b1c20 --- /dev/null +++ b/src/libs/actions/DemoActions.js @@ -0,0 +1,235 @@ +import CONST from '../../CONST'; +import * as API from '../API'; +import {buildOptimisticWorkspaceChats} from '../ReportUtils'; +import {buildOptimisticCustomUnits, generatePolicyID} from './Policy'; + +function createSaastrDemoWorkspaceAndNavigate() { + // Create workspace, owned and admin'd by SaaStr + const policyID = generatePolicyID(); + + // TODO: maybe add domain name as prefix?? + const workspaceName = 'SaaStr Cantina'; + + const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(); + + const { + announceChatReportID, + announceChatData, + announceReportActionData, + announceCreatedReportActionID, + // Commenting these out b/c user shouldn't an admin to start with, right? :think: + // adminsChatReportID, + // adminsChatData, + // adminsReportActionData, + // adminsCreatedReportActionID, + expenseChatReportID, + expenseChatData, + expenseReportActionData, + expenseCreatedReportActionID, + } = buildOptimisticWorkspaceChats(policyID, workspaceName); + + // TODO: Add this user to workspace as a member + // TODO: Add optimistic invite message comment + // TODO: Make sure a specific reimbursement account is tied to the workspace + // TODO: Is it fine if the expense chat report is OWNED by the user instead of saastr here? + + // should all of the "Created" report actions (for each room) be OWNED by saastr or user? + // - it shouldn't actually matter, we don't show anything + + API.write( + 'CreateSaastrDemoWorkspace', + { + policyID, + announceChatReportID, + adminsChatReportID, + expenseChatReportID, + policyName: workspaceName, + announceCreatedReportActionID, + adminsCreatedReportActionID, + expenseCreatedReportActionID, + customUnitID, + customUnitRateID, + }, + { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + id: policyID, + type: CONST.POLICY.TYPE.FREE, + name: workspaceName, + role: CONST.POLICY.ROLE.USER, + owner: CONST.EMAIL.SAASTR, + outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + customUnits, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, + value: { + [sessionAccountID]: { + role: CONST.POLICY.ROLE.USER, + errors: {}, + }, + [CONST.ACCOUNT_ID.SAASTR]: { + role: CONST.POLICY.ROLE.ADMIN, + errors: {}, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ...announceChatData, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, + value: announceReportActionData, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ...adminsChatData, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, + value: adminsReportActionData, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + ...expenseChatData, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, + value: expenseReportActionData, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: {pendingAction: null}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: null, + }, + pendingAction: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, + value: { + [_.keys(announceChatData)[0]]: { + pendingAction: null, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: null, + }, + pendingAction: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, + value: { + [_.keys(adminsChatData)[0]]: { + pendingAction: null, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, + value: { + pendingFields: { + addWorkspaceRoom: null, + }, + pendingAction: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, + value: { + [_.keys(expenseChatData)[0]]: { + pendingAction: null, + }, + }, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, + value: null, + }, + ], + } + ); + // TODO: navigate to workspace chat report +} + +export {createSaastrDemoWorkspaceAndNavigate}; diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js index d512eaff6cad..735b91a6b1d8 100644 --- a/src/pages/DemoSetupPage.js +++ b/src/pages/DemoSetupPage.js @@ -6,6 +6,7 @@ import {useFocusEffect} from '@react-navigation/native'; import ONYXKEYS from '../ONYXKEYS'; import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; import CONST from '../CONST'; +import {createSaastrDemoWorkspaceAndNavigate} from '../libs/actions/DemoActions'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -22,11 +23,10 @@ const propTypes = { * - If not, routes back to home */ function DemoSetupPage(props) { - console.log('DEMO props', props); useFocusEffect(() => { + // Depending on the route that the user hit to get here, run a specific demo flow if (props.route.name === CONST.DEMO_PAGES.SAASTR) { - // Do SaaStr demo setup here - console.log('HERE') + createSaastrDemoWorkspaceAndNavigate(); } }); From 49fb4c1844489c00e8d47430544b748a374f2ef5 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 14 Aug 2023 17:01:18 +0300 Subject: [PATCH 04/29] A few fixes to connect the new API command --- src/libs/actions/DemoActions.js | 31 +++++++++++++++++++++++-------- src/libs/actions/Policy.js | 1 + 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index a8529e9b1c20..d671c05197c2 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -1,7 +1,19 @@ +import Onyx from 'react-native-onyx'; import CONST from '../../CONST'; import * as API from '../API'; import {buildOptimisticWorkspaceChats} from '../ReportUtils'; import {buildOptimisticCustomUnits, generatePolicyID} from './Policy'; +import Navigation from '../Navigation/Navigation'; +import ROUTES from '../../ROUTES'; +import ONYXKEYS from '../../ONYXKEYS'; + +let sessionAccountID = 0; +Onyx.connect({ + key: ONYXKEYS.SESSION, + callback: (val) => { + sessionAccountID = lodashGet(val, 'accountID', 0); + }, +}); function createSaastrDemoWorkspaceAndNavigate() { // Create workspace, owned and admin'd by SaaStr @@ -17,18 +29,17 @@ function createSaastrDemoWorkspaceAndNavigate() { announceChatData, announceReportActionData, announceCreatedReportActionID, - // Commenting these out b/c user shouldn't an admin to start with, right? :think: - // adminsChatReportID, - // adminsChatData, - // adminsReportActionData, - // adminsCreatedReportActionID, + // TODO: maybe comment these admin report data out b/c user shouldn't an admin to start with, right? :think: + adminsChatReportID, + adminsChatData, + adminsReportActionData, + adminsCreatedReportActionID, expenseChatReportID, expenseChatData, expenseReportActionData, expenseCreatedReportActionID, } = buildOptimisticWorkspaceChats(policyID, workspaceName); - // TODO: Add this user to workspace as a member // TODO: Add optimistic invite message comment // TODO: Make sure a specific reimbursement account is tied to the workspace // TODO: Is it fine if the expense chat report is OWNED by the user instead of saastr here? @@ -61,7 +72,7 @@ function createSaastrDemoWorkspaceAndNavigate() { name: workspaceName, role: CONST.POLICY.ROLE.USER, owner: CONST.EMAIL.SAASTR, - outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), + outputCurrency: CONST.CURRENCY.USD, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, customUnits, }, @@ -229,7 +240,11 @@ function createSaastrDemoWorkspaceAndNavigate() { ], } ); - // TODO: navigate to workspace chat report + + // Navigate to the new workspace chat report + // We must call goBack() to remove the /saastr route from history + Navigation.goBack(); + Navigation.navigate(ROUTES.getWorkspaceInitialRoute(policyID)); } export {createSaastrDemoWorkspaceAndNavigate}; diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 809491c14950..873eb01b17a0 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1202,4 +1202,5 @@ export { setWorkspaceInviteMembersDraft, isPolicyOwner, clearErrors, + buildOptimisticCustomUnits, }; From 0507a0ff97002aaa48e9ff148f2cf9add5b78d6a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 14 Aug 2023 18:41:13 +0300 Subject: [PATCH 05/29] Add ability to run specific demo by initial URL --- src/Expensify.js | 11 +++++++++-- src/ONYXKEYS.js | 3 +++ src/languages/en.js | 5 +++++ src/languages/es.js | 5 +++++ src/libs/actions/App.js | 19 +++++++++++++++++++ src/pages/signin/SignInPage.js | 19 +++++++++++++++++-- 6 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/Expensify.js b/src/Expensify.js index c85c2862e96e..3d6f7a861663 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -31,6 +31,7 @@ import SplashScreenHider from './components/SplashScreenHider'; import KeyboardShortcutsModal from './components/KeyboardShortcutsModal'; import EmojiPicker from './components/EmojiPicker/EmojiPicker'; import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; +import {runDemoByURL} from './libs/actions/App'; // This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection // eslint-disable-next-line no-unused-vars @@ -163,10 +164,16 @@ function Expensify(props) { appStateChangeListener.current = AppState.addEventListener('change', initializeClient); // 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) => Report.openReportFromDeepLink(url, isAuthenticated)); + Linking.getInitialURL().then((url) => { + runDemoByURL(url); + Report.openReportFromDeepLink(url, isAuthenticated); + }); // Open chat report from a deep link (only mobile native) - Linking.addEventListener('url', (state) => Report.openReportFromDeepLink(state.url, isAuthenticated)); + Linking.addEventListener('url', (state) => { + runDemoByURL(state.url); + Report.openReportFromDeepLink(state.url, isAuthenticated); + }); return () => { if (!appStateChangeListener.current) { diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index a99a09063561..b6bc97c4e555 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -263,4 +263,7 @@ export default { // Receipt upload modal RECEIPT_MODAL: 'receiptModal', + + // Information on any active demos being run + DEMO_INFO: 'demoInfo', }; diff --git a/src/languages/en.js b/src/languages/en.js index 09651e6ec05e..78e8e69211d3 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1591,4 +1591,9 @@ export default { stateSelectorModal: { placeholderText: 'Search to see options', }, + demos: { + saastr: { + signInWelcome: 'Welcome to SaaStr! Hop in to start networking now.', + } + } }; diff --git a/src/languages/es.js b/src/languages/es.js index fa920c84ce35..2af31340cf9c 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -2063,4 +2063,9 @@ export default { stateSelectorModal: { placeholderText: 'Buscar para ver opciones', }, + demos: { + saastr: { + signInWelcome: '', + } + } }; diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index fe2c908dfd0b..18f5254346f8 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -437,6 +437,24 @@ function beginDeepLinkRedirectAfterTransition() { waitForSignOnTransitionToFinish().then(beginDeepLinkRedirect); } +/** + * 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 = '') { + if (url.endsWith(ROUTES.SAASTR)) { + Onyx.merge(ONYXKEYS.DEMO_INFO, { + saastr: { + isBeginningDemo: true, + } + }) + } else { + // No demo is being run, so clear out demo info + Onyx.set(ONYXKEYS.DEMO_INFO, null); + } +} + export { setLocale, setLocaleAndNavigate, @@ -449,4 +467,5 @@ export { beginDeepLinkRedirect, beginDeepLinkRedirectAfterTransition, createWorkspaceAndNavigateToIt, + runDemoByURL }; diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index f6eb4f9306f3..f46595daea60 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -45,11 +45,19 @@ const propTypes = { twoFactorAuthCode: PropTypes.string, validateCode: PropTypes.string, }), + + /** Information about any currently running demos */ + demoInfo: PropTypes.shape({ + saastr: PropTypes.shape({ + isBeginningDemo: PropTypes.bool, + }), + }), }; const defaultProps = { account: {}, credentials: {}, + demoInfo: {}, }; /** @@ -77,7 +85,7 @@ function getRenderOptions({hasLogin, hasValidateCode, hasAccount, isPrimaryLogin }; } -function SignInPage({credentials, account}) { +function SignInPage({credentials, account, demoInfo}) { const {translate, formatPhoneNumber} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); const safeAreaInsets = useSafeAreaInsets(); @@ -102,7 +110,13 @@ function SignInPage({credentials, account}) { let welcomeText = ''; if (shouldShowLoginForm) { welcomeHeader = isSmallScreenWidth ? translate('login.hero.header') : translate('welcomeText.getStarted'); - welcomeText = isSmallScreenWidth ? translate('welcomeText.getStarted') : ''; + + if (demoInfo.saastr && demoInfo.saastr.isBeginningDemo) { + welcomeText = translate('demos.saastr.signInWelcome'); + } else { + welcomeText = isSmallScreenWidth ? translate('welcomeText.getStarted') : ''; + } + } else if (shouldShowValidateCodeForm) { if (account.requiresTwoFactorAuth) { // We will only know this after a user signs in successfully, without their 2FA code @@ -165,4 +179,5 @@ SignInPage.displayName = 'SignInPage'; export default withOnyx({ account: {key: ONYXKEYS.ACCOUNT}, credentials: {key: ONYXKEYS.CREDENTIALS}, + demoInfo: {key: ONYXKEYS.DEMO_INFO}, })(SignInPage); From a3f7564a22f4baf2e64fab93b69cecaa8f8e3366 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 10:17:50 +0300 Subject: [PATCH 06/29] Fix customizing the header --- src/pages/signin/SignInPage.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index f46595daea60..2617aad1d630 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -110,13 +110,11 @@ function SignInPage({credentials, account, demoInfo}) { let welcomeText = ''; if (shouldShowLoginForm) { welcomeHeader = isSmallScreenWidth ? translate('login.hero.header') : translate('welcomeText.getStarted'); + welcomeText = isSmallScreenWidth ? translate('welcomeText.getStarted') : ''; if (demoInfo.saastr && demoInfo.saastr.isBeginningDemo) { - welcomeText = translate('demos.saastr.signInWelcome'); - } else { - welcomeText = isSmallScreenWidth ? translate('welcomeText.getStarted') : ''; + welcomeHeader = translate('demos.saastr.signInWelcome'); } - } else if (shouldShowValidateCodeForm) { if (account.requiresTwoFactorAuth) { // We will only know this after a user signs in successfully, without their 2FA code From 24843e6251e31d967e123b17a31584a38ac28c5a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 11:30:40 +0300 Subject: [PATCH 07/29] New util to get workspace chat report from policy owner --- src/libs/ReportUtils.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ab8537d2bcdd..951e93fa99c3 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2884,6 +2884,19 @@ function getPolicy(policyID) { return policy; } +/** + * @param {String} policyOwner + * @returns {String|null} + */ +function getPolicyExpenseChatReportIDByOwner(policyOwner) { + const policy = _.find(allPolicies, (policy) => policy.owner === policyOwner); + if (!policy) { + return null; + } + + return _find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policy.id); +} + /* * @param {Object|null} report * @returns {Boolean} @@ -3148,6 +3161,7 @@ export { getReportOfflinePendingActionAndErrors, isDM, getPolicy, + getPolicyExpenseChatReportIDByOwner, shouldDisableSettings, shouldDisableRename, hasSingleParticipant, From 247a58ac87cfa8d17666aed3b1f23e302c00c04b Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 11:31:04 +0300 Subject: [PATCH 08/29] Lookup workspace chat first & add workspace name prefix --- src/libs/actions/DemoActions.js | 34 +++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index d671c05197c2..fe237f5a1b25 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -1,26 +1,52 @@ +import Str from 'expensify-common/lib/str'; import Onyx from 'react-native-onyx'; +import lodashGet from 'lodash/get'; import CONST from '../../CONST'; import * as API from '../API'; -import {buildOptimisticWorkspaceChats} from '../ReportUtils'; +import {buildOptimisticWorkspaceChats, getPolicyExpenseChatReportIDByOwner} from '../ReportUtils'; import {buildOptimisticCustomUnits, generatePolicyID} from './Policy'; import Navigation from '../Navigation/Navigation'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; let sessionAccountID = 0; +let sessionEmail = 0; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { sessionAccountID = lodashGet(val, 'accountID', 0); + sessionEmail = lodashGet(val, 'email', ''); }, }); +let userIsFromPublicDomain; +Onyx.connect({ + key: ONYXKEYS.USER, + callback: (val) => { + if (!val) { + return; + } + + userIsFromPublicDomain = val.isFromPublicDomain; + } +}) + function createSaastrDemoWorkspaceAndNavigate() { + // Try to navigate to existing SaaStr expense chat if it exists in Onyx + const saastrWorkspaceChatReportID = getPolicyExpenseChatReportIDByOwner(CONST.EMAIL.SAASTR); + if (saastrWorkspaceChatReportID) { + // We must call goBack() to remove the /saastr route from history + Navigation.goBack(); + Navigation.navigate(ROUTES.getReportRoute(saastrWorkspaceChatReportID)); + return; + } + // Create workspace, owned and admin'd by SaaStr const policyID = generatePolicyID(); - // TODO: maybe add domain name as prefix?? - const workspaceName = 'SaaStr Cantina'; + // Add domain name as prefix (only if domain is private) + const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; + const workspaceName = `${domainNamePrefix}SaaStr Workspace`; const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(); @@ -244,7 +270,7 @@ function createSaastrDemoWorkspaceAndNavigate() { // Navigate to the new workspace chat report // We must call goBack() to remove the /saastr route from history Navigation.goBack(); - Navigation.navigate(ROUTES.getWorkspaceInitialRoute(policyID)); + Navigation.navigate(ROUTES.getReportRoute(expenseChatReportID)); } export {createSaastrDemoWorkspaceAndNavigate}; From 0b32e91742d13dc5b63d7a4beb76430492ed5341 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 11:59:34 +0300 Subject: [PATCH 09/29] Add optimistic welcome message when creating workspace chat --- src/libs/actions/DemoActions.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index fe237f5a1b25..6f2ad6ba2f7d 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -3,7 +3,7 @@ import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; import CONST from '../../CONST'; import * as API from '../API'; -import {buildOptimisticWorkspaceChats, getPolicyExpenseChatReportIDByOwner} from '../ReportUtils'; +import {buildOptimisticWorkspaceChats, buildOptimisticAddCommentReportAction, getPolicyExpenseChatReportIDByOwner} from '../ReportUtils'; import {buildOptimisticCustomUnits, generatePolicyID} from './Policy'; import Navigation from '../Navigation/Navigation'; import ROUTES from '../../ROUTES'; @@ -66,7 +66,29 @@ function createSaastrDemoWorkspaceAndNavigate() { expenseCreatedReportActionID, } = buildOptimisticWorkspaceChats(policyID, workspaceName); - // TODO: Add optimistic invite message comment + // Add optimistic invite message comment + const initialMessageText = ` + Welcome to NewExpensify, who wants $20? + + To scan the receipt and get paid: + 1. Click the + + 2. Click Request Money. + 3. Take a photo of the receipt, we'll automatically enter all the info. + 4. Come say hi at the Expensify booth (#601) and let us know if you have any feedback! + `; + // TODO: make sure this comes FROM saastr!! + const welcomeMessageReportAction = buildOptimisticAddCommentReportAction(initialMessageText); + + // Update policy expense chat report actions with welcome message from saastr + expenseReportActionData[welcomeMessageReportAction.reportAction.reportActionID] = welcomeMessageReportAction.reportAction; + + // Update report with info about last message sent + const currentTime = DateUtils.getDBTime(); + expenseChatData.lastVisibleActionCreated = currentTime, + expenseChatData.lastMessageText = initialMessageText, + expenseChatData.lastActorAccountID = CONST.ACCOUNT_ID.SAASTR, + expenseChatData.lastReadTime = currentTime, + // TODO: Make sure a specific reimbursement account is tied to the workspace // TODO: Is it fine if the expense chat report is OWNED by the user instead of saastr here? From 24f4e367c28d3f63de0f1f5e5d7775df61e7ea62 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 12:05:56 +0300 Subject: [PATCH 10/29] A few fixes & remove a few TODOs --- src/libs/actions/DemoActions.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 6f2ad6ba2f7d..5eeabac77142 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -84,16 +84,10 @@ function createSaastrDemoWorkspaceAndNavigate() { // Update report with info about last message sent const currentTime = DateUtils.getDBTime(); - expenseChatData.lastVisibleActionCreated = currentTime, - expenseChatData.lastMessageText = initialMessageText, - expenseChatData.lastActorAccountID = CONST.ACCOUNT_ID.SAASTR, - expenseChatData.lastReadTime = currentTime, - - // TODO: Make sure a specific reimbursement account is tied to the workspace - // TODO: Is it fine if the expense chat report is OWNED by the user instead of saastr here? - - // should all of the "Created" report actions (for each room) be OWNED by saastr or user? - // - it shouldn't actually matter, we don't show anything + expenseChatData.lastVisibleActionCreated = currentTime; + expenseChatData.lastMessageText = initialMessageText; + expenseChatData.lastActorAccountID = CONST.ACCOUNT_ID.SAASTR; + expenseChatData.lastReadTime = currentTime; API.write( 'CreateSaastrDemoWorkspace', From 2556d2f2e8013e94a536fa0629f3ae37b01a0f11 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 12:15:30 +0300 Subject: [PATCH 11/29] Make sure welcome message comes from SaaStr --- src/libs/actions/DemoActions.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 5eeabac77142..fef5e765ef1d 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -26,7 +26,6 @@ Onyx.connect({ if (!val) { return; } - userIsFromPublicDomain = val.isFromPublicDomain; } }) @@ -76,8 +75,10 @@ function createSaastrDemoWorkspaceAndNavigate() { 3. Take a photo of the receipt, we'll automatically enter all the info. 4. Come say hi at the Expensify booth (#601) and let us know if you have any feedback! `; - // TODO: make sure this comes FROM saastr!! const welcomeMessageReportAction = buildOptimisticAddCommentReportAction(initialMessageText); + welcomeMessageReportAction.reportAction.actorAccountID = CONST.ACCOUNT_ID.SAASTR; + welcomeMessageReportAction.reportAction.person[0].text = 'SaaStr 2023'; + welcomeMessageReportAction.reportAction.avatar = ''; // Update policy expense chat report actions with welcome message from saastr expenseReportActionData[welcomeMessageReportAction.reportAction.reportActionID] = welcomeMessageReportAction.reportAction; From e812d10a11291a5e417ec7303f2ba0ca22707834 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 12:18:26 +0300 Subject: [PATCH 12/29] Add saastr acct num --- src/CONST.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index e35926a78fc7..e4715eb43a9c 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -865,7 +865,7 @@ const CONST = { QA_TRAVIS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA_TRAVIS', 8595733)), RECEIPTS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1)), REWARDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767)), // rewards@expensify.com - SAASTR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SAASTR', -1)), + SAASTR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SAASTR', 15252830)), STUDENT_AMBASSADOR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956)), SVFG: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843)), }, From 2d3d3a3e2b5f8a46a158853e2ec159703cfdb80a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 12:25:46 +0300 Subject: [PATCH 13/29] prettify --- src/languages/en.js | 4 ++-- src/languages/es.js | 4 ++-- src/libs/Navigation/linkingConfig.js | 2 +- src/libs/actions/App.js | 6 +++--- src/libs/actions/DemoActions.js | 6 +++--- src/pages/signin/SignInPage.js | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index ee6a5893019c..c15e0a66b387 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1595,6 +1595,6 @@ export default { demos: { saastr: { signInWelcome: 'Welcome to SaaStr! Hop in to start networking now.', - } - } + }, + }, }; diff --git a/src/languages/es.js b/src/languages/es.js index 7511ec1e17e5..c150972aa750 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -2067,6 +2067,6 @@ export default { demos: { saastr: { signInWelcome: '', - } - } + }, + }, }; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 1a2bcc164bd0..d583d9c5bc13 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -23,7 +23,7 @@ export default { [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: { screens: { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID, - [CONST.DEMO_PAGES.SAASTR]: ROUTES.SAASTR + [CONST.DEMO_PAGES.SAASTR]: ROUTES.SAASTR, }, }, [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index b7ae9f7272d6..41b617379664 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -447,8 +447,8 @@ function runDemoByURL(url = '') { Onyx.merge(ONYXKEYS.DEMO_INFO, { saastr: { isBeginningDemo: true, - } - }) + }, + }); } else { // No demo is being run, so clear out demo info Onyx.set(ONYXKEYS.DEMO_INFO, null); @@ -467,5 +467,5 @@ export { beginDeepLinkRedirect, beginDeepLinkRedirectAfterTransition, createWorkspaceAndNavigateToIt, - runDemoByURL + runDemoByURL, }; diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index fef5e765ef1d..72169a7ce2c8 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -27,8 +27,8 @@ Onyx.connect({ return; } userIsFromPublicDomain = val.isFromPublicDomain; - } -}) + }, +}); function createSaastrDemoWorkspaceAndNavigate() { // Try to navigate to existing SaaStr expense chat if it exists in Onyx @@ -281,7 +281,7 @@ function createSaastrDemoWorkspaceAndNavigate() { value: null, }, ], - } + }, ); // Navigate to the new workspace chat report diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index 2617aad1d630..a19d1dea5faf 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -111,7 +111,7 @@ function SignInPage({credentials, account, demoInfo}) { if (shouldShowLoginForm) { welcomeHeader = isSmallScreenWidth ? translate('login.hero.header') : translate('welcomeText.getStarted'); welcomeText = isSmallScreenWidth ? translate('welcomeText.getStarted') : ''; - + if (demoInfo.saastr && demoInfo.saastr.isBeginningDemo) { welcomeHeader = translate('demos.saastr.signInWelcome'); } From 4cf57058833d40d672b813bfc01a35a99f7da290 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 15 Aug 2023 15:39:52 +0300 Subject: [PATCH 14/29] Update spanish translation --- src/languages/es.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.js b/src/languages/es.js index c150972aa750..20e215a18fe2 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -2066,7 +2066,7 @@ export default { }, demos: { saastr: { - signInWelcome: '', + signInWelcome: '¡Bienvenido a SaaStr! Entra y empieza a establecer contactos.', }, }, }; From 9be4aee96693e77de1ce0ef9d0ca8b58694acb6d Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 16 Aug 2023 04:58:38 +0300 Subject: [PATCH 15/29] Small tweaks --- src/libs/ReportUtils.js | 2 +- src/libs/actions/DemoActions.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index cb607fc9255c..a708c324b3ca 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3020,7 +3020,7 @@ function getPolicyExpenseChatReportIDByOwner(policyOwner) { return null; } - return _find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policy.id); + return _.find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policy.id); } /* diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 72169a7ce2c8..1029a92252d4 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -8,6 +8,7 @@ import {buildOptimisticCustomUnits, generatePolicyID} from './Policy'; import Navigation from '../Navigation/Navigation'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; +import DateUtils from '../DateUtils'; let sessionAccountID = 0; let sessionEmail = 0; From 5451be69e4f66bfd1496bfec7e791a208eb2f348 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 16 Aug 2023 11:32:12 +0300 Subject: [PATCH 16/29] Fixing up lint errors --- src/Expensify.js | 6 +++--- src/libs/ReportUtils.js | 6 +++--- src/libs/actions/DemoActions.js | 15 ++++++++------- src/pages/DemoSetupPage.js | 5 ++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Expensify.js b/src/Expensify.js index 3d6f7a861663..fd34f836d3ed 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -31,7 +31,7 @@ import SplashScreenHider from './components/SplashScreenHider'; import KeyboardShortcutsModal from './components/KeyboardShortcutsModal'; import EmojiPicker from './components/EmojiPicker/EmojiPicker'; import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; -import {runDemoByURL} from './libs/actions/App'; +import * as App from './libs/actions/App'; // This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection // eslint-disable-next-line no-unused-vars @@ -165,13 +165,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) => { - runDemoByURL(url); + App.runDemoByURL(url); Report.openReportFromDeepLink(url, isAuthenticated); }); // Open chat report from a deep link (only mobile native) Linking.addEventListener('url', (state) => { - runDemoByURL(state.url); + App.runDemoByURL(state.url); Report.openReportFromDeepLink(state.url, isAuthenticated); }); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index bce20cbb43f2..4386e9dc09a6 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3005,12 +3005,12 @@ function getPolicy(policyID) { * @returns {String|null} */ function getPolicyExpenseChatReportIDByOwner(policyOwner) { - const policy = _.find(allPolicies, (policy) => policy.owner === policyOwner); - if (!policy) { + const policyWithOwner = _.find(allPolicies, (policy) => policy.owner === policyOwner); + if (!policyWithOwner) { return null; } - return _.find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policy.id); + return _.find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policyWithOwner.id); } /* diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 1029a92252d4..c8b734ad59e7 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -1,10 +1,11 @@ import Str from 'expensify-common/lib/str'; import Onyx from 'react-native-onyx'; +import _ from 'underscore'; import lodashGet from 'lodash/get'; import CONST from '../../CONST'; import * as API from '../API'; -import {buildOptimisticWorkspaceChats, buildOptimisticAddCommentReportAction, getPolicyExpenseChatReportIDByOwner} from '../ReportUtils'; -import {buildOptimisticCustomUnits, generatePolicyID} from './Policy'; +import * as ReportUtils from '../ReportUtils'; +import * as Policy from './Policy'; import Navigation from '../Navigation/Navigation'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; @@ -33,7 +34,7 @@ Onyx.connect({ function createSaastrDemoWorkspaceAndNavigate() { // Try to navigate to existing SaaStr expense chat if it exists in Onyx - const saastrWorkspaceChatReportID = getPolicyExpenseChatReportIDByOwner(CONST.EMAIL.SAASTR); + const saastrWorkspaceChatReportID = ReportUtils.getPolicyExpenseChatReportIDByOwner(CONST.EMAIL.SAASTR); if (saastrWorkspaceChatReportID) { // We must call goBack() to remove the /saastr route from history Navigation.goBack(); @@ -42,13 +43,13 @@ function createSaastrDemoWorkspaceAndNavigate() { } // Create workspace, owned and admin'd by SaaStr - const policyID = generatePolicyID(); + const policyID = Policy.generatePolicyID(); // Add domain name as prefix (only if domain is private) const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; const workspaceName = `${domainNamePrefix}SaaStr Workspace`; - const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(); + const {customUnits, customUnitID, customUnitRateID} = Policy.buildOptimisticCustomUnits(); const { announceChatReportID, @@ -64,7 +65,7 @@ function createSaastrDemoWorkspaceAndNavigate() { expenseChatData, expenseReportActionData, expenseCreatedReportActionID, - } = buildOptimisticWorkspaceChats(policyID, workspaceName); + } = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName); // Add optimistic invite message comment const initialMessageText = ` @@ -76,7 +77,7 @@ function createSaastrDemoWorkspaceAndNavigate() { 3. Take a photo of the receipt, we'll automatically enter all the info. 4. Come say hi at the Expensify booth (#601) and let us know if you have any feedback! `; - const welcomeMessageReportAction = buildOptimisticAddCommentReportAction(initialMessageText); + const welcomeMessageReportAction = ReportUtils.buildOptimisticAddCommentReportAction(initialMessageText); welcomeMessageReportAction.reportAction.actorAccountID = CONST.ACCOUNT_ID.SAASTR; welcomeMessageReportAction.reportAction.person[0].text = 'SaaStr 2023'; welcomeMessageReportAction.reportAction.avatar = ''; diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js index 735b91a6b1d8..5bf9a6a68f2f 100644 --- a/src/pages/DemoSetupPage.js +++ b/src/pages/DemoSetupPage.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import React from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; @@ -6,7 +5,7 @@ import {useFocusEffect} from '@react-navigation/native'; import ONYXKEYS from '../ONYXKEYS'; import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; import CONST from '../CONST'; -import {createSaastrDemoWorkspaceAndNavigate} from '../libs/actions/DemoActions'; +import * as DemoActions from '../libs/actions/DemoActions'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -26,7 +25,7 @@ function DemoSetupPage(props) { useFocusEffect(() => { // Depending on the route that the user hit to get here, run a specific demo flow if (props.route.name === CONST.DEMO_PAGES.SAASTR) { - createSaastrDemoWorkspaceAndNavigate(); + DemoActions.createSaastrDemoWorkspaceAndNavigate(); } }); From 1b56731b29bb720072005c19fcb4151cc81947da Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 17 Aug 2023 15:30:12 +0300 Subject: [PATCH 17/29] Remove admin rooms, send welcome report action id --- src/libs/actions/DemoActions.js | 55 ++------------------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index c8b734ad59e7..094d74402f1a 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -56,11 +56,6 @@ function createSaastrDemoWorkspaceAndNavigate() { announceChatData, announceReportActionData, announceCreatedReportActionID, - // TODO: maybe comment these admin report data out b/c user shouldn't an admin to start with, right? :think: - adminsChatReportID, - adminsChatData, - adminsReportActionData, - adminsCreatedReportActionID, expenseChatReportID, expenseChatData, expenseReportActionData, @@ -83,7 +78,8 @@ function createSaastrDemoWorkspaceAndNavigate() { welcomeMessageReportAction.reportAction.avatar = ''; // Update policy expense chat report actions with welcome message from saastr - expenseReportActionData[welcomeMessageReportAction.reportAction.reportActionID] = welcomeMessageReportAction.reportAction; + const expenseChatWelcomeReportActionID = welcomeMessageReportAction.reportAction.reportActionID; + expenseReportActionData[expenseChatWelcomeReportActionID] = welcomeMessageReportAction.reportAction; // Update report with info about last message sent const currentTime = DateUtils.getDBTime(); @@ -97,12 +93,11 @@ function createSaastrDemoWorkspaceAndNavigate() { { policyID, announceChatReportID, - adminsChatReportID, expenseChatReportID, policyName: workspaceName, announceCreatedReportActionID, - adminsCreatedReportActionID, expenseCreatedReportActionID, + expenseChatWelcomeReportActionID, customUnitID, customUnitRateID, }, @@ -151,21 +146,6 @@ function createSaastrDemoWorkspaceAndNavigate() { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, value: announceReportActionData, }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, - value: { - pendingFields: { - addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }, - ...adminsChatData, - }, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, - value: adminsReportActionData, - }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, @@ -207,25 +187,6 @@ function createSaastrDemoWorkspaceAndNavigate() { }, }, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, - value: { - pendingFields: { - addWorkspaceRoom: null, - }, - pendingAction: null, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, - value: { - [_.keys(adminsChatData)[0]]: { - pendingAction: null, - }, - }, - }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, @@ -262,16 +223,6 @@ function createSaastrDemoWorkspaceAndNavigate() { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, value: null, }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${adminsChatReportID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`, - value: null, - }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, From 453ff522c8abc9d61ab6eb99f2c99c3d0fb21f69 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 21 Aug 2023 13:29:14 +0300 Subject: [PATCH 18/29] Remove duplicate demo page setup --- src/ROUTES.js | 1 - src/languages/en.js | 1 - src/languages/es.js | 1 - src/libs/Navigation/AppNavigator/PublicScreens.js | 6 ------ src/libs/Navigation/linkingConfig.js | 1 - 5 files changed, 10 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 0d82ec8383c2..d2a9884cfacf 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -25,7 +25,6 @@ export default { return `bank-account/${stepToOpen}?policyID=${policyID}${backToParam}`; }, HOME: '', - SAASTR_HOME: 'saastr', SETTINGS: 'settings', SETTINGS_PROFILE: 'settings/profile', SETTINGS_SHARE_CODE: 'settings/shareCode', diff --git a/src/languages/en.js b/src/languages/en.js index 3fd2a2e1904e..1929cf3c36a8 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -248,7 +248,6 @@ export default { hero: { header: 'Split bills, request payments, and chat with friends.', body: 'Welcome to the future of Expensify, your new go-to place for financial collaboration with friends and teammates alike.', - demoHeadline: 'Welcome to SaaStr! Hop in to start networking now.', }, }, thirdPartySignIn: { diff --git a/src/languages/es.js b/src/languages/es.js index bf1a9014e000..01422e0658f2 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -247,7 +247,6 @@ export default { hero: { header: 'Divida las facturas, solicite pagos y chatee con sus amigos.', body: 'Bienvenido al futuro de Expensify, tu nuevo lugar de referencia para la colaboración financiera con amigos y compañeros de equipo por igual.', - demoHeadline: '¡Bienvenido a SaaStr! Entra y empieza a establecer contactos.', }, }, thirdPartySignIn: { diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js index e78e3179d4ac..7a87530a2d9e 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.js +++ b/src/libs/Navigation/AppNavigator/PublicScreens.js @@ -1,7 +1,6 @@ import React from 'react'; import {createStackNavigator} from '@react-navigation/stack'; import SignInPage from '../../../pages/signin/SignInPage'; -import DemoSetupPage from '../../../pages/signin/DemoSetupPage'; import ValidateLoginPage from '../../../pages/ValidateLoginPage'; import LogInWithShortLivedAuthTokenPage from '../../../pages/LogInWithShortLivedAuthTokenPage'; import SCREENS from '../../../SCREENS'; @@ -20,11 +19,6 @@ function PublicScreens() { options={defaultScreenOptions} component={SignInPage} /> - Date: Mon, 21 Aug 2023 14:43:03 +0300 Subject: [PATCH 19/29] Add similar SBE demo workflow --- .env.example | 1 + src/CONST.js | 7 +++++++ src/ROUTES.js | 1 + src/languages/en.js | 3 +++ src/languages/es.js | 3 +++ .../AppNavigator/Navigators/CentralPaneNavigator.js | 8 ++++++++ src/libs/Navigation/linkingConfig.js | 1 + src/libs/actions/App.js | 11 +++++++++++ src/libs/actions/DemoActions.js | 9 ++++++++- src/pages/DemoSetupPage.js | 2 ++ 10 files changed, 45 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index d3bc11ec3024..601813eeab98 100644 --- a/.env.example +++ b/.env.example @@ -27,5 +27,6 @@ EXPENSIFY_ACCOUNT_ID_QA_TRAVIS=-1 EXPENSIFY_ACCOUNT_ID_RECEIPTS=-1 EXPENSIFY_ACCOUNT_ID_REWARDS=-1 EXPENSIFY_ACCOUNT_ID_SAASTR=-1 +EXPENSIFY_ACCOUNT_ID_SBE=-1 EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR=-1 EXPENSIFY_ACCOUNT_ID_SVFG=-1 diff --git a/src/CONST.js b/src/CONST.js index 9205c9fe374a..261b0528b3f9 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -860,6 +860,7 @@ const CONST = { QA_TRAVIS: 'qa+travisreceipts@expensify.com', RECEIPTS: 'receipts@expensify.com', SAASTR: 'saastr@expensify.com', + SBE: 'sbe@expensify.com', STUDENT_AMBASSADOR: 'studentambassadors@expensify.com', SVFG: 'svfg@expensify.com', }, @@ -880,6 +881,7 @@ const CONST = { RECEIPTS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1)), REWARDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767)), // rewards@expensify.com SAASTR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SAASTR', 15252830)), + SBE: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SBE', -1)), // TODO: replace with prod account ID STUDENT_AMBASSADOR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956)), SVFG: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843)), }, @@ -1211,6 +1213,8 @@ const CONST = { this.EMAIL.QA, this.EMAIL.QA_TRAVIS, this.EMAIL.RECEIPTS, + this.EMAIL.SAASTR, + this.EMAIL.SBE, this.EMAIL.STUDENT_AMBASSADOR, this.EMAIL.SVFG, ]; @@ -1231,6 +1235,8 @@ const CONST = { this.ACCOUNT_ID.QA_TRAVIS, this.ACCOUNT_ID.RECEIPTS, this.ACCOUNT_ID.REWARDS, + this.ACCOUNT_ID.SAASTR, + this.ACCOUNT_ID.SBE, this.ACCOUNT_ID.STUDENT_AMBASSADOR, this.ACCOUNT_ID.SVFG, ]; @@ -2568,6 +2574,7 @@ const CONST = { }, DEMO_PAGES: { SAASTR: 'SaaStrDemoSetup', + SBE: 'SbeDemoSetup', }, }; diff --git a/src/ROUTES.js b/src/ROUTES.js index d2a9884cfacf..0aae086522fa 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -183,6 +183,7 @@ export default { // These are some on-off routes that will be removed once they're no longer needed (see GH issues for details) SAASTR: 'saastr', + SBE: 'sbe', /** * @param {String} route diff --git a/src/languages/en.js b/src/languages/en.js index 1929cf3c36a8..9b5f5d2fecc1 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1626,5 +1626,8 @@ export default { saastr: { signInWelcome: 'Welcome to SaaStr! Hop in to start networking now.', }, + sbe: { + signInWelcome: 'Welcome to Small Business Expo! Get paid back for your ride.', + }, }, }; diff --git a/src/languages/es.js b/src/languages/es.js index 01422e0658f2..15f1d22fa2a6 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -2113,5 +2113,8 @@ export default { saastr: { signInWelcome: '¡Bienvenido a SaaStr! Entra y empieza a establecer contactos.', }, + sbe: { + signInWelcome: '¡Bienvenido a Small Business Expo! Recupera el dinero de tu viaje.', + }, }, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js index 47880ba14470..f685497e477b 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js @@ -38,6 +38,14 @@ function CentralPaneNavigator() { }} component={DemoSetupPage} /> + ); diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index a3a5ce902c69..a0e394dd3863 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -27,6 +27,7 @@ export default { screens: { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID, [CONST.DEMO_PAGES.SAASTR]: ROUTES.SAASTR, + [CONST.DEMO_PAGES.SBE]: ROUTES.SBE, }, }, [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 954d8470a146..37d3597df494 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -470,12 +470,23 @@ function beginDeepLinkRedirectAfterTransition(shouldAuthenticateWithCurrentAccou * @param {String} url - URL user is navigating to via deep link (or regular link in web) */ function runDemoByURL(url = '') { + if (!url) { + url = ''; + } + url = url.toLowerCase(); + if (url.endsWith(ROUTES.SAASTR)) { Onyx.merge(ONYXKEYS.DEMO_INFO, { saastr: { isBeginningDemo: true, }, }); + } else if (url.endsWith(ROUTES.SBE)) { + Onyx.merge(ONYXKEYS.DEMO_INFO, { + sbe: { + isBeginningDemo: true, + }, + }); } else { // No demo is being run, so clear out demo info Onyx.set(ONYXKEYS.DEMO_INFO, null); diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 094d74402f1a..1686ddd15954 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -32,6 +32,10 @@ Onyx.connect({ }, }); +function createSbeDemoWorkspaceAndNavigate() { + // TODO: reuse lots of code +} + function createSaastrDemoWorkspaceAndNavigate() { // Try to navigate to existing SaaStr expense chat if it exists in Onyx const saastrWorkspaceChatReportID = ReportUtils.getPolicyExpenseChatReportIDByOwner(CONST.EMAIL.SAASTR); @@ -243,4 +247,7 @@ function createSaastrDemoWorkspaceAndNavigate() { Navigation.navigate(ROUTES.getReportRoute(expenseChatReportID)); } -export {createSaastrDemoWorkspaceAndNavigate}; +export { + createSaastrDemoWorkspaceAndNavigate, + createSbeDemoWorkspaceAndNavigate, +}; diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js index 5bf9a6a68f2f..f79a5b880b28 100644 --- a/src/pages/DemoSetupPage.js +++ b/src/pages/DemoSetupPage.js @@ -26,6 +26,8 @@ function DemoSetupPage(props) { // Depending on the route that the user hit to get here, run a specific demo flow if (props.route.name === CONST.DEMO_PAGES.SAASTR) { DemoActions.createSaastrDemoWorkspaceAndNavigate(); + } else if (props.route.name === CONST.DEMO_PAGES.SBE) { + DemoActions.createSbeDemoWorkspaceAndNavigate(); } }); From db90ed0254bde7c3e4ef1dc5dbe1e712ebf11a7a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Mon, 21 Aug 2023 15:17:30 +0300 Subject: [PATCH 20/29] Refactor for new SBE flow --- src/libs/actions/DemoActions.js | 107 ++++++++++++++++++++------------ src/pages/DemoSetupPage.js | 7 ++- 2 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 1686ddd15954..e65b440e255e 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -32,29 +32,33 @@ Onyx.connect({ }, }); -function createSbeDemoWorkspaceAndNavigate() { - // TODO: reuse lots of code -} - -function createSaastrDemoWorkspaceAndNavigate() { - // Try to navigate to existing SaaStr expense chat if it exists in Onyx - const saastrWorkspaceChatReportID = ReportUtils.getPolicyExpenseChatReportIDByOwner(CONST.EMAIL.SAASTR); - if (saastrWorkspaceChatReportID) { - // We must call goBack() to remove the /saastr route from history +/** + * @param {String} workspaceOwnerEmail email of the workspace owner + * @param {String} workspaceName + * @param {String} welcomeNoteText + * @param {Number} adminAccountID + * @param {String} apiCommand + */ +function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, workspaceName, welcomeNoteText, adminAccountID, apiCommand) { + // If we don't have a command name to call, just go back so the user is navigated home + if (!apiCommand) { + Navigation.goBack(); + return; + } + + // Try to navigate to existing demo workspace expense chat if it exists in Onyx + const demoWorkspaceChatReportID = ReportUtils.getPolicyExpenseChatReportIDByOwner(workspaceOwnerEmail); + if (demoWorkspaceChatReportID) { + // We must call goBack() to remove the demo route from nav history Navigation.goBack(); - Navigation.navigate(ROUTES.getReportRoute(saastrWorkspaceChatReportID)); + Navigation.navigate(ROUTES.getReportRoute(demoWorkspaceChatReportID)); return; } - // Create workspace, owned and admin'd by SaaStr + // Create workspace, owned and admin'd by passed email const policyID = Policy.generatePolicyID(); - - // Add domain name as prefix (only if domain is private) - const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; - const workspaceName = `${domainNamePrefix}SaaStr Workspace`; - + const {customUnits, customUnitID, customUnitRateID} = Policy.buildOptimisticCustomUnits(); - const { announceChatReportID, announceChatData, @@ -67,33 +71,24 @@ function createSaastrDemoWorkspaceAndNavigate() { } = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName); // Add optimistic invite message comment - const initialMessageText = ` - Welcome to NewExpensify, who wants $20? - - To scan the receipt and get paid: - 1. Click the + - 2. Click Request Money. - 3. Take a photo of the receipt, we'll automatically enter all the info. - 4. Come say hi at the Expensify booth (#601) and let us know if you have any feedback! - `; - const welcomeMessageReportAction = ReportUtils.buildOptimisticAddCommentReportAction(initialMessageText); - welcomeMessageReportAction.reportAction.actorAccountID = CONST.ACCOUNT_ID.SAASTR; - welcomeMessageReportAction.reportAction.person[0].text = 'SaaStr 2023'; + const welcomeMessageReportAction = ReportUtils.buildOptimisticAddCommentReportAction(welcomeNoteText); + welcomeMessageReportAction.reportAction.actorAccountID = adminAccountID; + welcomeMessageReportAction.reportAction.person[0].text = ''; welcomeMessageReportAction.reportAction.avatar = ''; - // Update policy expense chat report actions with welcome message from saastr + // Update policy expense chat report actions with welcome message const expenseChatWelcomeReportActionID = welcomeMessageReportAction.reportAction.reportActionID; expenseReportActionData[expenseChatWelcomeReportActionID] = welcomeMessageReportAction.reportAction; // Update report with info about last message sent const currentTime = DateUtils.getDBTime(); expenseChatData.lastVisibleActionCreated = currentTime; - expenseChatData.lastMessageText = initialMessageText; - expenseChatData.lastActorAccountID = CONST.ACCOUNT_ID.SAASTR; + expenseChatData.lastMessageText = welcomeNoteText.replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim(); + expenseChatData.lastActorAccountID = adminAccountID; expenseChatData.lastReadTime = currentTime; API.write( - 'CreateSaastrDemoWorkspace', + apiCommand, { policyID, announceChatReportID, @@ -115,7 +110,7 @@ function createSaastrDemoWorkspaceAndNavigate() { type: CONST.POLICY.TYPE.FREE, name: workspaceName, role: CONST.POLICY.ROLE.USER, - owner: CONST.EMAIL.SAASTR, + owner: workspaceOwnerEmail, outputCurrency: CONST.CURRENCY.USD, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, customUnits, @@ -129,7 +124,7 @@ function createSaastrDemoWorkspaceAndNavigate() { role: CONST.POLICY.ROLE.USER, errors: {}, }, - [CONST.ACCOUNT_ID.SAASTR]: { + [adminAccountID]: { role: CONST.POLICY.ROLE.ADMIN, errors: {}, }, @@ -242,12 +237,48 @@ function createSaastrDemoWorkspaceAndNavigate() { ); // Navigate to the new workspace chat report - // We must call goBack() to remove the /saastr route from history + // We must call goBack() to remove the demo route from history Navigation.goBack(); Navigation.navigate(ROUTES.getReportRoute(expenseChatReportID)); } +function runSbeDemo() { + // Add domain name as prefix (only if domain is private) + const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; + const workspaceName = `${domainNamePrefix}SBE Workspace`; + + const welcomeNoteText = ` + Thanks for testing out New Expensify! + + Get paid back for your journey to or from Small Business Expo, whether you're driving yourself or catching a ride: + + 1. Click the "+" > Request money > Distance. + 2. Enter your start and end addresses. + 3. Get paid back at the IRS mileage rate of $0.655/mile! + + Note: Must submit by Thursday, September 7th, 2023. One reimbursement per person.`; + + createDemoWorkspaceAndNavigate(CONST.EMAIL.SBE, workspaceName, welcomeNoteText, CONST.ACCOUNT_ID.SBE, ''); +} + +function runSaastrDemo() { + // Add domain name as prefix (only if domain is private) + const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; + const workspaceName = `${domainNamePrefix}SaaStr Workspace`; + + const welcomeNoteText = ` + Welcome to NewExpensify, who wants $20? + + To scan the receipt and get paid: + 1. Click the + + 2. Click Request Money. + 3. Take a photo of the receipt, we'll automatically enter all the info. + 4. Come say hi at the Expensify booth (#601) and let us know if you have any feedback!`; + + createDemoWorkspaceAndNavigate(CONST.EMAIL.SAASTR, workspaceName, welcomeNoteText, CONST.ACCOUNT_ID.SAASTR, 'CreateSaastrDemoWorkspace'); +} + export { - createSaastrDemoWorkspaceAndNavigate, - createSbeDemoWorkspaceAndNavigate, + runSaastrDemo, + runSbeDemo, }; diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js index f79a5b880b28..69fad6493608 100644 --- a/src/pages/DemoSetupPage.js +++ b/src/pages/DemoSetupPage.js @@ -6,6 +6,7 @@ import ONYXKEYS from '../ONYXKEYS'; import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; import CONST from '../CONST'; import * as DemoActions from '../libs/actions/DemoActions'; +import * as Navigation from '../libs/Navigation/Navigation'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -25,9 +26,11 @@ function DemoSetupPage(props) { useFocusEffect(() => { // Depending on the route that the user hit to get here, run a specific demo flow if (props.route.name === CONST.DEMO_PAGES.SAASTR) { - DemoActions.createSaastrDemoWorkspaceAndNavigate(); + DemoActions.runSaastrDemo(); } else if (props.route.name === CONST.DEMO_PAGES.SBE) { - DemoActions.createSbeDemoWorkspaceAndNavigate(); + DemoActions.runSbeDemo(); + } else { + Navigation.goBack(); } }); From bc97f1a97fd9bf342bb5dc802a5b7fd5c33223a5 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 22 Aug 2023 10:42:32 +0300 Subject: [PATCH 21/29] Clean up url-cleaning logic --- src/libs/actions/App.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 37d3597df494..56a49cedce1a 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -470,18 +470,15 @@ function beginDeepLinkRedirectAfterTransition(shouldAuthenticateWithCurrentAccou * @param {String} url - URL user is navigating to via deep link (or regular link in web) */ function runDemoByURL(url = '') { - if (!url) { - url = ''; - } - url = url.toLowerCase(); + const cleanUrl = (url || '').toLowerCase(); - if (url.endsWith(ROUTES.SAASTR)) { + if (cleanUrl.endsWith(ROUTES.SAASTR)) { Onyx.merge(ONYXKEYS.DEMO_INFO, { saastr: { isBeginningDemo: true, }, }); - } else if (url.endsWith(ROUTES.SBE)) { + } else if (cleanUrl.endsWith(ROUTES.SBE)) { Onyx.merge(ONYXKEYS.DEMO_INFO, { sbe: { isBeginningDemo: true, From f4d1ff461346c9b49ed39b2705a496f22e7e5982 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 22 Aug 2023 10:46:22 +0300 Subject: [PATCH 22/29] Add sbe account number --- src/CONST.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index dd656cea68a9..dcf573bdb684 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -889,7 +889,7 @@ const CONST = { RECEIPTS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1)), REWARDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767)), // rewards@expensify.com SAASTR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SAASTR', 15252830)), - SBE: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SBE', -1)), // TODO: replace with prod account ID + SBE: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SBE', 15305309)), STUDENT_AMBASSADOR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956)), SVFG: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843)), }, From a2bda8c417817f0ff2f0800b7a1aa4ac853791d1 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 22 Aug 2023 14:02:58 +0300 Subject: [PATCH 23/29] Move fn to DemoActions, remove optimistic data --- src/Expensify.js | 6 +- src/libs/actions/App.js | 27 ---- src/libs/actions/DemoActions.js | 265 ++++++-------------------------- src/pages/signin/SignInPage.js | 6 +- 4 files changed, 51 insertions(+), 253 deletions(-) diff --git a/src/Expensify.js b/src/Expensify.js index db2e844d4a85..a3eb87ddb9a3 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -30,7 +30,7 @@ import KeyboardShortcutsModal from './components/KeyboardShortcutsModal'; import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper'; import EmojiPicker from './components/EmojiPicker/EmojiPicker'; import * as EmojiPickerAction from './libs/actions/EmojiPickerAction'; -import * as App from './libs/actions/App'; +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 @@ -165,13 +165,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) => { - App.runDemoByURL(url); + DemoActions.runDemoByURL(url); Report.openReportFromDeepLink(url, isAuthenticated); }); // Open chat report from a deep link (only mobile native) Linking.addEventListener('url', (state) => { - App.runDemoByURL(state.url); + DemoActions.runDemoByURL(state.url); Report.openReportFromDeepLink(state.url, isAuthenticated); }); diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 56a49cedce1a..46d21d50cc3e 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -464,32 +464,6 @@ function beginDeepLinkRedirectAfterTransition(shouldAuthenticateWithCurrentAccou waitForSignOnTransitionToFinish().then(() => beginDeepLinkRedirect(shouldAuthenticateWithCurrentAccount)); } -/** - * 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.SAASTR)) { - Onyx.merge(ONYXKEYS.DEMO_INFO, { - saastr: { - isBeginningDemo: true, - }, - }); - } else if (cleanUrl.endsWith(ROUTES.SBE)) { - Onyx.merge(ONYXKEYS.DEMO_INFO, { - sbe: { - isBeginningDemo: true, - }, - }); - } else { - // No demo is being run, so clear out demo info - Onyx.set(ONYXKEYS.DEMO_INFO, null); - } -} - export { setLocale, setLocaleAndNavigate, @@ -503,5 +477,4 @@ export { beginDeepLinkRedirect, beginDeepLinkRedirectAfterTransition, createWorkspaceAndNavigateToIt, - runDemoByURL, }; diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index e65b440e255e..bc7317d27d46 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -1,15 +1,13 @@ -import Str from 'expensify-common/lib/str'; import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import CONST from '../../CONST'; import * as API from '../API'; import * as ReportUtils from '../ReportUtils'; -import * as Policy from './Policy'; import Navigation from '../Navigation/Navigation'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; -import DateUtils from '../DateUtils'; +import * as Localize from '../Localize'; let sessionAccountID = 0; let sessionEmail = 0; @@ -34,12 +32,9 @@ Onyx.connect({ /** * @param {String} workspaceOwnerEmail email of the workspace owner - * @param {String} workspaceName - * @param {String} welcomeNoteText - * @param {Number} adminAccountID * @param {String} apiCommand */ -function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, workspaceName, welcomeNoteText, adminAccountID, apiCommand) { +function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, apiCommand) { // If we don't have a command name to call, just go back so the user is navigated home if (!apiCommand) { Navigation.goBack(); @@ -55,230 +50,62 @@ function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, workspaceName, welc return; } - // Create workspace, owned and admin'd by passed email - const policyID = Policy.generatePolicyID(); - - const {customUnits, customUnitID, customUnitRateID} = Policy.buildOptimisticCustomUnits(); - const { - announceChatReportID, - announceChatData, - announceReportActionData, - announceCreatedReportActionID, - expenseChatReportID, - expenseChatData, - expenseReportActionData, - expenseCreatedReportActionID, - } = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName); - - // Add optimistic invite message comment - const welcomeMessageReportAction = ReportUtils.buildOptimisticAddCommentReportAction(welcomeNoteText); - welcomeMessageReportAction.reportAction.actorAccountID = adminAccountID; - welcomeMessageReportAction.reportAction.person[0].text = ''; - welcomeMessageReportAction.reportAction.avatar = ''; - - // Update policy expense chat report actions with welcome message - const expenseChatWelcomeReportActionID = welcomeMessageReportAction.reportAction.reportActionID; - expenseReportActionData[expenseChatWelcomeReportActionID] = welcomeMessageReportAction.reportAction; - - // Update report with info about last message sent - const currentTime = DateUtils.getDBTime(); - expenseChatData.lastVisibleActionCreated = currentTime; - expenseChatData.lastMessageText = welcomeNoteText.replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim(); - expenseChatData.lastActorAccountID = adminAccountID; - expenseChatData.lastReadTime = currentTime; - - API.write( - apiCommand, - { - policyID, - announceChatReportID, - expenseChatReportID, - policyName: workspaceName, - announceCreatedReportActionID, - expenseCreatedReportActionID, - expenseChatWelcomeReportActionID, - customUnitID, - customUnitRateID, - }, - { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - id: policyID, - type: CONST.POLICY.TYPE.FREE, - name: workspaceName, - role: CONST.POLICY.ROLE.USER, - owner: workspaceOwnerEmail, - outputCurrency: CONST.CURRENCY.USD, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - customUnits, - }, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, - value: { - [sessionAccountID]: { - role: CONST.POLICY.ROLE.USER, - errors: {}, - }, - [adminAccountID]: { - role: CONST.POLICY.ROLE.ADMIN, - errors: {}, - }, - }, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, - value: { - pendingFields: { - addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }, - ...announceChatData, - }, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, - value: announceReportActionData, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, - value: { - pendingFields: { - addWorkspaceRoom: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }, - ...expenseChatData, - }, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, - value: expenseReportActionData, - }, - ], - successData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: {pendingAction: null}, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, - value: { - pendingFields: { - addWorkspaceRoom: null, - }, - pendingAction: null, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, - value: { - [_.keys(announceChatData)[0]]: { - pendingAction: null, - }, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, - value: { - pendingFields: { - addWorkspaceRoom: null, - }, - pendingAction: null, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, - value: { - [_.keys(expenseChatData)[0]]: { - pendingAction: null, - }, - }, - }, - ], - failureData: [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${announceChatReportID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${announceChatReportID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${expenseChatReportID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, - value: null, - }, - ], - }, - ); + API.makeRequestWithSideEffects(apiCommand, {}) + .then((response) => { + // Navigate to the new workspace chat report + // We must call goBack() to remove the demo route from history + Navigation.goBack(); + Navigation.navigate(ROUTES.getReportRoute(response.expenseChatReportID)); + }); - // Navigate to the new workspace chat report - // We must call goBack() to remove the demo route from history - Navigation.goBack(); - Navigation.navigate(ROUTES.getReportRoute(expenseChatReportID)); } function runSbeDemo() { - // Add domain name as prefix (only if domain is private) - const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; - const workspaceName = `${domainNamePrefix}SBE Workspace`; - - const welcomeNoteText = ` - Thanks for testing out New Expensify! - - Get paid back for your journey to or from Small Business Expo, whether you're driving yourself or catching a ride: - - 1. Click the "+" > Request money > Distance. - 2. Enter your start and end addresses. - 3. Get paid back at the IRS mileage rate of $0.655/mile! - - Note: Must submit by Thursday, September 7th, 2023. One reimbursement per person.`; - - createDemoWorkspaceAndNavigate(CONST.EMAIL.SBE, workspaceName, welcomeNoteText, CONST.ACCOUNT_ID.SBE, ''); + createDemoWorkspaceAndNavigate(CONST.EMAIL.SBE, ''); } function runSaastrDemo() { - // Add domain name as prefix (only if domain is private) - const domainNamePrefix = userIsFromPublicDomain ? `${Str.extractEmailDomain(sessionEmail)} ` : ''; - const workspaceName = `${domainNamePrefix}SaaStr Workspace`; - - const welcomeNoteText = ` - Welcome to NewExpensify, who wants $20? + createDemoWorkspaceAndNavigate(CONST.EMAIL.SAASTR, 'CreateSaastrDemoWorkspace'); +} - To scan the receipt and get paid: - 1. Click the + - 2. Click Request Money. - 3. Take a photo of the receipt, we'll automatically enter all the info. - 4. Come say hi at the Expensify booth (#601) and let us know if you have any feedback!`; +/** + * 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.SAASTR)) { + Onyx.set(ONYXKEYS.DEMO_INFO, { + saastr: { + isBeginningDemo: true, + }, + }); + } else if (cleanUrl.endsWith(ROUTES.SBE)) { + Onyx.set(ONYXKEYS.DEMO_INFO, { + sbe: { + isBeginningDemo: true, + }, + }); + } else { + // No demo is being run, so clear out demo info + Onyx.set(ONYXKEYS.DEMO_INFO, null); + } +} - createDemoWorkspaceAndNavigate(CONST.EMAIL.SAASTR, workspaceName, welcomeNoteText, CONST.ACCOUNT_ID.SAASTR, 'CreateSaastrDemoWorkspace'); +function getHeadlineKeyByDemoInfo(demoInfo = {}) { + if (lodashGet(demoInfo, 'saastr.isBeginningDemo')) { + return Localize.translateLocal('demos.saastr.signInWelcome'); + } else if (lodashGet(demoInfo, 'sbe.isBeginningDemo')) { + return Localize.translateLocal('demos.sbe.signInWelcome'); + } + return ''; } export { runSaastrDemo, runSbeDemo, + runDemoByURL, + getHeadlineKeyByDemoInfo, }; diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index e19b9ca7749f..79a1eaa4665a 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -19,6 +19,7 @@ import * as StyleUtils from '../../styles/StyleUtils'; import useLocalize from '../../hooks/useLocalize'; import useWindowDimensions from '../../hooks/useWindowDimensions'; import Log from '../../libs/Log'; +import * as DemoActions from '../../libs/actions/DemoActions'; const propTypes = { /** The details about the account that the user is signing in with */ @@ -113,10 +114,7 @@ function SignInPage({credentials, account, isInModal, demoInfo}) { let welcomeHeader = ''; let welcomeText = ''; - let customHeadline = ''; - if (demoInfo.saastr && demoInfo.saastr.isBeginningDemo) { - customHeadline = translate('demos.saastr.signInWelcome'); - } + let customHeadline = DemoActions.getHeadlineKeyByDemoInfo(demoInfo); const headerText = customHeadline || translate('login.hero.header'); if (shouldShowLoginForm) { welcomeHeader = isSmallScreenWidth ? headerText : translate('welcomeText.getStarted'); From 511f438bca34403b8b0940bcc888b37ab49cac4b Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 22 Aug 2023 17:56:27 +0300 Subject: [PATCH 24/29] Cleanup and correctly navigate --- src/libs/actions/DemoActions.js | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index bc7317d27d46..7170985ff505 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -35,12 +35,6 @@ Onyx.connect({ * @param {String} apiCommand */ function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, apiCommand) { - // If we don't have a command name to call, just go back so the user is navigated home - if (!apiCommand) { - Navigation.goBack(); - return; - } - // Try to navigate to existing demo workspace expense chat if it exists in Onyx const demoWorkspaceChatReportID = ReportUtils.getPolicyExpenseChatReportIDByOwner(workspaceOwnerEmail); if (demoWorkspaceChatReportID) { @@ -50,18 +44,30 @@ function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, apiCommand) { return; } - API.makeRequestWithSideEffects(apiCommand, {}) + API.makeRequestWithSideEffects(apiCommand) .then((response) => { - // Navigate to the new workspace chat report - // We must call goBack() to remove the demo route from history + // Get report updates from Onyx response data + const reportUpdate = _.find(response.onyxData, ({key}) => key === ONYXKEYS.COLLECTION.REPORT); + if (!reportUpdate) { + return; + } + + // Get the policy expense chat update + const policyExpenseChatReport = _.find(reportUpdate.value, ({chatType}) => chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT); + if (!policyExpenseChatReport) { + return; + } + + // Navigate to the new policy expense chat report + // Note: We must call goBack() to remove the demo route from history Navigation.goBack(); - Navigation.navigate(ROUTES.getReportRoute(response.expenseChatReportID)); + Navigation.navigate(ROUTES.getReportRoute(policyExpenseChatReport.reportID)); }); } function runSbeDemo() { - createDemoWorkspaceAndNavigate(CONST.EMAIL.SBE, ''); + createDemoWorkspaceAndNavigate(CONST.EMAIL.SBE, 'CreateSbeDemoWorkspace'); } function runSaastrDemo() { From 3eb170708bd1de05a0f3001a397b8c0a611486c4 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 22 Aug 2023 17:59:10 +0300 Subject: [PATCH 25/29] Lint cleanup --- src/libs/actions/DemoActions.js | 67 +++++++++++---------------------- src/pages/signin/SignInPage.js | 2 +- 2 files changed, 22 insertions(+), 47 deletions(-) diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js index 7170985ff505..aa2b43824f91 100644 --- a/src/libs/actions/DemoActions.js +++ b/src/libs/actions/DemoActions.js @@ -9,27 +9,6 @@ import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; import * as Localize from '../Localize'; -let sessionAccountID = 0; -let sessionEmail = 0; -Onyx.connect({ - key: ONYXKEYS.SESSION, - callback: (val) => { - sessionAccountID = lodashGet(val, 'accountID', 0); - sessionEmail = lodashGet(val, 'email', ''); - }, -}); - -let userIsFromPublicDomain; -Onyx.connect({ - key: ONYXKEYS.USER, - callback: (val) => { - if (!val) { - return; - } - userIsFromPublicDomain = val.isFromPublicDomain; - }, -}); - /** * @param {String} workspaceOwnerEmail email of the workspace owner * @param {String} apiCommand @@ -44,26 +23,26 @@ function createDemoWorkspaceAndNavigate(workspaceOwnerEmail, apiCommand) { return; } - API.makeRequestWithSideEffects(apiCommand) - .then((response) => { - // Get report updates from Onyx response data - const reportUpdate = _.find(response.onyxData, ({key}) => key === ONYXKEYS.COLLECTION.REPORT); - if (!reportUpdate) { - return; - } - - // Get the policy expense chat update - const policyExpenseChatReport = _.find(reportUpdate.value, ({chatType}) => chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT); - if (!policyExpenseChatReport) { - return; - } + // We use makeRequestWithSideEffects here because we need to get the workspace chat report ID to navigate to it after it's created + // eslint-disable-next-line rulesdir/no-api-side-effects-method + API.makeRequestWithSideEffects(apiCommand).then((response) => { + // Get report updates from Onyx response data + const reportUpdate = _.find(response.onyxData, ({key}) => key === ONYXKEYS.COLLECTION.REPORT); + if (!reportUpdate) { + return; + } - // Navigate to the new policy expense chat report - // Note: We must call goBack() to remove the demo route from history - Navigation.goBack(); - Navigation.navigate(ROUTES.getReportRoute(policyExpenseChatReport.reportID)); - }); + // Get the policy expense chat update + const policyExpenseChatReport = _.find(reportUpdate.value, ({chatType}) => chatType === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT); + if (!policyExpenseChatReport) { + return; + } + // Navigate to the new policy expense chat report + // Note: We must call goBack() to remove the demo route from history + Navigation.goBack(); + Navigation.navigate(ROUTES.getReportRoute(policyExpenseChatReport.reportID)); + }); } function runSbeDemo() { @@ -103,15 +82,11 @@ function runDemoByURL(url = '') { function getHeadlineKeyByDemoInfo(demoInfo = {}) { if (lodashGet(demoInfo, 'saastr.isBeginningDemo')) { return Localize.translateLocal('demos.saastr.signInWelcome'); - } else if (lodashGet(demoInfo, 'sbe.isBeginningDemo')) { + } + if (lodashGet(demoInfo, 'sbe.isBeginningDemo')) { return Localize.translateLocal('demos.sbe.signInWelcome'); } return ''; } -export { - runSaastrDemo, - runSbeDemo, - runDemoByURL, - getHeadlineKeyByDemoInfo, -}; +export {runSaastrDemo, runSbeDemo, runDemoByURL, getHeadlineKeyByDemoInfo}; diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index 79a1eaa4665a..f1a8cf3b910e 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -114,7 +114,7 @@ function SignInPage({credentials, account, isInModal, demoInfo}) { let welcomeHeader = ''; let welcomeText = ''; - let customHeadline = DemoActions.getHeadlineKeyByDemoInfo(demoInfo); + const customHeadline = DemoActions.getHeadlineKeyByDemoInfo(demoInfo); const headerText = customHeadline || translate('login.hero.header'); if (shouldShowLoginForm) { welcomeHeader = isSmallScreenWidth ? headerText : translate('welcomeText.getStarted'); From e8f719c289bafcc389df9b62cc33c35d0198334b Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 22 Aug 2023 22:14:07 +0300 Subject: [PATCH 26/29] Update src/pages/DemoSetupPage.js Co-authored-by: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> --- src/pages/DemoSetupPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js index 69fad6493608..e665e61b5088 100644 --- a/src/pages/DemoSetupPage.js +++ b/src/pages/DemoSetupPage.js @@ -6,7 +6,7 @@ import ONYXKEYS from '../ONYXKEYS'; import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; import CONST from '../CONST'; import * as DemoActions from '../libs/actions/DemoActions'; -import * as Navigation from '../libs/Navigation/Navigation'; +import Navigation from '../libs/Navigation/Navigation'; const propTypes = { /** Navigation route context info provided by react navigation */ From ac14e22c51e8b72b7bd90a7695bf612c6fbaf7b8 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 22 Aug 2023 22:39:46 +0300 Subject: [PATCH 27/29] Address feedback after review. --- src/libs/ReportUtils.js | 6 +++++- src/libs/actions/Policy.js | 1 - src/pages/DemoSetupPage.js | 8 +------- src/pages/signin/DemoSetupPage.js | 12 ------------ 4 files changed, 6 insertions(+), 21 deletions(-) delete mode 100644 src/pages/signin/DemoSetupPage.js diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index a487e3ca3896..a1b52b468735 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3115,7 +3115,11 @@ function getPolicyExpenseChatReportIDByOwner(policyOwner) { return null; } - return _.find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policyWithOwner.id); + const expenseChat = _.find(allReports, (report) => isPolicyExpenseChat(report) && report.policyID === policyWithOwner.id); + if (!expenseChat) { + return null; + } + return expenseChat; } /* diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 556a3f5f6d5d..6cc539be9503 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -1201,6 +1201,5 @@ export { removeWorkspace, setWorkspaceInviteMembersDraft, clearErrors, - buildOptimisticCustomUnits, openDraftWorkspaceRequest, }; diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js index e665e61b5088..53739820142b 100644 --- a/src/pages/DemoSetupPage.js +++ b/src/pages/DemoSetupPage.js @@ -1,8 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; import {useFocusEffect} from '@react-navigation/native'; -import ONYXKEYS from '../ONYXKEYS'; import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; import CONST from '../CONST'; import * as DemoActions from '../libs/actions/DemoActions'; @@ -40,8 +38,4 @@ function DemoSetupPage(props) { DemoSetupPage.propTypes = propTypes; DemoSetupPage.displayName = 'DemoSetupPage'; -export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, -})(DemoSetupPage); +export default DemoSetupPage; diff --git a/src/pages/signin/DemoSetupPage.js b/src/pages/signin/DemoSetupPage.js deleted file mode 100644 index f457c3a5421a..000000000000 --- a/src/pages/signin/DemoSetupPage.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import SignInPage from './SignInPage'; -import useLocalize from '../../hooks/useLocalize'; - -function DemoSetupPage() { - const {translate} = useLocalize(); - return ; -} - -DemoSetupPage.displayName = 'DemoSetupPage'; - -export default DemoSetupPage; From a32515a848c793348ef7724e0a076748ad73e73b Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 22 Aug 2023 22:56:45 +0300 Subject: [PATCH 28/29] Fix conflicts after merge. --- src/ONYXKEYS.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 3c0b3ee9a6d6..074a5e99e6b1 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -218,6 +218,9 @@ const ONYXKEYS = { // The access token to be used with the Mapbox library MAPBOX_ACCESS_TOKEN: 'mapboxAccessToken', + // Information on any active demos being run + DEMO_INFO: 'demoInfo', + /** Collection Keys */ COLLECTION: { DOWNLOAD: 'download_', From a694759c0bf3604b39e2d85f17f8051f0385a576 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 22 Aug 2023 23:19:05 +0300 Subject: [PATCH 29/29] Update src/libs/ReportUtils.js Co-authored-by: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index fa1fd1cb461b..5ba24f6ba513 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3118,7 +3118,7 @@ function getPolicyExpenseChatReportIDByOwner(policyOwner) { if (!expenseChat) { return null; } - return expenseChat; + return expenseChat.reportID; } /*