From 71aaa5aff5721ed25f670fcf990f7c48629008ac Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 13:15:45 -0700 Subject: [PATCH 01/90] Create new component --- .../PurposeForUsingExpensifyModal.js | 116 ++++++++++++++++++ src/pages/home/ReportScreen.js | 38 +++--- 2 files changed, 138 insertions(+), 16 deletions(-) create mode 100644 src/components/PurposeForUsingExpensifyModal.js diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js new file mode 100644 index 000000000000..c629442086aa --- /dev/null +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -0,0 +1,116 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import {withOnyx} from 'react-native-onyx'; +import useLocalize from '@hooks/useLocalize'; +import compose from '@libs/compose'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import useThemeStyles from "@styles/useThemeStyles"; +import useWindowDimensions from "@hooks/useWindowDimensions"; +import {useState} from "@types/react"; +import withLocalize, {withLocalizePropTypes} from "@components/withLocalize"; +import ScreenWrapper from "./ScreenWrapper"; +import MenuItemList from "./MenuItemList"; +import Header from "./Header"; +import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; +import Modal from "./Modal"; +import HeaderGap from "./HeaderGap"; +import * as Expensicons from './Icon/Expensicons'; + +const propTypes = { + + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user accountID */ + accountID: PropTypes.number, + }), + + ...withLocalizePropTypes, + + ...windowDimensionsPropTypes, +}; + +const defaultProps = { + session: {}, +}; + +function PurposeForUsingExpensifyModal() { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const {isSmallScreenWidth} = useWindowDimensions(); + const [isModalOpen, setIsModalOpen] = useState(true); + + const menuItems = [ + { + key: 'twoFactorAuth.headerTitle', + title: translate('twoFactorAuth.headerTitle'), + icon: Expensicons.ReceiptSearch, + iconRight: Expensicons.ArrowRight, + onPress: () => {debugger;}, + shouldShowRightIcon: true, + }, + { + key: 'twoFactorAuth.headerTitle', + title: translate('twoFactorAuth.headerTitle'), + icon: Expensicons.ReceiptSearch, + iconRight: Expensicons.ArrowRight, + onPress: () => {debugger;}, + shouldShowRightIcon: true, + }, + { + key: 'twoFactorAuth.headerTitle', + title: translate('twoFactorAuth.headerTitle'), + icon: Expensicons.MoneyBag, + iconRight: Expensicons.ArrowRight, + onPress: () => {debugger;}, + shouldShowRightIcon: true, + }, + { + key: 'twoFactorAuth.headerTitle', + title: translate('twoFactorAuth.headerTitle'), + icon: Expensicons.Briefcase, + iconRight: Expensicons.ArrowRight, + onPress: () => {debugger;}, + shouldShowRightIcon: true, + }, + ]; + + return ( + + + {isSmallScreenWidth && } +
setIsModalOpen(false)} + /> + + + + ); +} + +PurposeForUsingExpensifyModal.propTypes = propTypes; +PurposeForUsingExpensifyModal.defaultProps = defaultProps; +PurposeForUsingExpensifyModal.displayName = 'AddPaymentMethodMenu'; + +export default compose( + withWindowDimensions, + withLocalize, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }), +)(PurposeForUsingExpensifyModal); diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 33646e7129cd..bc5b63e08bc3 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -32,6 +32,7 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import PurposeForUsingExpensifyModal from '@components/PurposeForUsingExpensifyModal'; import HeaderView from './HeaderView'; import reportActionPropTypes from './report/reportActionPropTypes'; import ReportActionsView from './report/ReportActionsView'; @@ -135,22 +136,22 @@ function getReportID(route) { } function ReportScreen({ - betas, - route, - report, - reportMetadata, - reportActions, - accountManagerReportID, - personalDetails, - markReadyForHydration, - policies, - isSidebarLoaded, - viewportOffsetTop, - isComposerFullSize, - errors, - userLeavingStatus, - currentReportID, -}) { + betas, + route, + report, + reportMetadata, + reportActions, + accountManagerReportID, + personalDetails, + markReadyForHydration, + policies, + isSidebarLoaded, + viewportOffsetTop, + isComposerFullSize, + errors, + userLeavingStatus, + currentReportID, + }) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); @@ -452,6 +453,11 @@ function ReportScreen({ )} + {}} + onItemSelected={() => {}} + /> From 38f9c59303f2367b038ea0beb6eb9edd3bc53312 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 13:29:31 -0700 Subject: [PATCH 02/90] Fix imports --- src/components/PurposeForUsingExpensifyModal.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index c629442086aa..ac8fadf1b0e1 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React from 'react'; +import React, {useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; @@ -7,7 +7,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import useThemeStyles from "@styles/useThemeStyles"; import useWindowDimensions from "@hooks/useWindowDimensions"; -import {useState} from "@types/react"; import withLocalize, {withLocalizePropTypes} from "@components/withLocalize"; import ScreenWrapper from "./ScreenWrapper"; import MenuItemList from "./MenuItemList"; From d387417995c68b9e29c47efc84de91a8af39d1b9 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 13:50:23 -0700 Subject: [PATCH 03/90] Fix header --- src/components/PurposeForUsingExpensifyModal.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index ac8fadf1b0e1..6ef2fb2a33a4 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -10,7 +10,7 @@ import useWindowDimensions from "@hooks/useWindowDimensions"; import withLocalize, {withLocalizePropTypes} from "@components/withLocalize"; import ScreenWrapper from "./ScreenWrapper"; import MenuItemList from "./MenuItemList"; -import Header from "./Header"; +import HeaderWithBackButton from "./HeaderWithBackButton"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; import HeaderGap from "./HeaderGap"; @@ -78,6 +78,7 @@ function PurposeForUsingExpensifyModal() { {isSmallScreenWidth && } -
setIsModalOpen(false)} + shouldShowBackButton={false} + onCloseButtonPress={() => setIsModalOpen(false)} /> Date: Tue, 28 Nov 2023 13:55:13 -0700 Subject: [PATCH 04/90] Add english copy and fix key errors --- src/components/PurposeForUsingExpensifyModal.js | 16 ++++++++-------- src/languages/en.ts | 6 ++++++ src/languages/es.ts | 6 ++++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 6ef2fb2a33a4..5f591e7c8ccf 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -41,32 +41,32 @@ function PurposeForUsingExpensifyModal() { const menuItems = [ { - key: 'twoFactorAuth.headerTitle', - title: translate('twoFactorAuth.headerTitle'), + key: 'purposeForExpensify.track', + title: translate('purposeForExpensify.track'), icon: Expensicons.ReceiptSearch, iconRight: Expensicons.ArrowRight, onPress: () => {debugger;}, shouldShowRightIcon: true, }, { - key: 'twoFactorAuth.headerTitle', - title: translate('twoFactorAuth.headerTitle'), + key: 'purposeForExpensify.submit', + title: translate('purposeForExpensify.submit'), icon: Expensicons.ReceiptSearch, iconRight: Expensicons.ArrowRight, onPress: () => {debugger;}, shouldShowRightIcon: true, }, { - key: 'twoFactorAuth.headerTitle', - title: translate('twoFactorAuth.headerTitle'), + key: 'purposeForExpensify.VSB', + title: translate('purposeForExpensify.VSB'), icon: Expensicons.MoneyBag, iconRight: Expensicons.ArrowRight, onPress: () => {debugger;}, shouldShowRightIcon: true, }, { - key: 'twoFactorAuth.headerTitle', - title: translate('twoFactorAuth.headerTitle'), + key: 'purposeForExpensify.SMB', + title: translate('purposeForExpensify.SMB'), icon: Expensicons.Briefcase, iconRight: Expensicons.ArrowRight, onPress: () => {debugger;}, diff --git a/src/languages/en.ts b/src/languages/en.ts index 7bc9c985ad66..f95e964c3b54 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1974,4 +1974,10 @@ export default { }, copyReferralLink: 'Copy referral link', }, + purposeForExpensify: { + track: 'Keep track of personal receipts and expenses', + submit: 'Scan and submit receipts to my manager', + VSB: 'Manage my business expenses to file taxes', + SMB: 'Explore Expensify for my own company', + } } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 6ea01dc4bd14..1779de80a471 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2459,4 +2459,10 @@ export default { }, copyReferralLink: 'Copiar enlace de invitación', }, + purposeForExpensify: { + track: 'Keep track of personal receipts and expenses', + submit: 'Scan and submit receipts to my manager', + VSB: 'Manage my business expenses to file taxes', + SMB: 'Explore Expensify for my own company', + } } satisfies EnglishTranslation; From 01629a22ae3cbd912511d053d5dfe5125521ba09 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 14:13:00 -0700 Subject: [PATCH 05/90] Switch to IllustratedHeaderPageLayout --- .../PurposeForUsingExpensifyModal.js | 28 +++++++++++-------- src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 5f591e7c8ccf..25770f724329 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -11,10 +11,16 @@ import withLocalize, {withLocalizePropTypes} from "@components/withLocalize"; import ScreenWrapper from "./ScreenWrapper"; import MenuItemList from "./MenuItemList"; import HeaderWithBackButton from "./HeaderWithBackButton"; +import Header from "./Header"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; import HeaderGap from "./HeaderGap"; import * as Expensicons from './Icon/Expensicons'; +import * as StyleUtils from "@styles/StyleUtils"; +import IllustratedHeaderPageLayout from "@components/IllustratedHeaderPageLayout"; +import SCREENS from "@src/SCREENS"; +import LottieAnimations from "@components/LottieAnimations"; +import useTheme from '@styles/themes/useTheme'; const propTypes = { @@ -38,6 +44,7 @@ function PurposeForUsingExpensifyModal() { const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); const [isModalOpen, setIsModalOpen] = useState(true); + const theme = useTheme(); const menuItems = [ { @@ -80,23 +87,22 @@ function PurposeForUsingExpensifyModal() { isVisible={isModalOpen} fullscreen > - setIsModalOpen(false)} > - {isSmallScreenWidth && } - setIsModalOpen(false)} +
- + ); } diff --git a/src/languages/en.ts b/src/languages/en.ts index f95e964c3b54..0dc082bb23ec 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1979,5 +1979,7 @@ export default { submit: 'Scan and submit receipts to my manager', VSB: 'Manage my business expenses to file taxes', SMB: 'Explore Expensify for my own company', + welcomeMessage: 'Welcome to Expensify', + welcomeSubtitle: 'What\'s your main purpose for using Expensify?', } } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 1779de80a471..49458c794c90 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2464,5 +2464,7 @@ export default { submit: 'Scan and submit receipts to my manager', VSB: 'Manage my business expenses to file taxes', SMB: 'Explore Expensify for my own company', + welcomeMessage: 'Welcome to Expensify', + welcomeSubtitle: 'What\'s your main purpose for using Expensify?', } } satisfies EnglishTranslation; From 96dc71ea7cec3b0ffd313d60f8a83cb6f2d4225f Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 15:33:18 -0700 Subject: [PATCH 06/90] Use text instead of the header component for better styling --- src/components/PurposeForUsingExpensifyModal.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 25770f724329..a8eb921fe664 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -21,6 +21,8 @@ import IllustratedHeaderPageLayout from "@components/IllustratedHeaderPageLayout import SCREENS from "@src/SCREENS"; import LottieAnimations from "@components/LottieAnimations"; import useTheme from '@styles/themes/useTheme'; +import Text from "@components/Text"; +import {View} from "react-native"; const propTypes = { @@ -94,10 +96,15 @@ function PurposeForUsingExpensifyModal() { shouldShowBackButton={false} onCloseButtonPress={() => setIsModalOpen(false)} > -
+ + + {translate('purposeForExpensify.welcomeMessage')} + + {translate('purposeForExpensify.welcomeSubtitle')} + Date: Tue, 28 Nov 2023 15:35:31 -0700 Subject: [PATCH 07/90] Fix imports --- .../PurposeForUsingExpensifyModal.js | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index a8eb921fe664..1221afa59767 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -5,24 +5,18 @@ import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import SCREENS from "@src/SCREENS"; import useThemeStyles from "@styles/useThemeStyles"; +import useTheme from '@styles/themes/useTheme'; import useWindowDimensions from "@hooks/useWindowDimensions"; -import withLocalize, {withLocalizePropTypes} from "@components/withLocalize"; -import ScreenWrapper from "./ScreenWrapper"; +import {View} from "react-native"; +import IllustratedHeaderPageLayout from "./IllustratedHeaderPageLayout"; +import LottieAnimations from "./LottieAnimations"; +import Text from "./Text"; import MenuItemList from "./MenuItemList"; -import HeaderWithBackButton from "./HeaderWithBackButton"; -import Header from "./Header"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; -import HeaderGap from "./HeaderGap"; import * as Expensicons from './Icon/Expensicons'; -import * as StyleUtils from "@styles/StyleUtils"; -import IllustratedHeaderPageLayout from "@components/IllustratedHeaderPageLayout"; -import SCREENS from "@src/SCREENS"; -import LottieAnimations from "@components/LottieAnimations"; -import useTheme from '@styles/themes/useTheme'; -import Text from "@components/Text"; -import {View} from "react-native"; const propTypes = { @@ -32,8 +26,6 @@ const propTypes = { accountID: PropTypes.number, }), - ...withLocalizePropTypes, - ...windowDimensionsPropTypes, }; @@ -120,7 +112,6 @@ PurposeForUsingExpensifyModal.displayName = 'AddPaymentMethodMenu'; export default compose( withWindowDimensions, - withLocalize, withOnyx({ session: { key: ONYXKEYS.SESSION, From 39b3593a9325331c0155e13db428e712a71c51d2 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 16:30:25 -0700 Subject: [PATCH 08/90] Change illustration --- src/components/PurposeForUsingExpensifyModal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 1221afa59767..b2ed7f10c6b6 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -80,10 +80,11 @@ function PurposeForUsingExpensifyModal() { type={isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED : CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED} isVisible={isModalOpen} fullscreen + onClose={() => setIsModalOpen(false)} > setIsModalOpen(false)} From 2c21559074951acfbe19a24fe9668f7601c45810 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 28 Nov 2023 18:48:55 -0700 Subject: [PATCH 09/90] add scan asset and update row --- assets/images/scan.svg | 10 ++++++++++ src/components/Icon/Expensicons.ts | 2 ++ src/components/PurposeForUsingExpensifyModal.js | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 assets/images/scan.svg diff --git a/assets/images/scan.svg b/assets/images/scan.svg new file mode 100644 index 000000000000..629dc3823a12 --- /dev/null +++ b/assets/images/scan.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 3d4f0edb1656..4505e6f31de7 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -105,6 +105,7 @@ import Receipt from '@assets/images/receipt.svg'; import Rotate from '@assets/images/rotate-image.svg'; import RotateLeft from '@assets/images/rotate-left.svg'; import Send from '@assets/images/send.svg'; +import Scan from '@assets/images/scan.svg'; import Shield from '@assets/images/shield.svg'; import AppleLogo from '@assets/images/signIn/apple-logo.svg'; import GoogleLogo from '@assets/images/signIn/google-logo.svg'; @@ -238,6 +239,7 @@ export { ReceiptSearch, Rotate, RotateLeft, + Scan, Send, Shield, Sync, diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index b2ed7f10c6b6..e7651bd69315 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -52,7 +52,7 @@ function PurposeForUsingExpensifyModal() { { key: 'purposeForExpensify.submit', title: translate('purposeForExpensify.submit'), - icon: Expensicons.ReceiptSearch, + icon: Expensicons.Scan, iconRight: Expensicons.ArrowRight, onPress: () => {debugger;}, shouldShowRightIcon: true, From 7f32222b8ec887d5961cbd771b427c87edac40b3 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 4 Dec 2023 15:31:13 -0700 Subject: [PATCH 10/90] ReplaceillustratedHeaderPageLayout with views to make it work on mobile --- .../PurposeForUsingExpensifyModal.js | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index e7651bd69315..ef48513e68bd 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -5,18 +5,22 @@ import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import SCREENS from "@src/SCREENS"; import useThemeStyles from "@styles/useThemeStyles"; import useTheme from '@styles/themes/useTheme'; import useWindowDimensions from "@hooks/useWindowDimensions"; -import {View} from "react-native"; -import IllustratedHeaderPageLayout from "./IllustratedHeaderPageLayout"; +import {View, StyleSheet} from "react-native"; import LottieAnimations from "./LottieAnimations"; import Text from "./Text"; import MenuItemList from "./MenuItemList"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; import * as Expensicons from './Icon/Expensicons'; +import Lottie from "@components/Lottie"; +import * as Illustrations from '@components/Icon/Illustrations'; +import HeaderWithBackButton from "@components/HeaderWithBackButton"; +import Image from "@components/Image"; +import * as StyleUtils from "@styles/StyleUtils"; +import SCREENS from "@src/SCREENS"; const propTypes = { @@ -82,14 +86,22 @@ function PurposeForUsingExpensifyModal() { fullscreen onClose={() => setIsModalOpen(false)} > - setIsModalOpen(false)} - > - + + setIsModalOpen(false)} + /> + + + + - + ); } From 1d2ff01ed586247f743cd23d7dd76236a53a9052 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 4 Dec 2023 18:33:05 -0700 Subject: [PATCH 11/90] Add new method for completing engagement modal --- src/libs/actions/Report.js | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index a03488429405..f585985ad6fa 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2400,6 +2400,124 @@ function getReportPrivateNote(reportID) { ); } +/** + * Add up to two report actions to a report. This method can be called for the following situations: + * + * - Adding one comment + * - Adding one attachment + * - Add both a comment and attachment simultaneously + * + * @param {String} text + * @param {String} choice + */ +function completeEngagementModal( text , choice) { + const commandName = 'completeEngagementModal'; + const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text); + const reportCommentAction = reportComment.reportAction; + const reportCommentText = reportComment.commentText; + const currentTime = DateUtils.getDBTime(); + const lastCommentText = ReportUtils.formatReportLastMessageText(reportCommentAction.message[0].text); + + const optimisticReport = { + lastVisibleActionCreated: currentTime, + lastMessageTranslationKey: lodashGet(reportCommentAction, 'message[0].translationKey', ''), + lastMessageText: lastCommentText, + lastMessageHtml: lastCommentText, + lastActorAccountID: currentUserAccountID, + lastReadTime: currentTime, + }; + + if (ReportUtils.getReportNotificationPreference(ReportUtils.getReport(conciergeChatReportID)) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { + optimisticReport.notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + } + + // Optimistically add the new actions to the store before waiting to save them to the server + const optimisticReportActions = {}; + optimisticReportActions[reportCommentAction.reportActionID] = reportCommentAction; + + + const parameters = { + reportID: conciergeChatReportID, + reportActionID: reportCommentAction.reportActionID, + reportComment: reportCommentText, + engagementChoice: choice, + + }; + + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${conciergeChatReportID}`, + value: optimisticReport, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, + value: optimisticReportActions, + }, + ]; + + const successData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, + value: _.mapObject(optimisticReportActions, () => ({pendingAction: null})), + }, + ]; + + let failureReport = { + lastMessageTranslationKey: '', + lastMessageText: '', + lastVisibleActionCreated: '', + }; + const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(conciergeChatReportID); + if (lastMessageText || lastMessageTranslationKey) { + const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(conciergeChatReportID); + const lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); + const lastActorAccountID = lodashGet(lastVisibleAction, 'actorAccountID'); + failureReport = { + lastMessageTranslationKey, + lastMessageText, + lastVisibleActionCreated, + lastActorAccountID, + }; + } + const failureData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${conciergeChatReportID}`, + value: failureReport, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, + value: _.mapObject(optimisticReportActions, (action) => ({ + ...action, + errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), + })), + }, + ]; + + // Update the timezone if it's been 5 minutes from the last time the user added a comment + if (DateUtils.canUpdateTimezone()) { + const timezone = DateUtils.getCurrentTimezone(); + parameters.timezone = JSON.stringify(timezone); + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: {[currentUserAccountID]: {timezone}}, + }); + DateUtils.setTimezoneUpdated(); + } + + API.write(commandName, parameters, { + optimisticData, + successData, + failureData, + }); + notifyNewAction(conciergeChatReportID, reportCommentAction.actorAccountID, reportCommentAction.reportActionID); +} + /** * Loads necessary data for rendering the RoomMembersPage * From 5fb78b815057aacad51050e91162192db32870c8 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 5 Dec 2023 10:16:27 -0700 Subject: [PATCH 12/90] Add new nvp keys and add to the optimistic data --- src/ONYXKEYS.ts | 4 ++++ src/libs/actions/Report.js | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 5576eb64736d..8b499ff6d98b 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -110,6 +110,10 @@ const ONYXKEYS = { /** This NVP holds to most recent waypoints that a person has used when creating a distance request */ NVP_RECENT_WAYPOINTS: 'expensify_recentWaypoints', + NVP_HAS_DISMISSED_IDLE_PANEL: 'hasDismissedIdlePanel', + + NVP_INTRO_SELECTED: 'introSelected', + /** Does this user have push notifications enabled for this device? */ PUSH_NOTIFICATIONS_ENABLED: 'pushNotificationsEnabled', diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index f585985ad6fa..42257654b30e 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2455,6 +2455,11 @@ function completeEngagementModal( text , choice) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, value: optimisticReportActions, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: {choice} + }, ]; const successData = [ @@ -2462,7 +2467,7 @@ function completeEngagementModal( text , choice) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, value: _.mapObject(optimisticReportActions, () => ({pendingAction: null})), - }, + } ]; let failureReport = { From 877efb9d3fc117e5b2da804c8815fc42a4f47505 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 5 Dec 2023 11:52:38 -0700 Subject: [PATCH 13/90] Add copy that concierge will send --- .../PurposeForUsingExpensifyModal.js | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index ef48513e68bd..4bf0b4bea865 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -44,6 +44,51 @@ function PurposeForUsingExpensifyModal() { const [isModalOpen, setIsModalOpen] = useState(true); const theme = useTheme(); + const messageCopy = { + track: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:
' + + '
' + + '1. Press your avatar icon
' + + '2. Choose Workspaces
' + + '3. Choose New Workspace
' + + '4. Name your workspace something meaningful (eg, "My Business Expenses")
' + + '
' + + 'Once you have your workspace set up, you can add expenses to it as follows:
' + + '
' + + '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms
' + + '2. Choose the + button in the chat compose window
' + + '3. Choose Request money
' + + '4. Choose what kind of expense you\'d like to log, whether a manual expense, scanned receipt, or tracked distance.
' + + '
' + + 'That\'ll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!', + submit: 'Hi there, to submit expenses for reimbursement, please:
' + + '
' + + '1. Press the big green + button
' + + '2. Choose Request money
' + + '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance
' + + '4. Enter the email address or phone number of your boss
' + + '
' + + 'And we\'ll take it from there to get you paid back. Please give it a shot and let me know how it goes!', + manage: 'Great! To manage your team\'s expenses, create a workspace to keep everything contained:
' + + '
' + + '1. Press your avatar icon
' + + '2. Choose Workspaces
' + + '3. Choose New Workspace
' + + '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")
' + + '
' + + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', + chat: 'Hi there, to split an expense such as with a friend, please:
' + + '
' + + 'Press the big green + button
' + + 'Choose *Request money*
' + + 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance
' + + 'Enter the email address or phone number of your friend
' + + 'Press *Split* next to their name
' + + 'Repeat as many times as you like for each of your friends
' + + 'Press *Add to split* when done adding friends
' + + 'Press Split to split the bill
' + + '
' + + 'This will send an a money request to each of your friends for however much they owe you, and we\'ll take care of getting you paid back. Thanks for asking, and let me know how it goes!' + + } const menuItems = [ { key: 'purposeForExpensify.track', From 5f921af4c91706f29e0cfd213e4a7f30a9524850 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 5 Dec 2023 14:14:52 -0700 Subject: [PATCH 14/90] Update copy and send message --- .../PurposeForUsingExpensifyModal.js | 24 ++++++++++--------- src/languages/en.ts | 8 +++---- src/languages/es.ts | 8 +++---- src/libs/actions/Report.js | 1 + 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 4bf0b4bea865..22097df59902 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -11,6 +11,7 @@ import useWindowDimensions from "@hooks/useWindowDimensions"; import {View, StyleSheet} from "react-native"; import LottieAnimations from "./LottieAnimations"; import Text from "./Text"; +import * as Report from '../libs/actions/Report'; import MenuItemList from "./MenuItemList"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; @@ -44,6 +45,7 @@ function PurposeForUsingExpensifyModal() { const [isModalOpen, setIsModalOpen] = useState(true); const theme = useTheme(); + // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { track: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:
' + '
' + @@ -68,7 +70,7 @@ function PurposeForUsingExpensifyModal() { '4. Enter the email address or phone number of your boss
' + '
' + 'And we\'ll take it from there to get you paid back. Please give it a shot and let me know how it goes!', - manage: 'Great! To manage your team\'s expenses, create a workspace to keep everything contained:
' + + business: 'Great! To manage your team\'s expenses, create a workspace to keep everything contained:
' + '
' + '1. Press your avatar icon
' + '2. Choose Workspaces
' + @@ -76,7 +78,7 @@ function PurposeForUsingExpensifyModal() { '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")
' + '
' + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', - chat: 'Hi there, to split an expense such as with a friend, please:
' + + chatSplit: 'Hi there, to split an expense such as with a friend, please:
' + '
' + 'Press the big green + button
' + 'Choose *Request money*
' + @@ -87,7 +89,7 @@ function PurposeForUsingExpensifyModal() { 'Press *Add to split* when done adding friends
' + 'Press Split to split the bill
' + '
' + - 'This will send an a money request to each of your friends for however much they owe you, and we\'ll take care of getting you paid back. Thanks for asking, and let me know how it goes!' + + 'This will send a money request to each of your friends for however much they owe you, and we\'ll take care of getting you paid back. Thanks for asking, and let me know how it goes!', } const menuItems = [ { @@ -95,7 +97,7 @@ function PurposeForUsingExpensifyModal() { title: translate('purposeForExpensify.track'), icon: Expensicons.ReceiptSearch, iconRight: Expensicons.ArrowRight, - onPress: () => {debugger;}, + onPress: () => Report.completeEngagementModal(messageCopy.track, 'trackNewDot'), shouldShowRightIcon: true, }, { @@ -103,23 +105,23 @@ function PurposeForUsingExpensifyModal() { title: translate('purposeForExpensify.submit'), icon: Expensicons.Scan, iconRight: Expensicons.ArrowRight, - onPress: () => {debugger;}, + onPress: () => Report.completeEngagementModal(messageCopy.submit, 'submitNewDot'), shouldShowRightIcon: true, }, { - key: 'purposeForExpensify.VSB', - title: translate('purposeForExpensify.VSB'), + key: 'purposeForExpensify.business', + title: translate('purposeForExpensify.business'), icon: Expensicons.MoneyBag, iconRight: Expensicons.ArrowRight, - onPress: () => {debugger;}, + onPress: () => Report.completeEngagementModal(messageCopy.business, 'businessNewDot'), shouldShowRightIcon: true, }, { - key: 'purposeForExpensify.SMB', - title: translate('purposeForExpensify.SMB'), + key: 'purposeForExpensify.chatSplit', + title: translate('purposeForExpensify.chatSplit'), icon: Expensicons.Briefcase, iconRight: Expensicons.ArrowRight, - onPress: () => {debugger;}, + onPress: () => Report.completeEngagementModal(messageCopy.chatSplit, 'chatSplitNewDot'), shouldShowRightIcon: true, }, ]; diff --git a/src/languages/en.ts b/src/languages/en.ts index d10600d3bd3a..bd454480e471 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1976,10 +1976,10 @@ export default { copyReferralLink: 'Copy referral link', }, purposeForExpensify: { - track: 'Keep track of personal receipts and expenses', - submit: 'Scan and submit receipts to my manager', - VSB: 'Manage my business expenses to file taxes', - SMB: 'Explore Expensify for my own company', + track: 'Track my business expenses to file taxes', + submit: 'Submit expenses to my employer to get paid back', + business: 'Manage my team\'s expenses', + chatSplit: 'Chat and split expenses with friends', welcomeMessage: 'Welcome to Expensify', welcomeSubtitle: 'What\'s your main purpose for using Expensify?', } diff --git a/src/languages/es.ts b/src/languages/es.ts index 6a60c7a402fe..ce2ac0894c4f 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2461,10 +2461,10 @@ export default { copyReferralLink: 'Copiar enlace de invitación', }, purposeForExpensify: { - track: 'Keep track of personal receipts and expenses', - submit: 'Scan and submit receipts to my manager', - VSB: 'Manage my business expenses to file taxes', - SMB: 'Explore Expensify for my own company', + track: 'Track my business expenses to file taxes', + submit: 'Submit expenses to my employer to get paid back', + business: 'Manage my team\'s expenses', + chatSplit: 'Chat and split expenses with friends', welcomeMessage: 'Welcome to Expensify', welcomeSubtitle: 'What\'s your main purpose for using Expensify?', } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 42257654b30e..ceec4039cf0c 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2683,6 +2683,7 @@ export { hasErrorInPrivateNotes, getOlderActions, getNewerActions, + completeEngagementModal, openRoomMembersPage, savePrivateNotesDraft, getDraftPrivateNote, From cfad7ccf3af0098752304e3fe37261d6a985de40 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 5 Dec 2023 14:37:08 -0700 Subject: [PATCH 15/90] Aso close the modal when submitting an option --- .../PurposeForUsingExpensifyModal.js | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 22097df59902..83ab667a2109 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {useState} from 'react'; +import React, {useState, useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; @@ -91,13 +91,23 @@ function PurposeForUsingExpensifyModal() { '
' + 'This will send a money request to each of your friends for however much they owe you, and we\'ll take care of getting you paid back. Thanks for asking, and let me know how it goes!', } + + const closeModal = useCallback(() => { + setIsModalOpen(false); + }, []); + + const completeModalAndClose = (message, choice) => { + Report.completeEngagementModal(message, choice); + closeModal(); + } + const menuItems = [ { key: 'purposeForExpensify.track', title: translate('purposeForExpensify.track'), icon: Expensicons.ReceiptSearch, iconRight: Expensicons.ArrowRight, - onPress: () => Report.completeEngagementModal(messageCopy.track, 'trackNewDot'), + onPress: () => completeModalAndClose(messageCopy.track, 'trackNewDot'), shouldShowRightIcon: true, }, { @@ -105,7 +115,7 @@ function PurposeForUsingExpensifyModal() { title: translate('purposeForExpensify.submit'), icon: Expensicons.Scan, iconRight: Expensicons.ArrowRight, - onPress: () => Report.completeEngagementModal(messageCopy.submit, 'submitNewDot'), + onPress: () => completeModalAndClose(messageCopy.submit, 'submitNewDot'), shouldShowRightIcon: true, }, { @@ -113,7 +123,7 @@ function PurposeForUsingExpensifyModal() { title: translate('purposeForExpensify.business'), icon: Expensicons.MoneyBag, iconRight: Expensicons.ArrowRight, - onPress: () => Report.completeEngagementModal(messageCopy.business, 'businessNewDot'), + onPress: () => completeModalAndClose(messageCopy.business, 'businessNewDot'), shouldShowRightIcon: true, }, { @@ -121,7 +131,7 @@ function PurposeForUsingExpensifyModal() { title: translate('purposeForExpensify.chatSplit'), icon: Expensicons.Briefcase, iconRight: Expensicons.ArrowRight, - onPress: () => Report.completeEngagementModal(messageCopy.chatSplit, 'chatSplitNewDot'), + onPress: () => completeModalAndClose(messageCopy.chatSplit, 'chatSplitNewDot'), shouldShowRightIcon: true, }, ]; @@ -131,7 +141,7 @@ function PurposeForUsingExpensifyModal() { type={isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED : CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED} isVisible={isModalOpen} fullscreen - onClose={() => setIsModalOpen(false)} + onClose={closeModal} > Date: Tue, 5 Dec 2023 16:04:25 -0700 Subject: [PATCH 16/90] Re-order elements, add overlay param, and rename poorly named prop --- src/components/AttachmentModal.js | 2 +- src/components/HeaderWithBackButton/index.js | 7 ++++--- src/components/PurposeForUsingExpensifyModal.js | 15 ++++++++------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 356e75b1e1bb..56a3b2244ffa 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -440,7 +440,7 @@ function AttachmentModal(props) { shouldShowThreeDotsButton={shouldShowThreeDotsButton} threeDotsAnchorPosition={styles.threeDotsPopoverOffsetAttachmentModal(windowWidth)} threeDotsMenuItems={threeDotsMenuItems} - shouldOverlay + shouldOverlayDots /> {!_.isEmpty(props.report) ? ( diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js index 051e18ed675e..57897d17ecfd 100755 --- a/src/components/HeaderWithBackButton/index.js +++ b/src/components/HeaderWithBackButton/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Keyboard, View} from 'react-native'; +import {Keyboard, StyleSheet, View} from 'react-native'; import AvatarWithDisplayName from '@components/AvatarWithDisplayName'; import Header from '@components/Header'; import Icon from '@components/Icon'; @@ -51,6 +51,7 @@ function HeaderWithBackButton({ threeDotsMenuItems = [], shouldEnableDetailPageNavigation = false, children = null, + shouldOverlayDots = false, shouldOverlay = false, singleExecution = (func) => func, shouldNavigateToTopMostReport = false, @@ -65,7 +66,7 @@ function HeaderWithBackButton({ // Hover on some part of close icons will not work on Electron if dragArea is true // https://github.com/Expensify/App/issues/29598 dataSet={{dragArea: false}} - style={[styles.headerBar, shouldShowBorderBottom && styles.borderBottom, shouldShowBackButton && styles.pl2]} + style={[styles.headerBar, shouldShowBorderBottom && styles.borderBottom, shouldShowBackButton && styles.pl2, shouldOverlay && StyleSheet.absoluteFillObject]} > {shouldShowBackButton && ( @@ -159,7 +160,7 @@ function HeaderWithBackButton({ menuItems={threeDotsMenuItems} onIconPress={onThreeDotsButtonPress} anchorPosition={threeDotsAnchorPosition} - shouldOverlay={shouldOverlay} + shouldOverlay={shouldOverlayDots} /> )} {shouldShowCloseButton && ( diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 83ab667a2109..544dfa035e58 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -144,12 +144,7 @@ function PurposeForUsingExpensifyModal() { onClose={closeModal} > - setIsModalOpen(false)} - /> - + - + setIsModalOpen(false)} + shouldOverlay + /> + Date: Tue, 5 Dec 2023 16:38:56 -0700 Subject: [PATCH 17/90] Add padding and remove unnecessary view --- .../PurposeForUsingExpensifyModal.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 544dfa035e58..0cf1267c6dce 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -144,22 +144,20 @@ function PurposeForUsingExpensifyModal() { onClose={closeModal} > - - - + setIsModalOpen(false)} shouldOverlay /> - + Date: Tue, 5 Dec 2023 19:05:29 -0700 Subject: [PATCH 18/90] Fix copy --- .../PurposeForUsingExpensifyModal.js | 78 +++++++++---------- src/libs/actions/Report.js | 16 ---- 2 files changed, 39 insertions(+), 55 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 0cf1267c6dce..d9ff33c62a09 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -47,48 +47,48 @@ function PurposeForUsingExpensifyModal() { // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { - track: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:
' + - '
' + - '1. Press your avatar icon
' + - '2. Choose Workspaces
' + - '3. Choose New Workspace
' + - '4. Name your workspace something meaningful (eg, "My Business Expenses")
' + - '
' + - 'Once you have your workspace set up, you can add expenses to it as follows:
' + - '
' + - '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms
' + - '2. Choose the + button in the chat compose window
' + - '3. Choose Request money
' + - '4. Choose what kind of expense you\'d like to log, whether a manual expense, scanned receipt, or tracked distance.
' + - '
' + + track: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + + '\n' + + '1. Press your avatar icon\n' + + '2. Choose Workspaces\n' + + '3. Choose New Workspace\n' + + '4. Name your workspace something meaningful (eg, "My Business Expenses")\n' + + '\n' + + 'Once you have your workspace set up, you can add expenses to it as follows:\n' + + '\n' + + '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms\n' + + '2. Choose the + button in the chat compose window\n' + + '3. Choose Request money\n' + + '4. Choose what kind of expense you\'d like to log, whether a manual expense, scanned receipt, or tracked distance.\n' + + '\n' + 'That\'ll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!', - submit: 'Hi there, to submit expenses for reimbursement, please:
' + - '
' + - '1. Press the big green + button
' + - '2. Choose Request money
' + - '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance
' + - '4. Enter the email address or phone number of your boss
' + - '
' + + submit: 'Hi there, to submit expenses for reimbursement, please:\n' + + '\n' + + '1. Press the big green + button\n' + + '2. Choose Request money\n' + + '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance\n' + + '4. Enter the email address or phone number of your boss\n' + + '\n' + 'And we\'ll take it from there to get you paid back. Please give it a shot and let me know how it goes!', - business: 'Great! To manage your team\'s expenses, create a workspace to keep everything contained:
' + - '
' + - '1. Press your avatar icon
' + - '2. Choose Workspaces
' + - '3. Choose New Workspace
' + - '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")
' + - '
' + + business: 'Great! To manage your team\'s expenses, create a workspace to keep everything contained:\n' + + '\n' + + '1. Press your avatar icon\n' + + '2. Choose Workspaces\n' + + '3. Choose New Workspace\n' + + '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + + '\n' + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', - chatSplit: 'Hi there, to split an expense such as with a friend, please:
' + - '
' + - 'Press the big green + button
' + - 'Choose *Request money*
' + - 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance
' + - 'Enter the email address or phone number of your friend
' + - 'Press *Split* next to their name
' + - 'Repeat as many times as you like for each of your friends
' + - 'Press *Add to split* when done adding friends
' + - 'Press Split to split the bill
' + - '
' + + chatSplit: 'Hi there, to split an expense such as with a friend, please:\n' + + '\n' + + 'Press the big green + button\n' + + 'Choose *Request money*\n' + + 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance\n' + + 'Enter the email address or phone number of your friend\n' + + 'Press *Split* next to their name\n' + + 'Repeat as many times as you like for each of your friends\n' + + 'Press *Add to split* when done adding friends\n' + + 'Press Split to split the bill\n' + + '\n' + 'This will send a money request to each of your friends for however much they owe you, and we\'ll take care of getting you paid back. Thanks for asking, and let me know how it goes!', } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index ceec4039cf0c..9ea671a1b43a 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2487,21 +2487,6 @@ function completeEngagementModal( text , choice) { lastActorAccountID, }; } - const failureData = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${conciergeChatReportID}`, - value: failureReport, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, - value: _.mapObject(optimisticReportActions, (action) => ({ - ...action, - errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), - })), - }, - ]; // Update the timezone if it's been 5 minutes from the last time the user added a comment if (DateUtils.canUpdateTimezone()) { @@ -2518,7 +2503,6 @@ function completeEngagementModal( text , choice) { API.write(commandName, parameters, { optimisticData, successData, - failureData, }); notifyNewAction(conciergeChatReportID, reportCommentAction.actorAccountID, reportCommentAction.reportActionID); } From 91120f905cb05fb1737192c943d59c10fcb91938 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 5 Dec 2023 19:05:50 -0700 Subject: [PATCH 19/90] Always get the conciergeChatReport because sometimes it won't be set --- src/components/PurposeForUsingExpensifyModal.js | 1 + src/libs/actions/Report.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index d9ff33c62a09..52aa25390604 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -97,6 +97,7 @@ function PurposeForUsingExpensifyModal() { }, []); const completeModalAndClose = (message, choice) => { + debugger; Report.completeEngagementModal(message, choice); closeModal(); } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 9ea671a1b43a..7d4a558a310e 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2427,6 +2427,11 @@ function completeEngagementModal( text , choice) { lastReadTime: currentTime, }; + const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE]); + const conciergeChatReport = ReportUtils.getChatByParticipants(conciergeAccountID); + conciergeChatReportID = conciergeChatReport.reportID; + debugger; + if (ReportUtils.getReportNotificationPreference(ReportUtils.getReport(conciergeChatReportID)) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { optimisticReport.notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; } From 0def96ff1fc06f11dfc0e5d3909b99e1e0aec6c1 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 6 Dec 2023 06:47:26 -0700 Subject: [PATCH 20/90] Fix coloring --- src/components/PurposeForUsingExpensifyModal.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 52aa25390604..a18f91cd11a4 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -141,10 +141,9 @@ function PurposeForUsingExpensifyModal() { - + setIsModalOpen(false)} shouldOverlay /> + - ); } From e5ef2b4b2a70e27070f76b19e87fde8bd92b1fe3 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 6 Dec 2023 06:52:43 -0700 Subject: [PATCH 21/90] Fix x color --- src/components/PurposeForUsingExpensifyModal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index a18f91cd11a4..125d226d652f 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -156,6 +156,7 @@ function PurposeForUsingExpensifyModal() { shouldShowBackButton={false} onCloseButtonPress={() => setIsModalOpen(false)} shouldOverlay + iconFill={theme.iconColorfulBackground} />
From 73fb91986d4b6c675c28df46bfc3ec61de8dfe97 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 6 Dec 2023 07:36:06 -0700 Subject: [PATCH 22/90] Lint --- .../PurposeForUsingExpensifyModal.js | 15 +++++++-------- src/libs/actions/Report.js | 18 ------------------ 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 125d226d652f..135da1710db0 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -8,20 +8,19 @@ import ONYXKEYS from '@src/ONYXKEYS'; import useThemeStyles from "@styles/useThemeStyles"; import useTheme from '@styles/themes/useTheme'; import useWindowDimensions from "@hooks/useWindowDimensions"; -import {View, StyleSheet} from "react-native"; +import * as Report from '@userActions/Report'; +import * as StyleUtils from "@styles/StyleUtils"; +import SCREENS from "@src/SCREENS"; +import {View} from "react-native"; import LottieAnimations from "./LottieAnimations"; import Text from "./Text"; -import * as Report from '../libs/actions/Report'; +import Lottie from "./Lottie"; +import HeaderWithBackButton from "./HeaderWithBackButton"; + import MenuItemList from "./MenuItemList"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; import * as Expensicons from './Icon/Expensicons'; -import Lottie from "@components/Lottie"; -import * as Illustrations from '@components/Icon/Illustrations'; -import HeaderWithBackButton from "@components/HeaderWithBackButton"; -import Image from "@components/Image"; -import * as StyleUtils from "@styles/StyleUtils"; -import SCREENS from "@src/SCREENS"; const propTypes = { diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index c85f10a2750e..55c48a8302a6 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2466,24 +2466,6 @@ function completeEngagementModal( text , choice) { } ]; - let failureReport = { - lastMessageTranslationKey: '', - lastMessageText: '', - lastVisibleActionCreated: '', - }; - const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(conciergeChatReportID); - if (lastMessageText || lastMessageTranslationKey) { - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(conciergeChatReportID); - const lastVisibleActionCreated = lodashGet(lastVisibleAction, 'created'); - const lastActorAccountID = lodashGet(lastVisibleAction, 'actorAccountID'); - failureReport = { - lastMessageTranslationKey, - lastMessageText, - lastVisibleActionCreated, - lastActorAccountID, - }; - } - // Update the timezone if it's been 5 minutes from the last time the user added a comment if (DateUtils.canUpdateTimezone()) { const timezone = DateUtils.getCurrentTimezone(); From 01ce5e3ec4236db9d31f2d85fb085c734dac405b Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 6 Dec 2023 08:58:17 -0700 Subject: [PATCH 23/90] fix background color after merge --- src/components/PurposeForUsingExpensifyModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 135da1710db0..ec55ba94875e 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -142,7 +142,7 @@ function PurposeForUsingExpensifyModal() { isVisible={isModalOpen} onClose={closeModal} > - + Date: Wed, 6 Dec 2023 15:26:22 -0700 Subject: [PATCH 24/90] add modal to set dismissed NVP --- .../PurposeForUsingExpensifyModal.js | 6 +++--- src/libs/actions/Report.js | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index ec55ba94875e..e3065730dc58 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -92,13 +92,13 @@ function PurposeForUsingExpensifyModal() { } const closeModal = useCallback(() => { + Report.dismissEngagementModal(); setIsModalOpen(false); }, []); const completeModalAndClose = (message, choice) => { - debugger; Report.completeEngagementModal(message, choice); - closeModal(); + setIsModalOpen(false) } const menuItems = [ @@ -153,7 +153,7 @@ function PurposeForUsingExpensifyModal() { setIsModalOpen(false)} + onCloseButtonPress={closeModal} shouldOverlay iconFill={theme.iconColorfulBackground} /> diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 55c48a8302a6..c5627ff6845c 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2485,6 +2485,26 @@ function completeEngagementModal( text , choice) { notifyNewAction(conciergeChatReportID, reportCommentAction.actorAccountID, reportCommentAction.reportActionID); } +function dismissEngagementModal() { + const commandName = 'SetNameValuePair'; + const parameters = { + name: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL, + value: true, + }; + + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: 'ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL', + value: true, + }, + ]; + + API.write(commandName, parameters, { + optimisticData, + }); +} + /** * Loads necessary data for rendering the RoomMembersPage * @@ -2653,6 +2673,7 @@ export { getOlderActions, getNewerActions, completeEngagementModal, + dismissEngagementModal, openRoomMembersPage, savePrivateNotesDraft, getDraftPrivateNote, From 60c13dca923c6843aa71ab7a84930c1dcc959abd Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 6 Dec 2023 15:26:46 -0700 Subject: [PATCH 25/90] Use the concierge accountID so that the message comes from them --- src/libs/ReportUtils.ts | 9 +++++---- src/libs/actions/Report.js | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b50b4611a249..c0ea2bf80556 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2376,12 +2376,13 @@ function getParsedComment(text: string): string { return text.length <= CONST.MAX_MARKUP_LENGTH ? parser.replace(text) : lodashEscape(text); } -function buildOptimisticAddCommentReportAction(text?: string, file?: File & {source: string; uri: string}): OptimisticReportAction { +function buildOptimisticAddCommentReportAction(text?: string, file?: File & {source: string; uri: string}, actorAccountID?: number): OptimisticReportAction { const parser = new ExpensiMark(); const commentText = getParsedComment(text ?? ''); const isAttachment = !text && file !== undefined; const attachmentInfo = isAttachment ? file : {}; const htmlForNewComment = isAttachment ? CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML : commentText; + const accountID = actorAccountID ?? currentUserAccountID; // Remove HTML from text when applying optimistic offline comment const textForNewComment = isAttachment ? CONST.ATTACHMENT_MESSAGE_TEXT : parser.htmlToText(htmlForNewComment); @@ -2390,16 +2391,16 @@ function buildOptimisticAddCommentReportAction(text?: string, file?: File & {sou reportAction: { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, - actorAccountID: currentUserAccountID, + actorAccountID: accountID, person: [ { style: 'strong', - text: allPersonalDetails?.[currentUserAccountID ?? -1]?.displayName ?? currentUserEmail, + text: allPersonalDetails?.[accountID ?? -1]?.displayName ?? currentUserEmail, type: 'TEXT', }, ], automatic: false, - avatar: allPersonalDetails?.[currentUserAccountID ?? -1]?.avatar ?? UserUtils.getDefaultAvatarURL(currentUserAccountID), + avatar: allPersonalDetails?.[accountID ?? -1]?.avatar ?? UserUtils.getDefaultAvatarURL(accountID), created: DateUtils.getDBTime(), message: [ { diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index c5627ff6845c..fd43b6814317 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2402,8 +2402,9 @@ function getReportPrivateNote(reportID) { * @param {String} choice */ function completeEngagementModal( text , choice) { - const commandName = 'completeEngagementModal'; - const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text); + const commandName = 'CompleteEngagementModal'; + const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; + const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, null, conciergeAccountID); const reportCommentAction = reportComment.reportAction; const reportCommentText = reportComment.commentText; const currentTime = DateUtils.getDBTime(); @@ -2418,8 +2419,7 @@ function completeEngagementModal( text , choice) { lastReadTime: currentTime, }; - const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE]); - const conciergeChatReport = ReportUtils.getChatByParticipants(conciergeAccountID); + const conciergeChatReport = ReportUtils.getChatByParticipants([conciergeAccountID]); conciergeChatReportID = conciergeChatReport.reportID; debugger; From 6855f21151a7333531dbeed6180bbdf94b68edf7 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 7 Dec 2023 10:13:34 -0700 Subject: [PATCH 26/90] Remove auto-show for create menu --- .../FloatingActionButtonAndPopover.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 21e712c418e6..d6c38de0c101 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -149,19 +149,7 @@ function FloatingActionButtonAndPopover(props) { } }; - useEffect(() => { - const navigationState = props.navigation.getState(); - const routes = lodashGet(navigationState, 'routes', []); - const currentRoute = routes[navigationState.index]; - 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]); + useEffect(() => { if (!didScreenBecomeInactive()) { From bb36f6ee7a5caf35359548266e0cf7c4f2f28bc1 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 7 Dec 2023 10:15:04 -0700 Subject: [PATCH 27/90] Move the engagement modal to the sidebarScreen so that it is in the same place for both mobile and web --- src/pages/home/ReportScreen.js | 5 ----- src/pages/home/sidebar/SidebarScreen/index.js | 2 ++ src/pages/home/sidebar/SidebarScreen/index.native.js | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 1944028f1aa4..98bad2d3b167 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -456,11 +456,6 @@ function ReportScreen({ )} - {}} - onItemSelected={() => {}} - /> diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js index 0b4c520c78a2..9c099da75d7d 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.js +++ b/src/pages/home/sidebar/SidebarScreen/index.js @@ -4,6 +4,7 @@ import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; +import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; function SidebarScreen(props) { const popoverModal = useRef(null); @@ -44,6 +45,7 @@ function SidebarScreen(props) { onShowCreateMenu={createDragoverListener} onHideCreateMenu={removeDragoverListener} /> + ); diff --git a/src/pages/home/sidebar/SidebarScreen/index.native.js b/src/pages/home/sidebar/SidebarScreen/index.native.js index 36724c02d278..683afd9168e7 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.native.js +++ b/src/pages/home/sidebar/SidebarScreen/index.native.js @@ -4,6 +4,7 @@ import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; +import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; function SidebarScreen(props) { const {isSmallScreenWidth} = useWindowDimensions(); @@ -14,6 +15,7 @@ function SidebarScreen(props) { {...props} > + ); From f7dcb5e0e6611914e8fbe999c78b364438552c27 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 7 Dec 2023 15:58:53 -0700 Subject: [PATCH 28/90] Update modal to use welcome.ts --- .../PurposeForUsingExpensifyModal.js | 24 ++++++++++++-- src/libs/actions/Welcome.ts | 32 +++++++++++++++++-- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index e3065730dc58..1f294a2a246c 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {useState, useCallback} from 'react'; +import React, {useState, useCallback, useEffect} from 'react'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; @@ -16,11 +16,14 @@ import LottieAnimations from "./LottieAnimations"; import Text from "./Text"; import Lottie from "./Lottie"; import HeaderWithBackButton from "./HeaderWithBackButton"; - import MenuItemList from "./MenuItemList"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; import * as Expensicons from './Icon/Expensicons'; +import lodashGet from "lodash/get"; +import NAVIGATORS from "@src/NAVIGATORS"; +import * as Welcome from "@userActions/Welcome"; +import withNavigation from "@components/withNavigation"; const propTypes = { @@ -37,13 +40,27 @@ const defaultProps = { session: {}, }; -function PurposeForUsingExpensifyModal() { +function PurposeForUsingExpensifyModal(props) { const {translate} = useLocalize(); const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); const [isModalOpen, setIsModalOpen] = useState(true); const theme = useTheme(); + useEffect(() => { + const navigationState = props.navigation.getState(); + const routes = lodashGet(navigationState, 'routes', []); + const currentRoute = routes[navigationState.index]; + if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) { + return; + } + if (lodashGet(props.demoInfo, 'money2020.isBeginningDemo', false)) { + return; + } + Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.isLoading]); + // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { track: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + @@ -181,6 +198,7 @@ PurposeForUsingExpensifyModal.displayName = 'AddPaymentMethodMenu'; export default compose( withWindowDimensions, + withNavigation, withOnyx({ session: { key: ONYXKEYS.SESSION, diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 7fd7adeafa96..7b5a092014fa 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -25,7 +25,7 @@ type Route = { type ShowParams = { routes: Route[]; - showCreateMenu?: () => void; + showEngagementModal?: () => void; showPopoverMenu?: () => boolean; }; @@ -57,6 +57,32 @@ Onyx.connect({ }, }); +Onyx.connect({ + key: ONYXKEYS.NVP_INTRO_SELECTED, + initWithStoredValues: false, + callback: (value) => { + // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic + // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 + + isFirstTimeNewExpensifyUser = value ?? undefined; + + checkOnReady(); + }, +}); + +Onyx.connect({ + key: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL, + initWithStoredValues: false, + callback: (value) => { + // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic + // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 + + isFirstTimeNewExpensifyUser = value ?? undefined; + + checkOnReady(); + }, +}); + Onyx.connect({ key: ONYXKEYS.IS_LOADING_REPORT_DATA, initWithStoredValues: false, @@ -110,7 +136,7 @@ Onyx.connect({ /** * Shows a welcome action on first login */ -function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => false}: ShowParams) { +function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => false}: ShowParams) { isReadyPromise.then(() => { if (!isFirstTimeNewExpensifyUser) { return; @@ -158,7 +184,7 @@ function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => false} // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the create menu. if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute) { - showCreateMenu(); + showEngagementModal(); } // Update isFirstTimeNewExpensifyUser so the Welcome logic doesn't run again From a1e53ccf222fb3ccdb03f0cd61699528c09b2383 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 12 Dec 2023 17:18:07 -0700 Subject: [PATCH 29/90] Fix import of style utils --- src/components/PurposeForUsingExpensifyModal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 1f294a2a246c..e6d323dac29e 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -9,7 +9,7 @@ import useThemeStyles from "@styles/useThemeStyles"; import useTheme from '@styles/themes/useTheme'; import useWindowDimensions from "@hooks/useWindowDimensions"; import * as Report from '@userActions/Report'; -import * as StyleUtils from "@styles/StyleUtils"; +import useStyleUtils from "@styles/useStyleUtils"; import SCREENS from "@src/SCREENS"; import {View} from "react-native"; import LottieAnimations from "./LottieAnimations"; @@ -42,6 +42,7 @@ const defaultProps = { function PurposeForUsingExpensifyModal(props) { const {translate} = useLocalize(); + const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); const [isModalOpen, setIsModalOpen] = useState(true); From 0a815733ddfc84f10cbacaeb3f0c916b16d23344 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 13 Dec 2023 17:03:26 -0700 Subject: [PATCH 30/90] Update for typescript --- src/libs/actions/Report.ts | 53 ++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index fa9d0a4cc1af..e3ae9d9415e8 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2438,22 +2438,20 @@ function getReportPrivateNote(reportID: string) { * - Adding one comment * - Adding one attachment * - Add both a comment and attachment simultaneously - * - * @param {String} text - * @param {String} choice */ -function completeEngagementModal( text , choice) { +function completeEngagementModal(text: string, choice: string) { const commandName = 'CompleteEngagementModal'; const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; - const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, null, conciergeAccountID); - const reportCommentAction = reportComment.reportAction; + const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, undefined, conciergeAccountID); + const reportCommentAction: Partial = reportComment.reportAction; + const lastComment = reportCommentAction?.message?.[0]; + const lastCommentText = ReportUtils.formatReportLastMessageText(lastComment?.text ?? ''); const reportCommentText = reportComment.commentText; const currentTime = DateUtils.getDBTime(); - const lastCommentText = ReportUtils.formatReportLastMessageText(reportCommentAction.message[0].text); - const optimisticReport = { + const optimisticReport: Partial = { lastVisibleActionCreated: currentTime, - lastMessageTranslationKey: lodashGet(reportCommentAction, 'message[0].translationKey', ''), + lastMessageTranslationKey: lastComment?.translationKey ?? '', lastMessageText: lastCommentText, lastMessageHtml: lastCommentText, lastActorAccountID: currentUserAccountID, @@ -2461,27 +2459,38 @@ function completeEngagementModal( text , choice) { }; const conciergeChatReport = ReportUtils.getChatByParticipants([conciergeAccountID]); - conciergeChatReportID = conciergeChatReport.reportID; - debugger; + conciergeChatReportID = conciergeChatReport?.reportID; + + const report = ReportUtils.getReport(conciergeChatReportID); - if (ReportUtils.getReportNotificationPreference(ReportUtils.getReport(conciergeChatReportID)) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { + if (isNotEmptyObject(report) && ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { optimisticReport.notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; } // Optimistically add the new actions to the store before waiting to save them to the server - const optimisticReportActions = {}; - optimisticReportActions[reportCommentAction.reportActionID] = reportCommentAction; + const optimisticReportActions: OnyxCollection> = {}; + if (reportCommentAction?.reportActionID) { + optimisticReportActions[reportCommentAction.reportActionID] = reportCommentAction; + } + type CompleteEngagementParameters = { + reportID: string; + reportActionID?: string; + commentReportActionID?: string | null; + reportComment?: string; + engagementChoice: string, + timezone?: string; + }; - const parameters = { - reportID: conciergeChatReportID, + const parameters: CompleteEngagementParameters = { + reportID: conciergeChatReportID ?? '', reportActionID: reportCommentAction.reportActionID, reportComment: reportCommentText, engagementChoice: choice, }; - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${conciergeChatReportID}`, @@ -2499,11 +2508,11 @@ function completeEngagementModal( text , choice) { }, ]; - const successData = [ + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, - value: _.mapObject(optimisticReportActions, () => ({pendingAction: null})), + value: {[reportCommentAction.reportActionID]: {pendingAction: null}}, } ]; @@ -2523,7 +2532,7 @@ function completeEngagementModal( text , choice) { optimisticData, successData, }); - notifyNewAction(conciergeChatReportID, reportCommentAction.actorAccountID, reportCommentAction.reportActionID); + notifyNewAction(conciergeChatReportID ?? '', reportCommentAction.actorAccountID, reportCommentAction.reportActionID); } function dismissEngagementModal() { @@ -2533,10 +2542,10 @@ function dismissEngagementModal() { value: true, }; - const optimisticData = [ + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: 'ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL', + key: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL, value: true, }, ]; From 0773d9e5be8a3bf89516036b2e7106f66f35dfd6 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 13 Dec 2023 19:59:24 -0700 Subject: [PATCH 31/90] Create new type and fix welcome.ts --- src/ONYXKEYS.ts | 2 ++ src/libs/actions/Welcome.ts | 12 ++++++------ src/types/onyx/IntroSelected.ts | 11 +++++++++++ src/types/onyx/index.ts | 2 ++ 4 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 src/types/onyx/IntroSelected.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index e0c04e07f3f4..92e4b062bf29 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -397,6 +397,8 @@ type OnyxValues = { [ONYXKEYS.FOCUS_MODE_NOTIFICATION]: boolean; [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: Record; [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoint[]; + [ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL]: boolean; + [ONYXKEYS.NVP_INTRO_SELECTED]: OnyxTypes.IntroSelected; [ONYXKEYS.PUSH_NOTIFICATIONS_ENABLED]: boolean; [ONYXKEYS.PLAID_DATA]: OnyxTypes.PlaidData; [ONYXKEYS.IS_PLAID_DISABLED]: boolean; diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 40652b9f8994..100653c14f6a 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -15,6 +15,8 @@ let isReadyPromise = new Promise((resolve) => { }); let isFirstTimeNewExpensifyUser: boolean | undefined; +let hasDismissedModal: boolean | undefined; +let hasSelectedChoice: boolean | undefined; let isLoadingReportData = true; let currentUserAccountID: number | undefined; @@ -59,12 +61,11 @@ Onyx.connect({ Onyx.connect({ key: ONYXKEYS.NVP_INTRO_SELECTED, - initWithStoredValues: false, + initWithStoredValues: true, callback: (value) => { // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 - - isFirstTimeNewExpensifyUser = value ?? undefined; + hasSelectedChoice = !!value; checkOnReady(); }, @@ -72,12 +73,11 @@ Onyx.connect({ Onyx.connect({ key: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL, - initWithStoredValues: false, + initWithStoredValues: true, callback: (value) => { // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 - - isFirstTimeNewExpensifyUser = value ?? undefined; + hasDismissedModal = value ?? false; checkOnReady(); }, diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts new file mode 100644 index 000000000000..d0a9def4f49a --- /dev/null +++ b/src/types/onyx/IntroSelected.ts @@ -0,0 +1,11 @@ +import * as OnyxCommon from './OnyxCommon'; + +type IntroSelected = { + /** The choice that the user selected in the engagement modal */ + choice: string; +}; + +type LoginList = Record; + +export default IntroSelected; +export type {LoginList}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 110bdb024a8c..ca09e300fbf4 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -12,6 +12,7 @@ import Download from './Download'; import Form, {AddDebitCardForm, DateOfBirthForm} from './Form'; import FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import Fund, {FundList} from './Fund'; +import IntroSelected from './IntroSelected'; import IOU from './IOU'; import Locale from './Locale'; import Login, {LoginList} from './Login'; @@ -75,6 +76,7 @@ export type { FrequentlyUsedEmoji, Fund, FundList, + IntroSelected, IOU, Locale, Login, From e52c81e8ff63afa80ac9aa6e360d613e217feb56 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 13 Dec 2023 19:59:46 -0700 Subject: [PATCH 32/90] Don't check for isLoading and default to hidden --- src/components/PurposeForUsingExpensifyModal.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index e6d323dac29e..6de5043ea8c0 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -45,7 +45,7 @@ function PurposeForUsingExpensifyModal(props) { const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); - const [isModalOpen, setIsModalOpen] = useState(true); + const [isModalOpen, setIsModalOpen] = useState(false); const theme = useTheme(); useEffect(() => { @@ -58,9 +58,10 @@ function PurposeForUsingExpensifyModal(props) { if (lodashGet(props.demoInfo, 'money2020.isBeginningDemo', false)) { return; } + debugger; Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.isLoading]); + }, []); // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { From 08e88435946231adcfadd6d8095f8f477e4b3fd8 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 13 Dec 2023 20:00:03 -0700 Subject: [PATCH 33/90] Also check for nvps before showing modal --- src/libs/actions/Welcome.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 100653c14f6a..216b5b2425e3 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -39,7 +39,8 @@ type ShowParams = { * - Whether we have loaded all reports the server knows about */ function checkOnReady() { - if (isFirstTimeNewExpensifyUser === undefined || isLoadingReportData) { + debugger; + if (isFirstTimeNewExpensifyUser === undefined || isLoadingReportData || hasSelectedChoice === undefined || hasDismissedModal === undefined) { return; } @@ -181,9 +182,10 @@ function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => f return; } + debugger; // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the create menu. - if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute) { + if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal) { showEngagementModal(); } From 4d7030368ec3720432fc6432cbbb3055cf21ee8b Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 18 Dec 2023 17:59:26 -0700 Subject: [PATCH 34/90] fix import order --- src/components/PurposeForUsingExpensifyModal.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 12342016b943..fe446c4adb33 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -5,13 +5,17 @@ import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import useThemeStyles from "@styles/useThemeStyles"; -import useTheme from '@styles/themes/useTheme'; +import useThemeStyles from "@hooks/useThemeStyles"; +import useTheme from '@hooks/useTheme'; import useWindowDimensions from "@hooks/useWindowDimensions"; import * as Report from '@userActions/Report'; -import useStyleUtils from "@styles/useStyleUtils"; +import useStyleUtils from "@hooks/useStyleUtils"; import SCREENS from "@src/SCREENS"; import {View} from "react-native"; +import NAVIGATORS from "@src/NAVIGATORS"; +import * as Welcome from "@userActions/Welcome"; +import lodashGet from "lodash/get"; +import withNavigation from "./withNavigation"; import LottieAnimations from "./LottieAnimations"; import Text from "./Text"; import Lottie from "./Lottie"; @@ -20,10 +24,6 @@ import MenuItemList from "./MenuItemList"; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import Modal from "./Modal"; import * as Expensicons from './Icon/Expensicons'; -import lodashGet from "lodash/get"; -import NAVIGATORS from "@src/NAVIGATORS"; -import * as Welcome from "@userActions/Welcome"; -import withNavigation from "@components/withNavigation"; const propTypes = { From c68d7285522052a1d2754083ffdcd199ff141c4f Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 19 Dec 2023 12:15:39 -0700 Subject: [PATCH 35/90] Check for number of policies --- src/libs/actions/Welcome.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 17ffc3821457..daf024f885b6 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -6,6 +6,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import OnyxPolicy from '@src/types/onyx/Policy'; +import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import Report from '@src/types/onyx/Report'; import * as Policy from './Policy'; @@ -39,9 +40,6 @@ type ShowParams = { * - Whether we have loaded all reports the server knows about */ function checkOnReady() { - if (allPolicies) { - debugger; - } if (isFirstTimeNewExpensifyUser === undefined || isLoadingReportData || hasSelectedChoice === undefined || hasDismissedModal === undefined) { return; } @@ -108,7 +106,7 @@ Onyx.connect({ }, }); -const allPolicies: OnyxCollection = {}; +const allPolicies: OnyxCollection | EmptyObject = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, callback: (val, key) => { @@ -186,7 +184,7 @@ function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => f // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the engagement modal. - if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal) { + if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal && Object.keys(allPolicies ?? {}).length === 1) { showEngagementModal(); } From 17dbbe6a56afe74dccbd4d236d2d5c7ee7265336 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 19 Dec 2023 15:38:42 -0700 Subject: [PATCH 36/90] Style --- .../PurposeForUsingExpensifyModal.js | 26 +++++++++---------- src/libs/actions/Welcome.ts | 2 +- src/pages/home/ReportScreen.js | 1 - .../FloatingActionButtonAndPopover.js | 4 --- src/pages/home/sidebar/SidebarScreen/index.js | 2 +- .../sidebar/SidebarScreen/index.native.js | 2 +- src/types/onyx/IntroSelected.ts | 5 ---- 7 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index fe446c4adb33..593e3086a2e6 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -176,19 +176,19 @@ function PurposeForUsingExpensifyModal(props) { iconFill={theme.iconColorfulBackground} /> - - - {translate('purposeForExpensify.welcomeMessage')} - - {translate('purposeForExpensify.welcomeSubtitle')} - - + + + {translate('purposeForExpensify.welcomeMessage')} + + {translate('purposeForExpensify.welcomeSubtitle')} + + ); } diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index daf024f885b6..838e9e200899 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -6,7 +6,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import OnyxPolicy from '@src/types/onyx/Policy'; -import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; +import {EmptyObject} from '@src/types/utils/EmptyObject'; import Report from '@src/types/onyx/Report'; import * as Policy from './Policy'; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index f2daec6145fe..d6249c0a28eb 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -35,7 +35,6 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import PurposeForUsingExpensifyModal from '@components/PurposeForUsingExpensifyModal'; import HeaderView from './HeaderView'; import reportActionPropTypes from './report/reportActionPropTypes'; import ReportActionsView from './report/ReportActionsView'; diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index e63e7e522f7d..9c2028c63677 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -1,4 +1,3 @@ -import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; import {View} from 'react-native'; @@ -20,12 +19,9 @@ import * as IOU from '@userActions/IOU'; import * as Policy from '@userActions/Policy'; import * as Session from '@userActions/Session'; import * as Task from '@userActions/Task'; -import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; /** * @param {Object} [policy] diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js index 9c099da75d7d..00136826e13c 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.js +++ b/src/pages/home/sidebar/SidebarScreen/index.js @@ -2,9 +2,9 @@ import React, {useCallback, useRef} from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; +import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; -import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; function SidebarScreen(props) { const popoverModal = useRef(null); diff --git a/src/pages/home/sidebar/SidebarScreen/index.native.js b/src/pages/home/sidebar/SidebarScreen/index.native.js index 683afd9168e7..ddda0019ea5f 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.native.js +++ b/src/pages/home/sidebar/SidebarScreen/index.native.js @@ -2,9 +2,9 @@ import React from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; +import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; -import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; function SidebarScreen(props) { const {isSmallScreenWidth} = useWindowDimensions(); diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index d0a9def4f49a..f7446cdd7a4c 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -1,11 +1,6 @@ -import * as OnyxCommon from './OnyxCommon'; - type IntroSelected = { /** The choice that the user selected in the engagement modal */ choice: string; }; -type LoginList = Record; - export default IntroSelected; -export type {LoginList}; From 356db316c7efcae0abb1ecf78ad73776c0a2ddfb Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 19 Dec 2023 15:44:53 -0700 Subject: [PATCH 37/90] import order --- src/pages/home/sidebar/SidebarScreen/index.js | 2 +- src/pages/home/sidebar/SidebarScreen/index.native.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js index 00136826e13c..6b390c524aad 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.js +++ b/src/pages/home/sidebar/SidebarScreen/index.js @@ -1,8 +1,8 @@ import React, {useCallback, useRef} from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; -import BaseSidebarScreen from './BaseSidebarScreen'; import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; +import BaseSidebarScreen from './BaseSidebarScreen'; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; diff --git a/src/pages/home/sidebar/SidebarScreen/index.native.js b/src/pages/home/sidebar/SidebarScreen/index.native.js index ddda0019ea5f..e69aa00c72f6 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.native.js +++ b/src/pages/home/sidebar/SidebarScreen/index.native.js @@ -1,8 +1,8 @@ import React from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; -import BaseSidebarScreen from './BaseSidebarScreen'; import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; +import BaseSidebarScreen from './BaseSidebarScreen'; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; From 2ba2966975ec916e2db1d40a3916068c68ad140e Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 19 Dec 2023 15:54:04 -0700 Subject: [PATCH 38/90] Prettier --- src/components/Icon/Expensicons.ts | 2 +- .../PurposeForUsingExpensifyModal.js | 65 ++++++++++--------- src/languages/en.ts | 4 +- src/languages/es.ts | 4 +- src/libs/actions/Report.ts | 9 ++- src/libs/actions/Welcome.ts | 2 +- src/pages/home/ReportScreen.js | 32 ++++----- .../FloatingActionButtonAndPopover.js | 2 - src/pages/home/sidebar/SidebarScreen/index.js | 2 +- .../sidebar/SidebarScreen/index.native.js | 2 +- 10 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 082b5b545cf8..a01ac4b62382 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -105,8 +105,8 @@ import ReceiptSearch from '@assets/images/receipt-search.svg'; import Receipt from '@assets/images/receipt.svg'; import Rotate from '@assets/images/rotate-image.svg'; import RotateLeft from '@assets/images/rotate-left.svg'; -import Send from '@assets/images/send.svg'; import Scan from '@assets/images/scan.svg'; +import Send from '@assets/images/send.svg'; import Shield from '@assets/images/shield.svg'; import AppleLogo from '@assets/images/signIn/apple-logo.svg'; import GoogleLogo from '@assets/images/signIn/google-logo.svg'; diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 593e3086a2e6..dd698a731f28 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -1,32 +1,31 @@ +import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useState, useCallback, useEffect} from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; +import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; +import * as Report from '@userActions/Report'; +import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; -import useThemeStyles from "@hooks/useThemeStyles"; -import useTheme from '@hooks/useTheme'; -import useWindowDimensions from "@hooks/useWindowDimensions"; -import * as Report from '@userActions/Report'; -import useStyleUtils from "@hooks/useStyleUtils"; -import SCREENS from "@src/SCREENS"; -import {View} from "react-native"; -import NAVIGATORS from "@src/NAVIGATORS"; -import * as Welcome from "@userActions/Welcome"; -import lodashGet from "lodash/get"; -import withNavigation from "./withNavigation"; -import LottieAnimations from "./LottieAnimations"; -import Text from "./Text"; -import Lottie from "./Lottie"; -import HeaderWithBackButton from "./HeaderWithBackButton"; -import MenuItemList from "./MenuItemList"; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; -import Modal from "./Modal"; +import SCREENS from '@src/SCREENS'; +import HeaderWithBackButton from './HeaderWithBackButton'; import * as Expensicons from './Icon/Expensicons'; +import Lottie from './Lottie'; +import LottieAnimations from './LottieAnimations'; +import MenuItemList from './MenuItemList'; +import Modal from './Modal'; +import Text from './Text'; +import withNavigation from './withNavigation'; +import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; const propTypes = { - /** Session info for the currently logged in user. */ session: PropTypes.shape({ /** Currently logged in user accountID */ @@ -64,7 +63,8 @@ function PurposeForUsingExpensifyModal(props) { // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { - track: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + + track: + 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + '\n' + '1. Press your avatar icon\n' + '2. Choose Workspaces\n' + @@ -76,18 +76,20 @@ function PurposeForUsingExpensifyModal(props) { '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms\n' + '2. Choose the + button in the chat compose window\n' + '3. Choose Request money\n' + - '4. Choose what kind of expense you\'d like to log, whether a manual expense, scanned receipt, or tracked distance.\n' + + "4. Choose what kind of expense you'd like to log, whether a manual expense, scanned receipt, or tracked distance.\n" + '\n' + - 'That\'ll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!', - submit: 'Hi there, to submit expenses for reimbursement, please:\n' + + "That'll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!", + submit: + 'Hi there, to submit expenses for reimbursement, please:\n' + '\n' + '1. Press the big green + button\n' + '2. Choose Request money\n' + '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance\n' + '4. Enter the email address or phone number of your boss\n' + '\n' + - 'And we\'ll take it from there to get you paid back. Please give it a shot and let me know how it goes!', - business: 'Great! To manage your team\'s expenses, create a workspace to keep everything contained:\n' + + "And we'll take it from there to get you paid back. Please give it a shot and let me know how it goes!", + business: + "Great! To manage your team's expenses, create a workspace to keep everything contained:\n" + '\n' + '1. Press your avatar icon\n' + '2. Choose Workspaces\n' + @@ -95,7 +97,8 @@ function PurposeForUsingExpensifyModal(props) { '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + '\n' + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', - chatSplit: 'Hi there, to split an expense such as with a friend, please:\n' + + chatSplit: + 'Hi there, to split an expense such as with a friend, please:\n' + '\n' + 'Press the big green + button\n' + 'Choose *Request money*\n' + @@ -106,8 +109,8 @@ function PurposeForUsingExpensifyModal(props) { 'Press *Add to split* when done adding friends\n' + 'Press Split to split the bill\n' + '\n' + - 'This will send a money request to each of your friends for however much they owe you, and we\'ll take care of getting you paid back. Thanks for asking, and let me know how it goes!', - } + "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", + }; const closeModal = useCallback(() => { Report.dismissEngagementModal(); @@ -116,8 +119,8 @@ function PurposeForUsingExpensifyModal(props) { const completeModalAndClose = (message, choice) => { Report.completeEngagementModal(message, choice); - setIsModalOpen(false) - } + setIsModalOpen(false); + }; const menuItems = [ { diff --git a/src/languages/en.ts b/src/languages/en.ts index 7ff0cc736464..c5e6b79817fe 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2024,10 +2024,10 @@ export default { purposeForExpensify: { track: 'Track my business expenses to file taxes', submit: 'Submit expenses to my employer to get paid back', - business: 'Manage my team\'s expenses', + business: "Manage my team's expenses", chatSplit: 'Chat and split expenses with friends', welcomeMessage: 'Welcome to Expensify', - welcomeSubtitle: 'What\'s your main purpose for using Expensify?', + welcomeSubtitle: "What's your main purpose for using Expensify?", }, violations: { allTagLevelsRequired: 'dummy.violations.allTagLevelsRequired', diff --git a/src/languages/es.ts b/src/languages/es.ts index d28eea1fbae0..4b3a55e9d8c3 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2511,10 +2511,10 @@ export default { purposeForExpensify: { track: 'Track my business expenses to file taxes', submit: 'Submit expenses to my employer to get paid back', - business: 'Manage my team\'s expenses', + business: "Manage my team's expenses", chatSplit: 'Chat and split expenses with friends', welcomeMessage: 'Welcome to Expensify', - welcomeSubtitle: 'What\'s your main purpose for using Expensify?', + welcomeSubtitle: "What's your main purpose for using Expensify?", }, violations: { allTagLevelsRequired: 'dummy.violations.allTagLevelsRequired', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index b910c69903d9..8030111d9d69 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2475,7 +2475,7 @@ function completeEngagementModal(text: string, choice: string) { reportActionID?: string; commentReportActionID?: string | null; reportComment?: string; - engagementChoice: string, + engagementChoice: string; timezone?: string; }; @@ -2484,7 +2484,6 @@ function completeEngagementModal(text: string, choice: string) { reportActionID: reportCommentAction.reportActionID, reportComment: reportCommentText, engagementChoice: choice, - }; const optimisticData: OnyxUpdate[] = [ @@ -2501,7 +2500,7 @@ function completeEngagementModal(text: string, choice: string) { { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_INTRO_SELECTED, - value: {choice} + value: {choice}, }, ]; @@ -2509,8 +2508,8 @@ function completeEngagementModal(text: string, choice: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, - value: {[reportCommentAction.reportActionID]: {pendingAction: null}}, - } + value: {[reportCommentAction.reportActionID]: {pendingAction: null}}, + }, ]; // Update the timezone if it's been 5 minutes from the last time the user added a comment diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 838e9e200899..380436b761c1 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -6,8 +6,8 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import OnyxPolicy from '@src/types/onyx/Policy'; -import {EmptyObject} from '@src/types/utils/EmptyObject'; import Report from '@src/types/onyx/Report'; +import {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; let resolveIsReadyPromise: (value?: Promise) => void | undefined; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index f2d8c60a821c..161b8aa8889d 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -138,22 +138,22 @@ function getReportID(route) { } function ReportScreen({ - betas, - route, - report, - reportMetadata, - reportActions, - accountManagerReportID, - personalDetails, - markReadyForHydration, - policies, - isSidebarLoaded, - viewportOffsetTop, - isComposerFullSize, - errors, - userLeavingStatus, - currentReportID, - }) { + betas, + route, + report, + reportMetadata, + reportActions, + accountManagerReportID, + personalDetails, + markReadyForHydration, + policies, + isSidebarLoaded, + viewportOffsetTop, + isComposerFullSize, + errors, + userLeavingStatus, + currentReportID, +}) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 9c2028c63677..a1b4789bcdef 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -146,8 +146,6 @@ function FloatingActionButtonAndPopover(props) { } }; - - useEffect(() => { if (!didScreenBecomeInactive()) { return; diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js index 6b390c524aad..e823d24b87fe 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.js +++ b/src/pages/home/sidebar/SidebarScreen/index.js @@ -1,7 +1,7 @@ import React, {useCallback, useRef} from 'react'; +import PurposeForUsingExpensifyModal from '@components/PurposeForUsingExpensifyModal'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; -import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; import BaseSidebarScreen from './BaseSidebarScreen'; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; diff --git a/src/pages/home/sidebar/SidebarScreen/index.native.js b/src/pages/home/sidebar/SidebarScreen/index.native.js index e69aa00c72f6..7f36e4ebfa22 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.native.js +++ b/src/pages/home/sidebar/SidebarScreen/index.native.js @@ -1,7 +1,7 @@ import React from 'react'; +import PurposeForUsingExpensifyModal from '@components/PurposeForUsingExpensifyModal'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; -import PurposeForUsingExpensifyModal from "@components/PurposeForUsingExpensifyModal"; import BaseSidebarScreen from './BaseSidebarScreen'; import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; From 1f3420cb676ee581c91cb0a797da8f6a32d66e72 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 19 Dec 2023 16:01:34 -0700 Subject: [PATCH 39/90] Remove unnecessary file --- docs/universal-darwin21 | 1 - 1 file changed, 1 deletion(-) delete mode 120000 docs/universal-darwin21 diff --git a/docs/universal-darwin21 b/docs/universal-darwin21 deleted file mode 120000 index 06de9bd9290c..000000000000 --- a/docs/universal-darwin21 +++ /dev/null @@ -1 +0,0 @@ -universal-darwin22 \ No newline at end of file From 874543fc062083268dd54d5d6332915e750c23b6 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 19 Dec 2023 16:27:05 -0700 Subject: [PATCH 40/90] Add prop type --- .../HeaderWithBackButton/headerWithBackButtonPropTypes.js | 3 +++ src/components/PurposeForUsingExpensifyModal.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js b/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js index 109e60adf672..2f7ac48b558b 100644 --- a/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js +++ b/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js @@ -96,6 +96,9 @@ const propTypes = { /** Whether we should navigate to report page when the route have a topMostReport */ shouldNavigateToTopMostReport: PropTypes.bool, + + /** Whether we should overlay the 3 dots menu */ + shouldOverlayDots: PropTypes.bool, }; export default propTypes; diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index dd698a731f28..ad0f23d6081c 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -162,6 +162,8 @@ function PurposeForUsingExpensifyModal(props) { type={isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED : CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED} isVisible={isModalOpen} onClose={closeModal} + shouldAddTopSafeAreaMargin={false} + shouldAddTopSafeAreaPadding={false} > Date: Tue, 19 Dec 2023 16:56:02 -0700 Subject: [PATCH 41/90] Fix typescript --- src/components/PurposeForUsingExpensifyModal.js | 2 -- src/libs/actions/Report.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index ad0f23d6081c..dd698a731f28 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -162,8 +162,6 @@ function PurposeForUsingExpensifyModal(props) { type={isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED : CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED} isVisible={isModalOpen} onClose={closeModal} - shouldAddTopSafeAreaMargin={false} - shouldAddTopSafeAreaPadding={false} > Date: Tue, 19 Dec 2023 17:28:07 -0700 Subject: [PATCH 42/90] Remove white padding --- src/components/PurposeForUsingExpensifyModal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index dd698a731f28..f5f417a8225d 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -162,6 +162,7 @@ function PurposeForUsingExpensifyModal(props) { type={isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED : CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED} isVisible={isModalOpen} onClose={closeModal} + innerContainerStyle={styles.pt0} > Date: Tue, 19 Dec 2023 17:49:16 -0700 Subject: [PATCH 43/90] Redirect to concierge chat after completing modal --- src/components/PurposeForUsingExpensifyModal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index f5f417a8225d..8845bbe5dafa 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -120,6 +120,7 @@ function PurposeForUsingExpensifyModal(props) { const completeModalAndClose = (message, choice) => { Report.completeEngagementModal(message, choice); setIsModalOpen(false); + Report.navigateToConciergeChat(); }; const menuItems = [ From 489b14806b7d50586a3c56e6194d36e0009e9357 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 20 Dec 2023 09:17:44 -0700 Subject: [PATCH 44/90] Add new param to show backdrop for modals --- src/components/Modal/BaseModal.tsx | 3 ++- src/components/Modal/types.ts | 3 +++ src/components/PurposeForUsingExpensifyModal.js | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 89640c56f5ef..620828290d9c 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -38,6 +38,7 @@ function BaseModal( onLayout, avoidKeyboard = false, children, + shouldShowBackdrop = false, }: BaseModalProps, ref: React.ForwardedRef, ) { @@ -185,7 +186,7 @@ function BaseModal( swipeDirection={swipeDirection} isVisible={isVisible} backdropColor={theme.overlay} - backdropOpacity={hideBackdrop ? 0 : variables.overlayOpacity} + backdropOpacity={!shouldShowBackdrop && hideBackdrop ? 0 : variables.overlayOpacity} backdropTransitionOutTiming={0} hasBackdrop={fullscreen} coverScreen={fullscreen} diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts index 172965b45fb2..1675114b4571 100644 --- a/src/components/Modal/types.ts +++ b/src/components/Modal/types.ts @@ -61,6 +61,9 @@ type BaseModalProps = WindowDimensionsProps & * See: https://github.com/react-native-modal/react-native-modal/pull/116 * */ hideModalContentWhileAnimating?: boolean; + + /** Should we show the background overlay around the modal */ + shouldShowBackdrop?: boolean; }; export default BaseModalProps; diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 8845bbe5dafa..f2565f6e0326 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -164,6 +164,7 @@ function PurposeForUsingExpensifyModal(props) { isVisible={isModalOpen} onClose={closeModal} innerContainerStyle={styles.pt0} + shouldShowBackdrop > Date: Wed, 20 Dec 2023 09:41:11 -0700 Subject: [PATCH 45/90] Allow all options to be on 2 lines --- src/components/PurposeForUsingExpensifyModal.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index f2565f6e0326..657b3eef85dc 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -131,6 +131,7 @@ function PurposeForUsingExpensifyModal(props) { iconRight: Expensicons.ArrowRight, onPress: () => completeModalAndClose(messageCopy.track, 'trackNewDot'), shouldShowRightIcon: true, + numberOfLinesTitle: 2, }, { key: 'purposeForExpensify.submit', @@ -139,6 +140,7 @@ function PurposeForUsingExpensifyModal(props) { iconRight: Expensicons.ArrowRight, onPress: () => completeModalAndClose(messageCopy.submit, 'submitNewDot'), shouldShowRightIcon: true, + numberOfLinesTitle: 2, }, { key: 'purposeForExpensify.business', @@ -147,6 +149,7 @@ function PurposeForUsingExpensifyModal(props) { iconRight: Expensicons.ArrowRight, onPress: () => completeModalAndClose(messageCopy.business, 'businessNewDot'), shouldShowRightIcon: true, + numberOfLinesTitle: 2, }, { key: 'purposeForExpensify.chatSplit', @@ -155,6 +158,7 @@ function PurposeForUsingExpensifyModal(props) { iconRight: Expensicons.ArrowRight, onPress: () => completeModalAndClose(messageCopy.chatSplit, 'chatSplitNewDot'), shouldShowRightIcon: true, + numberOfLinesTitle: 2, }, ]; From cf1a9ec5687873cd9d14e0a313d11fceabe537b0 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 20 Dec 2023 14:18:44 -0700 Subject: [PATCH 46/90] Revert background changes --- src/components/Modal/BaseModal.tsx | 3 +-- src/components/Modal/types.ts | 3 --- src/components/PurposeForUsingExpensifyModal.js | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 620828290d9c..89640c56f5ef 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -38,7 +38,6 @@ function BaseModal( onLayout, avoidKeyboard = false, children, - shouldShowBackdrop = false, }: BaseModalProps, ref: React.ForwardedRef, ) { @@ -186,7 +185,7 @@ function BaseModal( swipeDirection={swipeDirection} isVisible={isVisible} backdropColor={theme.overlay} - backdropOpacity={!shouldShowBackdrop && hideBackdrop ? 0 : variables.overlayOpacity} + backdropOpacity={hideBackdrop ? 0 : variables.overlayOpacity} backdropTransitionOutTiming={0} hasBackdrop={fullscreen} coverScreen={fullscreen} diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts index 1675114b4571..172965b45fb2 100644 --- a/src/components/Modal/types.ts +++ b/src/components/Modal/types.ts @@ -61,9 +61,6 @@ type BaseModalProps = WindowDimensionsProps & * See: https://github.com/react-native-modal/react-native-modal/pull/116 * */ hideModalContentWhileAnimating?: boolean; - - /** Should we show the background overlay around the modal */ - shouldShowBackdrop?: boolean; }; export default BaseModalProps; diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 657b3eef85dc..2c7b61ff5bcf 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -168,7 +168,6 @@ function PurposeForUsingExpensifyModal(props) { isVisible={isModalOpen} onClose={closeModal} innerContainerStyle={styles.pt0} - shouldShowBackdrop > Date: Wed, 20 Dec 2023 14:19:30 -0700 Subject: [PATCH 47/90] Fix name --- src/components/PurposeForUsingExpensifyModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 2c7b61ff5bcf..8452edc6c8da 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -204,7 +204,7 @@ function PurposeForUsingExpensifyModal(props) { PurposeForUsingExpensifyModal.propTypes = propTypes; PurposeForUsingExpensifyModal.defaultProps = defaultProps; -PurposeForUsingExpensifyModal.displayName = 'AddPaymentMethodMenu'; +PurposeForUsingExpensifyModal.displayName = 'PurposeForUsingExpensifyModal'; export default compose( withWindowDimensions, From 4e0eb0df0652ffd0aeef450fce227fe21d165520 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Wed, 20 Dec 2023 15:28:27 -0700 Subject: [PATCH 48/90] Re-add backdrop --- src/components/Modal/BaseModal.tsx | 3 ++- src/components/Modal/types.ts | 3 +++ src/components/PurposeForUsingExpensifyModal.js | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 89640c56f5ef..620828290d9c 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -38,6 +38,7 @@ function BaseModal( onLayout, avoidKeyboard = false, children, + shouldShowBackdrop = false, }: BaseModalProps, ref: React.ForwardedRef, ) { @@ -185,7 +186,7 @@ function BaseModal( swipeDirection={swipeDirection} isVisible={isVisible} backdropColor={theme.overlay} - backdropOpacity={hideBackdrop ? 0 : variables.overlayOpacity} + backdropOpacity={!shouldShowBackdrop && hideBackdrop ? 0 : variables.overlayOpacity} backdropTransitionOutTiming={0} hasBackdrop={fullscreen} coverScreen={fullscreen} diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts index 172965b45fb2..1675114b4571 100644 --- a/src/components/Modal/types.ts +++ b/src/components/Modal/types.ts @@ -61,6 +61,9 @@ type BaseModalProps = WindowDimensionsProps & * See: https://github.com/react-native-modal/react-native-modal/pull/116 * */ hideModalContentWhileAnimating?: boolean; + + /** Should we show the background overlay around the modal */ + shouldShowBackdrop?: boolean; }; export default BaseModalProps; diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 8452edc6c8da..aaf352bae53e 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -168,6 +168,7 @@ function PurposeForUsingExpensifyModal(props) { isVisible={isModalOpen} onClose={closeModal} innerContainerStyle={styles.pt0} + shouldShowBackdrop > Date: Thu, 21 Dec 2023 08:22:07 -0700 Subject: [PATCH 49/90] Add custom backdrop --- src/components/Modal/BaseModal.tsx | 6 ++++-- src/components/Modal/types.ts | 4 ++-- src/components/PurposeForUsingExpensifyModal.js | 2 +- src/libs/Navigation/AppNavigator/Navigators/Overlay.tsx | 6 ++++-- src/styles/index.ts | 4 ++++ 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 620828290d9c..538daf0eb3cb 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -13,6 +13,7 @@ import useNativeDriver from '@libs/useNativeDriver'; import variables from '@styles/variables'; import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; +import Overlay from '@libs/Navigation/AppNavigator/Navigators/Overlay'; import BaseModalProps from './types'; function BaseModal( @@ -38,7 +39,7 @@ function BaseModal( onLayout, avoidKeyboard = false, children, - shouldShowBackdrop = false, + shouldUseCustomBackdrop = false, }: BaseModalProps, ref: React.ForwardedRef, ) { @@ -186,7 +187,7 @@ function BaseModal( swipeDirection={swipeDirection} isVisible={isVisible} backdropColor={theme.overlay} - backdropOpacity={!shouldShowBackdrop && hideBackdrop ? 0 : variables.overlayOpacity} + backdropOpacity={!shouldUseCustomBackdrop && hideBackdrop ? 0 : variables.overlayOpacity} backdropTransitionOutTiming={0} hasBackdrop={fullscreen} coverScreen={fullscreen} @@ -202,6 +203,7 @@ function BaseModal( statusBarTranslucent={statusBarTranslucent} onLayout={onLayout} avoidKeyboard={avoidKeyboard} + customBackdrop={shouldUseCustomBackdrop ? : undefined} > diff --git a/src/styles/index.ts b/src/styles/index.ts index 905c25f4f7d8..8ad7be0a893a 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -2858,6 +2858,10 @@ const styles = (theme: ThemeColors) => outlineStyle: 'none', }, + boxShadowNone: { + boxShadow: 'none', + }, + cardStyleNavigator: { overflow: 'hidden', height: '100%', From fdf8429acf823d55824c0a72441dba5cad6b6fb1 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 21 Dec 2023 09:20:34 -0700 Subject: [PATCH 50/90] Add proper spanish translations --- src/languages/en.ts | 8 ++++---- src/languages/es.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 08023948326f..174bebaf96f4 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2023,12 +2023,12 @@ export default { copyReferralLink: 'Copy invite link', }, purposeForExpensify: { - track: 'Track my business expenses to file taxes', - submit: 'Submit expenses to my employer to get paid back', + track: 'Track business spend for taxes', + submit: 'Get paid back by my employer', business: "Manage my team's expenses", - chatSplit: 'Chat and split expenses with friends', + chatSplit: 'Chat and split bills with friends', welcomeMessage: 'Welcome to Expensify', - welcomeSubtitle: "What's your main purpose for using Expensify?", + welcomeSubtitle: 'What would you like to do?', }, violations: { allTagLevelsRequired: 'dummy.violations.allTagLevelsRequired', diff --git a/src/languages/es.ts b/src/languages/es.ts index e754f0554701..61d1a7bed3b4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2510,12 +2510,12 @@ export default { copyReferralLink: 'Copiar enlace de invitación', }, purposeForExpensify: { - track: 'Track my business expenses to file taxes', - submit: 'Submit expenses to my employer to get paid back', - business: "Manage my team's expenses", - chatSplit: 'Chat and split expenses with friends', - welcomeMessage: 'Welcome to Expensify', - welcomeSubtitle: "What's your main purpose for using Expensify?", + track: 'Seguimiento de los gastos de empresa para fines fiscales' , + submit: 'Reclamar gastos a mi empleador', + business: 'Gestionar los gastos de mi equipo', + chatSplit: 'Chatea y divide gastos con tus amigos', + welcomeMessage: 'Bienvenido a Expensify', + welcomeSubtitle: '¿Qué te gustaría hacer?', }, violations: { allTagLevelsRequired: 'dummy.violations.allTagLevelsRequired', From 23b3f8911cb8a58a0380dffd8bd9af84b3530601 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 21 Dec 2023 13:29:10 -0700 Subject: [PATCH 51/90] only use custom backdrop for large screens --- src/components/PurposeForUsingExpensifyModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index c53117dca6d0..3522ab8586dd 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -168,7 +168,7 @@ function PurposeForUsingExpensifyModal(props) { isVisible={isModalOpen} onClose={closeModal} innerContainerStyle={styles.pt0} - shouldUseCustomBackdrop + shouldUseCustomBackdrop={!isSmallScreenWidth} > Date: Thu, 21 Dec 2023 15:00:43 -0700 Subject: [PATCH 52/90] Shrink image when screen is small --- .../PurposeForUsingExpensifyModal.js | 23 +++++++++++++++---- .../utils/generators/ModalStyleUtils.ts | 1 + 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 3522ab8586dd..52774c315d86 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -9,6 +9,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; +import variables from '@styles/variables'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; @@ -58,6 +59,7 @@ function PurposeForUsingExpensifyModal(props) { return; } Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); + setIsModalOpen(true); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -162,19 +164,32 @@ function PurposeForUsingExpensifyModal(props) { }, ]; + let containerStyle; + let lottieContainerStyle; + let lottieStyle; + if (isSmallScreenWidth) { + containerStyle = {...styles.pt0, ...styles.flex1, marginTop: variables.contentHeaderHeight}; + lottieContainerStyle = [StyleUtils.getBackgroundColorStyle(theme.PAGE_THEMES[SCREENS.SETTINGS.WORKSPACES].backgroundColor), styles.flex1]; + lottieStyle = {width: undefined, ...styles.h100, ...styles.alignSelfCenter}; + } else { + containerStyle = styles.pt0; + lottieContainerStyle = StyleUtils.getBackgroundColorStyle(theme.PAGE_THEMES[SCREENS.SETTINGS.WORKSPACES].backgroundColor); + lottieStyle = styles.w100; + } + return ( - + diff --git a/src/styles/utils/generators/ModalStyleUtils.ts b/src/styles/utils/generators/ModalStyleUtils.ts index 67faec504d61..1ea57ebaf54d 100644 --- a/src/styles/utils/generators/ModalStyleUtils.ts +++ b/src/styles/utils/generators/ModalStyleUtils.ts @@ -187,6 +187,7 @@ const createModalStyleUtils: StyleUtilGenerator = ({the swipeDirection = undefined; animationIn = 'slideInUp'; animationOut = 'slideOutDown'; + shouldAddTopSafeAreaMargin = true; break; case CONST.MODAL.MODAL_TYPE.POPOVER: modalStyle = { From 9adf07d738fa552d7ea1a7ae449c383e955b5bbc Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 21 Dec 2023 15:23:53 -0700 Subject: [PATCH 53/90] Revert resizing changes --- .../PurposeForUsingExpensifyModal.js | 23 ++++--------------- .../utils/generators/ModalStyleUtils.ts | 1 - 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 52774c315d86..3522ab8586dd 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -9,7 +9,6 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; -import variables from '@styles/variables'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; @@ -59,7 +58,6 @@ function PurposeForUsingExpensifyModal(props) { return; } Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); - setIsModalOpen(true); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -164,32 +162,19 @@ function PurposeForUsingExpensifyModal(props) { }, ]; - let containerStyle; - let lottieContainerStyle; - let lottieStyle; - if (isSmallScreenWidth) { - containerStyle = {...styles.pt0, ...styles.flex1, marginTop: variables.contentHeaderHeight}; - lottieContainerStyle = [StyleUtils.getBackgroundColorStyle(theme.PAGE_THEMES[SCREENS.SETTINGS.WORKSPACES].backgroundColor), styles.flex1]; - lottieStyle = {width: undefined, ...styles.h100, ...styles.alignSelfCenter}; - } else { - containerStyle = styles.pt0; - lottieContainerStyle = StyleUtils.getBackgroundColorStyle(theme.PAGE_THEMES[SCREENS.SETTINGS.WORKSPACES].backgroundColor); - lottieStyle = styles.w100; - } - return ( - + diff --git a/src/styles/utils/generators/ModalStyleUtils.ts b/src/styles/utils/generators/ModalStyleUtils.ts index 1ea57ebaf54d..67faec504d61 100644 --- a/src/styles/utils/generators/ModalStyleUtils.ts +++ b/src/styles/utils/generators/ModalStyleUtils.ts @@ -187,7 +187,6 @@ const createModalStyleUtils: StyleUtilGenerator = ({the swipeDirection = undefined; animationIn = 'slideInUp'; animationOut = 'slideOutDown'; - shouldAddTopSafeAreaMargin = true; break; case CONST.MODAL.MODAL_TYPE.POPOVER: modalStyle = { From daf05b61ddf9dc47e11da0e172b8c7521684c093 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 21 Dec 2023 15:44:45 -0700 Subject: [PATCH 54/90] Scrollview --- .../PurposeForUsingExpensifyModal.js | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 3522ab8586dd..6f8fd2b1a238 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -1,7 +1,7 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useState} from 'react'; -import {View} from 'react-native'; +import {View, ScrollView} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -170,35 +170,37 @@ function PurposeForUsingExpensifyModal(props) { innerContainerStyle={styles.pt0} shouldUseCustomBackdrop={!isSmallScreenWidth} > - - + + + + + + + {translate('purposeForExpensify.welcomeMessage')} + + {translate('purposeForExpensify.welcomeSubtitle')} + + - - - - - {translate('purposeForExpensify.welcomeMessage')} - - {translate('purposeForExpensify.welcomeSubtitle')} - - + ); } From 998c2e9fbd15fb780717ebb2ecba7ac2b6c86d75 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 21 Dec 2023 15:49:09 -0700 Subject: [PATCH 55/90] Style --- src/components/Modal/BaseModal.tsx | 4 ++-- src/components/PurposeForUsingExpensifyModal.js | 2 +- src/languages/es.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 538daf0eb3cb..39132e2af686 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -9,11 +9,11 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import ComposerFocusManager from '@libs/ComposerFocusManager'; +import Overlay from '@libs/Navigation/AppNavigator/Navigators/Overlay'; import useNativeDriver from '@libs/useNativeDriver'; import variables from '@styles/variables'; import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; -import Overlay from '@libs/Navigation/AppNavigator/Navigators/Overlay'; import BaseModalProps from './types'; function BaseModal( @@ -203,7 +203,7 @@ function BaseModal( statusBarTranslucent={statusBarTranslucent} onLayout={onLayout} avoidKeyboard={avoidKeyboard} - customBackdrop={shouldUseCustomBackdrop ? : undefined} + customBackdrop={shouldUseCustomBackdrop ? : undefined} > Date: Thu, 4 Jan 2024 17:02:03 -0700 Subject: [PATCH 56/90] Change keys' --- src/components/PurposeForUsingExpensifyModal.js | 16 ++++++++-------- src/languages/en.ts | 4 ++-- src/languages/es.ts | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index 38d63214673e..ace35019ed80 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -129,7 +129,7 @@ function PurposeForUsingExpensifyModal(props) { title: translate('purposeForExpensify.track'), icon: Expensicons.ReceiptSearch, iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.track, 'trackNewDot'), + onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), shouldShowRightIcon: true, numberOfLinesTitle: 2, }, @@ -138,25 +138,25 @@ function PurposeForUsingExpensifyModal(props) { title: translate('purposeForExpensify.submit'), icon: Expensicons.Scan, iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.submit, 'submitNewDot'), + onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), shouldShowRightIcon: true, numberOfLinesTitle: 2, }, { - key: 'purposeForExpensify.business', - title: translate('purposeForExpensify.business'), + key: 'purposeForExpensify.manageTeam', + title: translate('purposeForExpensify.manageTeam'), icon: Expensicons.MoneyBag, iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.business, 'businessNewDot'), + onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), shouldShowRightIcon: true, numberOfLinesTitle: 2, }, { - key: 'purposeForExpensify.chatSplit', - title: translate('purposeForExpensify.chatSplit'), + key: 'purposeForExpensify.splitChat', + title: translate('purposeForExpensify.splitChat'), icon: Expensicons.Briefcase, iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.chatSplit, 'chatSplitNewDot'), + onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), shouldShowRightIcon: true, numberOfLinesTitle: 2, }, diff --git a/src/languages/en.ts b/src/languages/en.ts index 9d76fbd92a73..753dc19922d7 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2037,8 +2037,8 @@ export default { purposeForExpensify: { track: 'Track business spend for taxes', submit: 'Get paid back by my employer', - business: "Manage my team's expenses", - chatSplit: 'Chat and split bills with friends', + manageTeam: "Manage my team's expenses", + splitChat: 'Chat and split bills with friends', welcomeMessage: 'Welcome to Expensify', welcomeSubtitle: 'What would you like to do?', }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 74efd36b4c94..ef9719d04e84 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2524,8 +2524,8 @@ export default { purposeForExpensify: { track: 'Seguimiento de los gastos de empresa para fines fiscales', submit: 'Reclamar gastos a mi empleador', - business: 'Gestionar los gastos de mi equipo', - chatSplit: 'Chatea y divide gastos con tus amigos', + manageTeam: 'Gestionar los gastos de mi equipo', + splitChat: 'Chatea y divide gastos con tus amigos', welcomeMessage: 'Bienvenido a Expensify', welcomeSubtitle: '¿Qué te gustaría hacer?', }, From 5bdc2c6395cc0dc72e15b9f991fc7af420d495dc Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 4 Jan 2024 18:12:01 -0700 Subject: [PATCH 57/90] Style --- src/libs/actions/Welcome.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 83c742da6ca2..3f17ced0ea0e 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -6,9 +6,9 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; import type OnyxPolicy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; let resolveIsReadyPromise: (value?: Promise) => void | undefined; From cf23709193c0b072bd65c2f1064b7525203b2acd Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 4 Jan 2024 18:14:48 -0700 Subject: [PATCH 58/90] Fix props --- src/components/HeaderWithBackButton/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/HeaderWithBackButton/types.ts b/src/components/HeaderWithBackButton/types.ts index 9ffb0b5ef2f3..e5c8860c8fe0 100644 --- a/src/components/HeaderWithBackButton/types.ts +++ b/src/components/HeaderWithBackButton/types.ts @@ -108,6 +108,9 @@ type HeaderWithBackButtonProps = Partial & { /** Whether we should enable detail page navigation */ shouldEnableDetailPageNavigation?: boolean; + + /** Whether we should overlay the 3 dots menu */ + shouldOverlayDots?: boolean; }; export default HeaderWithBackButtonProps; From 4df4d3aaa85d864949854068fc3b63a92ddd4255 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 5 Jan 2024 12:12:13 -0700 Subject: [PATCH 59/90] Fix import error --- tests/unit/CalendarPickerTest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/CalendarPickerTest.js b/tests/unit/CalendarPickerTest.js index e1c11fbb8ca8..3aab3a13c1c3 100644 --- a/tests/unit/CalendarPickerTest.js +++ b/tests/unit/CalendarPickerTest.js @@ -7,6 +7,7 @@ import DateUtils from '../../src/libs/DateUtils'; const monthNames = DateUtils.getMonthNames(CONST.LOCALES.EN); jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), useNavigation: () => ({navigate: jest.fn()}), createNavigationContainerRef: jest.fn(), })); From 6cc3f5c9f89c0058ab99adcef810b07dc34d52c7 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 9 Jan 2024 11:08:51 -0700 Subject: [PATCH 60/90] Move message copy outside of component lifecycle --- .../PurposeForUsingExpensifyModal.js | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index ace35019ed80..d05df72f7649 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -39,6 +39,57 @@ const defaultProps = { session: {}, }; +// This is not translated because it is a message coming from concierge, which only supports english +const messageCopy = { + track: + 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + + '\n' + + '1. Press your avatar icon\n' + + '2. Choose Workspaces\n' + + '3. Choose New Workspace\n' + + '4. Name your workspace something meaningful (eg, "My Business Expenses")\n' + + '\n' + + 'Once you have your workspace set up, you can add expenses to it as follows:\n' + + '\n' + + '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms\n' + + '2. Choose the + button in the chat compose window\n' + + '3. Choose Request money\n' + + "4. Choose what kind of expense you'd like to log, whether a manual expense, scanned receipt, or tracked distance.\n" + + '\n' + + "That'll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!", + submit: + 'Hi there, to submit expenses for reimbursement, please:\n' + + '\n' + + '1. Press the big green + button\n' + + '2. Choose Request money\n' + + '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance\n' + + '4. Enter the email address or phone number of your boss\n' + + '\n' + + "And we'll take it from there to get you paid back. Please give it a shot and let me know how it goes!", + business: + "Great! To manage your team's expenses, create a workspace to keep everything contained:\n" + + '\n' + + '1. Press your avatar icon\n' + + '2. Choose Workspaces\n' + + '3. Choose New Workspace\n' + + '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + + '\n' + + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', + chatSplit: + 'Hi there, to split an expense such as with a friend, please:\n' + + '\n' + + 'Press the big green + button\n' + + 'Choose *Request money*\n' + + 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance\n' + + 'Enter the email address or phone number of your friend\n' + + 'Press *Split* next to their name\n' + + 'Repeat as many times as you like for each of your friends\n' + + 'Press *Add to split* when done adding friends\n' + + 'Press Split to split the bill\n' + + '\n' + + "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", +}; + function PurposeForUsingExpensifyModal(props) { const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); @@ -61,57 +112,6 @@ function PurposeForUsingExpensifyModal(props) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - // This is not translated because it is a message coming from concierge, which only supports english - const messageCopy = { - track: - 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + - '\n' + - '1. Press your avatar icon\n' + - '2. Choose Workspaces\n' + - '3. Choose New Workspace\n' + - '4. Name your workspace something meaningful (eg, "My Business Expenses")\n' + - '\n' + - 'Once you have your workspace set up, you can add expenses to it as follows:\n' + - '\n' + - '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms\n' + - '2. Choose the + button in the chat compose window\n' + - '3. Choose Request money\n' + - "4. Choose what kind of expense you'd like to log, whether a manual expense, scanned receipt, or tracked distance.\n" + - '\n' + - "That'll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!", - submit: - 'Hi there, to submit expenses for reimbursement, please:\n' + - '\n' + - '1. Press the big green + button\n' + - '2. Choose Request money\n' + - '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance\n' + - '4. Enter the email address or phone number of your boss\n' + - '\n' + - "And we'll take it from there to get you paid back. Please give it a shot and let me know how it goes!", - business: - "Great! To manage your team's expenses, create a workspace to keep everything contained:\n" + - '\n' + - '1. Press your avatar icon\n' + - '2. Choose Workspaces\n' + - '3. Choose New Workspace\n' + - '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + - '\n' + - 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', - chatSplit: - 'Hi there, to split an expense such as with a friend, please:\n' + - '\n' + - 'Press the big green + button\n' + - 'Choose *Request money*\n' + - 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance\n' + - 'Enter the email address or phone number of your friend\n' + - 'Press *Split* next to their name\n' + - 'Repeat as many times as you like for each of your friends\n' + - 'Press *Add to split* when done adding friends\n' + - 'Press Split to split the bill\n' + - '\n' + - "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", - }; - const closeModal = useCallback(() => { Report.dismissEngagementModal(); setIsModalOpen(false); From aa6398a4ba4f9525ba6e70b87baf13d8512947a3 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 9 Jan 2024 17:20:01 -0700 Subject: [PATCH 61/90] Add view for max height --- .../PurposeForUsingExpensifyModal.js | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index d05df72f7649..c70dd44ffdfc 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -94,7 +94,7 @@ function PurposeForUsingExpensifyModal(props) { const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); const [isModalOpen, setIsModalOpen] = useState(false); const theme = useTheme(); @@ -163,45 +163,49 @@ function PurposeForUsingExpensifyModal(props) { ]; return ( - - - - - + + + + + + + + + + {translate('purposeForExpensify.welcomeMessage')} + + {translate('purposeForExpensify.welcomeSubtitle')} + + + - - - {translate('purposeForExpensify.welcomeMessage')} - - {translate('purposeForExpensify.welcomeSubtitle')} - - - - + ); } From 37ff12a067b49d04495d606a94d7626fd058012c Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Tue, 9 Jan 2024 17:22:10 -0700 Subject: [PATCH 62/90] Prettier --- .../PurposeForUsingExpensifyModal.js | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js index c70dd44ffdfc..e80c28e768fa 100644 --- a/src/components/PurposeForUsingExpensifyModal.js +++ b/src/components/PurposeForUsingExpensifyModal.js @@ -163,49 +163,47 @@ function PurposeForUsingExpensifyModal(props) { ]; return ( - - - - - - - - - - {translate('purposeForExpensify.welcomeMessage')} - - {translate('purposeForExpensify.welcomeSubtitle')} - - + + + + - - - + + + + + {translate('purposeForExpensify.welcomeMessage')} + + {translate('purposeForExpensify.welcomeSubtitle')} + + + + + ); } From cbd3db5639b7b631ff0faae257f6223ad0a2ef02 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 16:03:42 -0700 Subject: [PATCH 63/90] Convert to ts --- .../PurposeForUsingExpensifyModal.tsx | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 src/components/PurposeForUsingExpensifyModal.tsx diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx new file mode 100644 index 000000000000..510f610b1581 --- /dev/null +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -0,0 +1,211 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, {useCallback, useEffect, useState} from 'react'; +import {ScrollView, View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import useLocalize from '@hooks/useLocalize'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import compose from '@libs/compose'; +import * as Report from '@userActions/Report'; +import * as Welcome from '@userActions/Welcome'; +import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; +import ONYXKEYS from '@src/ONYXKEYS'; +import SCREENS from '@src/SCREENS'; +import HeaderWithBackButton from './HeaderWithBackButton'; +import * as Expensicons from './Icon/Expensicons'; +import Lottie from './Lottie'; +import LottieAnimations from './LottieAnimations'; +import MenuItemList from './MenuItemList'; +import Modal from './Modal'; +import Text from './Text'; +import withNavigation from './withNavigation'; +import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; +import type {WindowDimensionsProps} from "@components/withWindowDimensions/types"; + +type PurposeForUsingExpensifyModalProps = WindowDimensionsProps; + +// This is not translated because it is a message coming from concierge, which only supports english +const messageCopy = { + track: + 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + + '\n' + + '1. Press your avatar icon\n' + + '2. Choose Workspaces\n' + + '3. Choose New Workspace\n' + + '4. Name your workspace something meaningful (eg, "My Business Expenses")\n' + + '\n' + + 'Once you have your workspace set up, you can add expenses to it as follows:\n' + + '\n' + + '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms\n' + + '2. Choose the + button in the chat compose window\n' + + '3. Choose Request money\n' + + "4. Choose what kind of expense you'd like to log, whether a manual expense, scanned receipt, or tracked distance.\n" + + '\n' + + "That'll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!", + submit: + 'Hi there, to submit expenses for reimbursement, please:\n' + + '\n' + + '1. Press the big green + button\n' + + '2. Choose Request money\n' + + '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance\n' + + '4. Enter the email address or phone number of your boss\n' + + '\n' + + "And we'll take it from there to get you paid back. Please give it a shot and let me know how it goes!", + business: + "Great! To manage your team's expenses, create a workspace to keep everything contained:\n" + + '\n' + + '1. Press your avatar icon\n' + + '2. Choose Workspaces\n' + + '3. Choose New Workspace\n' + + '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + + '\n' + + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', + chatSplit: + 'Hi there, to split an expense such as with a friend, please:\n' + + '\n' + + 'Press the big green + button\n' + + 'Choose *Request money*\n' + + 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance\n' + + 'Enter the email address or phone number of your friend\n' + + 'Press *Split* next to their name\n' + + 'Repeat as many times as you like for each of your friends\n' + + 'Press *Add to split* when done adding friends\n' + + 'Press Split to split the bill\n' + + '\n' + + "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", +}; + +function PurposeForUsingExpensifyModal(props) { + const {translate} = useLocalize(); + const StyleUtils = useStyleUtils(); + const styles = useThemeStyles(); + const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); + const [isModalOpen, setIsModalOpen] = useState(false); + const theme = useTheme(); + + useEffect(() => { + const navigationState = props.navigation.getState(); + const routes = lodashGet(navigationState, 'routes', []); + const currentRoute = routes[navigationState.index]; + if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) { + return; + } + if (lodashGet(props.demoInfo, 'money2020.isBeginningDemo', false)) { + return; + } + Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const closeModal = useCallback(() => { + Report.dismissEngagementModal(); + setIsModalOpen(false); + }, []); + + const completeModalAndClose = (message, choice) => { + Report.completeEngagementModal(message, choice); + setIsModalOpen(false); + Report.navigateToConciergeChat(); + }; + + const menuItems = [ + { + key: 'purposeForExpensify.track', + title: translate('purposeForExpensify.track'), + icon: Expensicons.ReceiptSearch, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + { + key: 'purposeForExpensify.submit', + title: translate('purposeForExpensify.submit'), + icon: Expensicons.Scan, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + { + key: 'purposeForExpensify.manageTeam', + title: translate('purposeForExpensify.manageTeam'), + icon: Expensicons.MoneyBag, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + { + key: 'purposeForExpensify.splitChat', + title: translate('purposeForExpensify.splitChat'), + icon: Expensicons.Briefcase, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + ]; + + return ( + + + + + + + + + + {translate('purposeForExpensify.welcomeMessage')} + + {translate('purposeForExpensify.welcomeSubtitle')} + + + + + + ); +} + +PurposeForUsingExpensifyModal.propTypes = propTypes; +PurposeForUsingExpensifyModal.defaultProps = defaultProps; +PurposeForUsingExpensifyModal.displayName = 'PurposeForUsingExpensifyModal'; + +export default compose( + withWindowDimensions, + withNavigation, + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }), +)(PurposeForUsingExpensifyModal); From 69ccc512927c5cbeb1c7973de35715dba2e44667 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 16:04:40 -0700 Subject: [PATCH 64/90] Remove old file and fix menuitem type --- src/components/MenuItemList.tsx | 2 +- .../PurposeForUsingExpensifyModal.js | 222 ------------------ 2 files changed, 1 insertion(+), 223 deletions(-) delete mode 100644 src/components/PurposeForUsingExpensifyModal.js diff --git a/src/components/MenuItemList.tsx b/src/components/MenuItemList.tsx index f83f173a644f..7d7ecd9d41ac 100644 --- a/src/components/MenuItemList.tsx +++ b/src/components/MenuItemList.tsx @@ -15,7 +15,7 @@ type MenuItemWithLink = MenuItemProps & { type MenuItemListProps = { /** An array of props that are pass to individual MenuItem components */ - menuItems: MenuItemWithLink[]; + menuItems: MenuItemWithLink[] | MenuItemProps[]; /** Whether or not to use the single execution hook */ shouldUseSingleExecution?: boolean; diff --git a/src/components/PurposeForUsingExpensifyModal.js b/src/components/PurposeForUsingExpensifyModal.js deleted file mode 100644 index e80c28e768fa..000000000000 --- a/src/components/PurposeForUsingExpensifyModal.js +++ /dev/null @@ -1,222 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useState} from 'react'; -import {ScrollView, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import useLocalize from '@hooks/useLocalize'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useTheme from '@hooks/useTheme'; -import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import compose from '@libs/compose'; -import * as Report from '@userActions/Report'; -import * as Welcome from '@userActions/Welcome'; -import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ONYXKEYS from '@src/ONYXKEYS'; -import SCREENS from '@src/SCREENS'; -import HeaderWithBackButton from './HeaderWithBackButton'; -import * as Expensicons from './Icon/Expensicons'; -import Lottie from './Lottie'; -import LottieAnimations from './LottieAnimations'; -import MenuItemList from './MenuItemList'; -import Modal from './Modal'; -import Text from './Text'; -import withNavigation from './withNavigation'; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; - -const propTypes = { - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user accountID */ - accountID: PropTypes.number, - }), - - ...windowDimensionsPropTypes, -}; - -const defaultProps = { - session: {}, -}; - -// This is not translated because it is a message coming from concierge, which only supports english -const messageCopy = { - track: - 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + - '\n' + - '1. Press your avatar icon\n' + - '2. Choose Workspaces\n' + - '3. Choose New Workspace\n' + - '4. Name your workspace something meaningful (eg, "My Business Expenses")\n' + - '\n' + - 'Once you have your workspace set up, you can add expenses to it as follows:\n' + - '\n' + - '1. Choose My Business Expenses (or whatever you named it) in the list of chat rooms\n' + - '2. Choose the + button in the chat compose window\n' + - '3. Choose Request money\n' + - "4. Choose what kind of expense you'd like to log, whether a manual expense, scanned receipt, or tracked distance.\n" + - '\n' + - "That'll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!", - submit: - 'Hi there, to submit expenses for reimbursement, please:\n' + - '\n' + - '1. Press the big green + button\n' + - '2. Choose Request money\n' + - '3. Indicate how much to request, either manually, by scanning a receipt, or by tracking distance\n' + - '4. Enter the email address or phone number of your boss\n' + - '\n' + - "And we'll take it from there to get you paid back. Please give it a shot and let me know how it goes!", - business: - "Great! To manage your team's expenses, create a workspace to keep everything contained:\n" + - '\n' + - '1. Press your avatar icon\n' + - '2. Choose Workspaces\n' + - '3. Choose New Workspace\n' + - '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + - '\n' + - 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', - chatSplit: - 'Hi there, to split an expense such as with a friend, please:\n' + - '\n' + - 'Press the big green + button\n' + - 'Choose *Request money*\n' + - 'Indicate how much was spent, either manually, by scanning a receipt, or by tracking distance\n' + - 'Enter the email address or phone number of your friend\n' + - 'Press *Split* next to their name\n' + - 'Repeat as many times as you like for each of your friends\n' + - 'Press *Add to split* when done adding friends\n' + - 'Press Split to split the bill\n' + - '\n' + - "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", -}; - -function PurposeForUsingExpensifyModal(props) { - const {translate} = useLocalize(); - const StyleUtils = useStyleUtils(); - const styles = useThemeStyles(); - const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); - const [isModalOpen, setIsModalOpen] = useState(false); - const theme = useTheme(); - - useEffect(() => { - const navigationState = props.navigation.getState(); - const routes = lodashGet(navigationState, 'routes', []); - const currentRoute = routes[navigationState.index]; - if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) { - return; - } - if (lodashGet(props.demoInfo, 'money2020.isBeginningDemo', false)) { - return; - } - Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const closeModal = useCallback(() => { - Report.dismissEngagementModal(); - setIsModalOpen(false); - }, []); - - const completeModalAndClose = (message, choice) => { - Report.completeEngagementModal(message, choice); - setIsModalOpen(false); - Report.navigateToConciergeChat(); - }; - - const menuItems = [ - { - key: 'purposeForExpensify.track', - title: translate('purposeForExpensify.track'), - icon: Expensicons.ReceiptSearch, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - { - key: 'purposeForExpensify.submit', - title: translate('purposeForExpensify.submit'), - icon: Expensicons.Scan, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - { - key: 'purposeForExpensify.manageTeam', - title: translate('purposeForExpensify.manageTeam'), - icon: Expensicons.MoneyBag, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - { - key: 'purposeForExpensify.splitChat', - title: translate('purposeForExpensify.splitChat'), - icon: Expensicons.Briefcase, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - ]; - - return ( - - - - - - - - - - {translate('purposeForExpensify.welcomeMessage')} - - {translate('purposeForExpensify.welcomeSubtitle')} - - - - - - ); -} - -PurposeForUsingExpensifyModal.propTypes = propTypes; -PurposeForUsingExpensifyModal.defaultProps = defaultProps; -PurposeForUsingExpensifyModal.displayName = 'PurposeForUsingExpensifyModal'; - -export default compose( - withWindowDimensions, - withNavigation, - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(PurposeForUsingExpensifyModal); From a02c8aeb0ddb4ce1029b9672e9be579171cb2113 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 16:29:32 -0700 Subject: [PATCH 65/90] More typescript chages --- .../PurposeForUsingExpensifyModal.tsx | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 510f610b1581..f4f037cd24e1 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -8,6 +8,7 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import {useNavigation} from "@react-navigation/native"; import compose from '@libs/compose'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; @@ -23,10 +24,10 @@ import MenuItemList from './MenuItemList'; import Modal from './Modal'; import Text from './Text'; import withNavigation from './withNavigation'; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; -import type {WindowDimensionsProps} from "@components/withWindowDimensions/types"; - -type PurposeForUsingExpensifyModalProps = WindowDimensionsProps; +import withWindowDimensions from './withWindowDimensions'; +import type {WindowDimensionsProps} from "./withWindowDimensions/types"; +import type {StackNavigationProp} from "@react-navigation/stack"; +import type {RootStackParamList} from "@navigation/types"; // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { @@ -79,24 +80,23 @@ const messageCopy = { "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", }; -function PurposeForUsingExpensifyModal(props) { +function PurposeForUsingExpensifyModal() { const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); + const navigation = useNavigation(); const [isModalOpen, setIsModalOpen] = useState(false); const theme = useTheme(); useEffect(() => { - const navigationState = props.navigation.getState(); + const navigationState = navigation.getState(); const routes = lodashGet(navigationState, 'routes', []); const currentRoute = routes[navigationState.index]; if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) { return; } - if (lodashGet(props.demoInfo, 'money2020.isBeginningDemo', false)) { - return; - } + Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -196,16 +196,6 @@ function PurposeForUsingExpensifyModal(props) { ); } -PurposeForUsingExpensifyModal.propTypes = propTypes; -PurposeForUsingExpensifyModal.defaultProps = defaultProps; PurposeForUsingExpensifyModal.displayName = 'PurposeForUsingExpensifyModal'; -export default compose( - withWindowDimensions, - withNavigation, - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(PurposeForUsingExpensifyModal); +export default PurposeForUsingExpensifyModal; From a248b46b11a841cc860bdb6cab0c0030cff1bdcb Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 16:31:39 -0700 Subject: [PATCH 66/90] remove unused imports --- src/components/PurposeForUsingExpensifyModal.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index f4f037cd24e1..51dbc2856cf1 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,20 +1,16 @@ import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useState} from 'react'; import {ScrollView, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import {useNavigation} from "@react-navigation/native"; -import compose from '@libs/compose'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; -import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; import HeaderWithBackButton from './HeaderWithBackButton'; import * as Expensicons from './Icon/Expensicons'; @@ -23,11 +19,6 @@ import LottieAnimations from './LottieAnimations'; import MenuItemList from './MenuItemList'; import Modal from './Modal'; import Text from './Text'; -import withNavigation from './withNavigation'; -import withWindowDimensions from './withWindowDimensions'; -import type {WindowDimensionsProps} from "./withWindowDimensions/types"; -import type {StackNavigationProp} from "@react-navigation/stack"; -import type {RootStackParamList} from "@navigation/types"; // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { From 1569ef614cd26bc46120b060e78e2be34fbc0875 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 16:51:39 -0700 Subject: [PATCH 67/90] Fix background on mobile web --- src/components/PurposeForUsingExpensifyModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 51dbc2856cf1..d566ef9cafd1 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -148,7 +148,7 @@ function PurposeForUsingExpensifyModal() { isVisible={isModalOpen} onClose={closeModal} innerContainerStyle={styles.pt0} - shouldUseCustomBackdrop={!isSmallScreenWidth} + shouldUseCustomBackdrop > From d5719145b5cdfbc4dcb010884f63bb8c5b2a74ce Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 16:51:46 -0700 Subject: [PATCH 68/90] Fix typing --- src/components/PurposeForUsingExpensifyModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index d566ef9cafd1..0a080371372b 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -97,7 +97,7 @@ function PurposeForUsingExpensifyModal() { setIsModalOpen(false); }, []); - const completeModalAndClose = (message, choice) => { + const completeModalAndClose = (message: string, choice: string) => { Report.completeEngagementModal(message, choice); setIsModalOpen(false); Report.navigateToConciergeChat(); @@ -175,7 +175,7 @@ function PurposeForUsingExpensifyModal() { > {translate('purposeForExpensify.welcomeMessage')}
- {translate('purposeForExpensify.welcomeSubtitle')} + {translate('purposeForExpensify.welcomeSubtitle')}
Date: Thu, 11 Jan 2024 16:57:41 -0700 Subject: [PATCH 69/90] Add undefined link to fix types --- src/components/MenuItemList.tsx | 2 +- src/components/PurposeForUsingExpensifyModal.tsx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/MenuItemList.tsx b/src/components/MenuItemList.tsx index 7d7ecd9d41ac..f83f173a644f 100644 --- a/src/components/MenuItemList.tsx +++ b/src/components/MenuItemList.tsx @@ -15,7 +15,7 @@ type MenuItemWithLink = MenuItemProps & { type MenuItemListProps = { /** An array of props that are pass to individual MenuItem components */ - menuItems: MenuItemWithLink[] | MenuItemProps[]; + menuItems: MenuItemWithLink[]; /** Whether or not to use the single execution hook */ shouldUseSingleExecution?: boolean; diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 0a080371372b..4ed963c1665e 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -112,6 +112,7 @@ function PurposeForUsingExpensifyModal() { onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), shouldShowRightIcon: true, numberOfLinesTitle: 2, + link: undefined, }, { key: 'purposeForExpensify.submit', @@ -121,6 +122,7 @@ function PurposeForUsingExpensifyModal() { onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), shouldShowRightIcon: true, numberOfLinesTitle: 2, + link: undefined, }, { key: 'purposeForExpensify.manageTeam', @@ -130,6 +132,7 @@ function PurposeForUsingExpensifyModal() { onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), shouldShowRightIcon: true, numberOfLinesTitle: 2, + link: undefined, }, { key: 'purposeForExpensify.splitChat', @@ -139,6 +142,7 @@ function PurposeForUsingExpensifyModal() { onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), shouldShowRightIcon: true, numberOfLinesTitle: 2, + link: undefined, }, ]; From f216232d57ee28d28c4d6639d50bfc69ae993573 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 17:06:39 -0700 Subject: [PATCH 70/90] More types --- src/components/MenuItemList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MenuItemList.tsx b/src/components/MenuItemList.tsx index f83f173a644f..4660d1172c94 100644 --- a/src/components/MenuItemList.tsx +++ b/src/components/MenuItemList.tsx @@ -6,7 +6,7 @@ import CONST from '@src/CONST'; import type {MenuItemProps} from './MenuItem'; import MenuItem from './MenuItem'; -type MenuItemLink = string | (() => Promise); +type MenuItemLink = string | (() => Promise) | undefined; type MenuItemWithLink = MenuItemProps & { /** The link to open when the menu item is clicked */ From 6f8ccf01de2b80ab0a5612b759520dd6655d7320 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 17:07:13 -0700 Subject: [PATCH 71/90] Style --- src/components/PurposeForUsingExpensifyModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 4ed963c1665e..14ff86c3c865 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,3 +1,4 @@ +import {useNavigation} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import React, {useCallback, useEffect, useState} from 'react'; import {ScrollView, View} from 'react-native'; @@ -6,7 +7,6 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import {useNavigation} from "@react-navigation/native"; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; From bca21afcd348a6f74ee05e98d1016980c7344fc9 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 11 Jan 2024 17:22:40 -0700 Subject: [PATCH 72/90] Style --- src/components/PurposeForUsingExpensifyModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 14ff86c3c865..fbc9c71185d8 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -82,7 +82,7 @@ function PurposeForUsingExpensifyModal() { useEffect(() => { const navigationState = navigation.getState(); - const routes = lodashGet(navigationState, 'routes', []); + const routes = navigationState.routes; const currentRoute = routes[navigationState.index]; if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) { return; From 8c59d64b956857dd51b403bdca6d79037e04ed39 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 12 Jan 2024 17:11:34 -0700 Subject: [PATCH 73/90] Fix types --- src/components/PurposeForUsingExpensifyModal.tsx | 5 +++-- src/libs/actions/Welcome.ts | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index fbc9c71185d8..fe984823803d 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,5 +1,4 @@ import {useNavigation} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; import React, {useCallback, useEffect, useState} from 'react'; import {ScrollView, View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; @@ -83,8 +82,10 @@ function PurposeForUsingExpensifyModal() { useEffect(() => { const navigationState = navigation.getState(); const routes = navigationState.routes; + debugger; const currentRoute = routes[navigationState.index]; - if (currentRoute && ![NAVIGATORS.CENTRAL_PANE_NAVIGATOR, SCREENS.HOME].includes(currentRoute.name)) { + const currentRouteName: string = currentRoute.name; + if (currentRoute && NAVIGATORS.CENTRAL_PANE_NAVIGATOR !== currentRouteName && currentRouteName !== SCREENS.HOME) { return; } diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 3f17ced0ea0e..019f6ccda9d5 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -10,6 +10,7 @@ import type OnyxPolicy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; +import type {ParamListBase, RouteProp} from '@react-navigation/native'; let resolveIsReadyPromise: (value?: Promise) => void | undefined; let isReadyPromise = new Promise((resolve) => { @@ -22,9 +23,8 @@ let hasSelectedChoice: boolean | undefined; let isLoadingReportData = true; let currentUserAccountID: number | undefined; -type Route = { - name: string; - params?: {path: string; exitTo?: string; openOnAdminRoom?: boolean}; +type Route = ParamListBase & { + params: {path?: string; exitTo?: string; openOnAdminRoom?: boolean}; }; type ShowParams = { @@ -147,7 +147,7 @@ function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => f // If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global // create menu right now. We should also stay on the workspace page if that is our destination. const topRoute = routes.length > 0 ? routes[routes.length - 1] : undefined; - const isWorkspaceRoute = topRoute !== undefined && topRoute.name === SCREENS.RIGHT_MODAL.SETTINGS && topRoute.params?.path.includes('workspace'); + const isWorkspaceRoute = topRoute !== undefined && topRoute.name === SCREENS.RIGHT_MODAL.SETTINGS && topRoute.params?.path?.includes('workspace'); const transitionRoute = routes.find((route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS); const exitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new'; const openOnAdminRoom = topRoute?.params?.openOnAdminRoom ?? false; From 6ca99b068b5b9b1415a0976fe39f6f1baa400097 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 12 Jan 2024 17:49:40 -0700 Subject: [PATCH 74/90] Remove bad routing logic --- .../PurposeForUsingExpensifyModal.tsx | 14 +--- src/libs/actions/Welcome.ts | 70 ++----------------- 2 files changed, 5 insertions(+), 79 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index fe984823803d..c00fa392f4f1 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,4 +1,3 @@ -import {useNavigation} from '@react-navigation/native'; import React, {useCallback, useEffect, useState} from 'react'; import {ScrollView, View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; @@ -9,7 +8,6 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import HeaderWithBackButton from './HeaderWithBackButton'; import * as Expensicons from './Icon/Expensicons'; @@ -75,21 +73,11 @@ function PurposeForUsingExpensifyModal() { const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); - const navigation = useNavigation(); const [isModalOpen, setIsModalOpen] = useState(false); const theme = useTheme(); useEffect(() => { - const navigationState = navigation.getState(); - const routes = navigationState.routes; - debugger; - const currentRoute = routes[navigationState.index]; - const currentRouteName: string = currentRoute.name; - if (currentRoute && NAVIGATORS.CENTRAL_PANE_NAVIGATOR !== currentRouteName && currentRouteName !== SCREENS.HOME) { - return; - } - - Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); + Welcome.show({showEngagementModal: () => setIsModalOpen(true)}); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 019f6ccda9d5..875eb61d625f 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -1,16 +1,10 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import Navigation from '@libs/Navigation/Navigation'; -import * as ReportUtils from '@libs/ReportUtils'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import type OnyxPolicy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import * as Policy from './Policy'; -import type {ParamListBase, RouteProp} from '@react-navigation/native'; let resolveIsReadyPromise: (value?: Promise) => void | undefined; let isReadyPromise = new Promise((resolve) => { @@ -21,16 +15,9 @@ let isFirstTimeNewExpensifyUser: boolean | undefined; let hasDismissedModal: boolean | undefined; let hasSelectedChoice: boolean | undefined; let isLoadingReportData = true; -let currentUserAccountID: number | undefined; - -type Route = ParamListBase & { - params: {path?: string; exitTo?: string; openOnAdminRoom?: boolean}; -}; type ShowParams = { - routes: Route[]; - showEngagementModal?: () => void; - showPopoverMenu?: () => boolean; + showEngagementModal: () => void; }; /** @@ -124,68 +111,19 @@ Onyx.connect({ }, }); -Onyx.connect({ - key: ONYXKEYS.SESSION, - callback: (val, key) => { - if (!val || !key) { - return; - } - - currentUserAccountID = val.accountID; - }, -}); - /** * Shows a welcome action on first login */ -function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => false}: ShowParams) { +function show({showEngagementModal}: ShowParams) { isReadyPromise.then(() => { if (!isFirstTimeNewExpensifyUser) { return; } - // If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global - // create menu right now. We should also stay on the workspace page if that is our destination. - const topRoute = routes.length > 0 ? routes[routes.length - 1] : undefined; - const isWorkspaceRoute = topRoute !== undefined && topRoute.name === SCREENS.RIGHT_MODAL.SETTINGS && topRoute.params?.path?.includes('workspace'); - const transitionRoute = routes.find((route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS); - const exitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new'; - const openOnAdminRoom = topRoute?.params?.openOnAdminRoom ?? false; - const isDisplayingWorkspaceRoute = isWorkspaceRoute ?? exitingToWorkspaceRoute; - - // If we already opened the workspace settings or want the admin room to stay open, do not - // navigate away to the workspace chat report - const shouldNavigateToWorkspaceChat = !isDisplayingWorkspaceRoute && !openOnAdminRoom; - - const workspaceChatReport = Object.values(allReports ?? {}).find((report) => { - if (report) { - return ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS.CLOSED; - } - return false; - }); - - if (workspaceChatReport ?? openOnAdminRoom) { - // This key is only updated when we call ReconnectApp, setting it to false now allows the user to navigate normally instead of always redirecting to the workspace chat - Onyx.set(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, false); - } - - if (shouldNavigateToWorkspaceChat && workspaceChatReport) { - if (workspaceChatReport.reportID !== null) { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID)); - } - - // If showPopoverMenu exists and returns true then it opened the Popover Menu successfully, and we can update isFirstTimeNewExpensifyUser - // so the Welcome logic doesn't run again - if (showPopoverMenu?.()) { - isFirstTimeNewExpensifyUser = false; - } - - return; - } - // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the engagement modal. - if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal && Object.keys(allPolicies ?? {}).length === 1) { + if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !hasSelectedChoice && !hasDismissedModal && Object.keys(allPolicies ?? {}).length === 1) { + Onyx.set(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, false); showEngagementModal(); } From 58a4e52194db7c6b6e98d4374c55b751d011f52d Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 15 Jan 2024 14:25:28 -0700 Subject: [PATCH 75/90] Fix typing and consolidate logic --- .../PurposeForUsingExpensifyModal.tsx | 3 +- src/libs/actions/Welcome.ts | 39 +++++++------------ 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index fe984823803d..a9f2a96d8dc9 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -82,14 +82,13 @@ function PurposeForUsingExpensifyModal() { useEffect(() => { const navigationState = navigation.getState(); const routes = navigationState.routes; - debugger; const currentRoute = routes[navigationState.index]; const currentRouteName: string = currentRoute.name; if (currentRoute && NAVIGATORS.CENTRAL_PANE_NAVIGATOR !== currentRouteName && currentRouteName !== SCREENS.HOME) { return; } - Welcome.show({routes, showEngagementModal: () => setIsModalOpen(true)}); + Welcome.show(routes, () => setIsModalOpen(true)); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 019f6ccda9d5..9881ee04be51 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -9,8 +9,9 @@ import SCREENS from '@src/SCREENS'; import type OnyxPolicy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import type {RootStackParamList} from '@navigation/types'; +import type {NavigationState} from '@react-navigation/native'; import * as Policy from './Policy'; -import type {ParamListBase, RouteProp} from '@react-navigation/native'; let resolveIsReadyPromise: (value?: Promise) => void | undefined; let isReadyPromise = new Promise((resolve) => { @@ -23,16 +24,6 @@ let hasSelectedChoice: boolean | undefined; let isLoadingReportData = true; let currentUserAccountID: number | undefined; -type Route = ParamListBase & { - params: {path?: string; exitTo?: string; openOnAdminRoom?: boolean}; -}; - -type ShowParams = { - routes: Route[]; - showEngagementModal?: () => void; - showPopoverMenu?: () => boolean; -}; - /** * Check that a few requests have completed so that the welcome action can proceed: * @@ -138,7 +129,7 @@ Onyx.connect({ /** * Shows a welcome action on first login */ -function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => false}: ShowParams) { +function show(routes: NavigationState['routes'], showEngagementModal = () => {}) { isReadyPromise.then(() => { if (!isFirstTimeNewExpensifyUser) { return; @@ -146,16 +137,14 @@ function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => f // If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global // create menu right now. We should also stay on the workspace page if that is our destination. - const topRoute = routes.length > 0 ? routes[routes.length - 1] : undefined; - const isWorkspaceRoute = topRoute !== undefined && topRoute.name === SCREENS.RIGHT_MODAL.SETTINGS && topRoute.params?.path?.includes('workspace'); - const transitionRoute = routes.find((route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS); - const exitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new'; - const openOnAdminRoom = topRoute?.params?.openOnAdminRoom ?? false; - const isDisplayingWorkspaceRoute = isWorkspaceRoute ?? exitingToWorkspaceRoute; + const transitionRoute = routes.find( + (route): route is NavigationState>['routes'][number] => route.name === SCREENS.TRANSITION_BETWEEN_APPS, + ); + const isExitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new'; // If we already opened the workspace settings or want the admin room to stay open, do not // navigate away to the workspace chat report - const shouldNavigateToWorkspaceChat = !isDisplayingWorkspaceRoute && !openOnAdminRoom; + const shouldNavigateToWorkspaceChat = !isExitingToWorkspaceRoute; const workspaceChatReport = Object.values(allReports ?? {}).find((report) => { if (report) { @@ -164,7 +153,7 @@ function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => f return false; }); - if (workspaceChatReport ?? openOnAdminRoom) { + if (workspaceChatReport) { // This key is only updated when we call ReconnectApp, setting it to false now allows the user to navigate normally instead of always redirecting to the workspace chat Onyx.set(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, false); } @@ -174,18 +163,16 @@ function show({routes, showEngagementModal = () => {}, showPopoverMenu = () => f Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID)); } - // If showPopoverMenu exists and returns true then it opened the Popover Menu successfully, and we can update isFirstTimeNewExpensifyUser - // so the Welcome logic doesn't run again - if (showPopoverMenu?.()) { - isFirstTimeNewExpensifyUser = false; - } + // New user has been redirected to their workspace chat, and we won't show them the engagement modal. + // So we update isFirstTimeNewExpensifyUser to prevent the Welcome logic from running again + isFirstTimeNewExpensifyUser = false; return; } // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the engagement modal. - if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal && Object.keys(allPolicies ?? {}).length === 1) { + if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isExitingToWorkspaceRoute && !hasSelectedChoice && !hasDismissedModal && Object.keys(allPolicies ?? {}).length === 1) { showEngagementModal(); } From fe2625e48d86c95ede67f95a97aa88fa5226263e Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 15 Jan 2024 14:32:51 -0700 Subject: [PATCH 76/90] Fix merge --- src/components/PurposeForUsingExpensifyModal.tsx | 3 +++ src/libs/actions/Welcome.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 9cb02c643c39..a9f2a96d8dc9 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,3 +1,4 @@ +import {useNavigation} from '@react-navigation/native'; import React, {useCallback, useEffect, useState} from 'react'; import {ScrollView, View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; @@ -8,6 +9,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import HeaderWithBackButton from './HeaderWithBackButton'; import * as Expensicons from './Icon/Expensicons'; @@ -73,6 +75,7 @@ function PurposeForUsingExpensifyModal() { const StyleUtils = useStyleUtils(); const styles = useThemeStyles(); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); + const navigation = useNavigation(); const [isModalOpen, setIsModalOpen] = useState(false); const theme = useTheme(); diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 055ce4b06932..3e55c10c920d 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -1,6 +1,11 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import type OnyxPolicy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; @@ -110,6 +115,17 @@ Onyx.connect({ }, }); +Onyx.connect({ + key: ONYXKEYS.SESSION, + callback: (val, key) => { + if (!val || !key) { + return; + } + + currentUserAccountID = val.accountID; + }, +}); + /** * Shows a welcome action on first login */ From 189bae91d0a1e28c56637499d6aee8980f549568 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 15 Jan 2024 14:37:43 -0700 Subject: [PATCH 77/90] Comments --- src/ONYXKEYS.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 4d9fd999fd49..3213b1051805 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -110,8 +110,10 @@ const ONYXKEYS = { /** This NVP holds to most recent waypoints that a person has used when creating a distance request */ NVP_RECENT_WAYPOINTS: 'expensify_recentWaypoints', + /** This NVP will be `true` if the user has dismissed the engagement modal */ NVP_HAS_DISMISSED_IDLE_PANEL: 'hasDismissedIdlePanel', + /** This NVP contains the choice that the user made on the engagement modal */ NVP_INTRO_SELECTED: 'introSelected', /** Does this user have push notifications enabled for this device? */ From 9e86e8e9a63d90a534b1837dcaccbe8c79c70d12 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 15 Jan 2024 14:50:43 -0700 Subject: [PATCH 78/90] Fix copy pasta --- src/libs/actions/Report.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 7b94c0f151ca..46fe15ed16f3 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2491,11 +2491,10 @@ function getReportPrivateNote(reportID: string) { } /** - * Add up to two report actions to a report. This method can be called for the following situations: + * Completes the engagement modal that new NewDot users see when they first sign up/log in by doing the following: * - * - Adding one comment - * - Adding one attachment - * - Add both a comment and attachment simultaneously + * - Sets the introSelected NVP to the choice the user made + * - Creates an optimistic report comment from concierge */ function completeEngagementModal(text: string, choice: string) { const commandName = 'CompleteEngagementModal'; From 7edb569e935874469e1dd14a2e1d6670661e8263 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Mon, 15 Jan 2024 14:51:38 -0700 Subject: [PATCH 79/90] Style --- src/libs/actions/Welcome.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 3e55c10c920d..720298403e62 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -1,7 +1,9 @@ +import type {NavigationState} from '@react-navigation/native'; import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; +import type {RootStackParamList} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -9,8 +11,6 @@ import SCREENS from '@src/SCREENS'; import type OnyxPolicy from '@src/types/onyx/Policy'; import type Report from '@src/types/onyx/Report'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; -import type {RootStackParamList} from '@navigation/types'; -import type {NavigationState} from '@react-navigation/native'; import * as Policy from './Policy'; let resolveIsReadyPromise: (value?: Promise) => void | undefined; From 0b6bf56729c45485483d67e8e4cba5f49a69263c Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 16:54:09 -0700 Subject: [PATCH 80/90] Call the name directly after checking for currentRoute so that we don't accidentally call an undefined object --- src/components/PurposeForUsingExpensifyModal.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index a9f2a96d8dc9..69a46ae92e56 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -83,8 +83,7 @@ function PurposeForUsingExpensifyModal() { const navigationState = navigation.getState(); const routes = navigationState.routes; const currentRoute = routes[navigationState.index]; - const currentRouteName: string = currentRoute.name; - if (currentRoute && NAVIGATORS.CENTRAL_PANE_NAVIGATOR !== currentRouteName && currentRouteName !== SCREENS.HOME) { + if (currentRoute && NAVIGATORS.CENTRAL_PANE_NAVIGATOR !== currentRoute.name && currentRoute.name !== SCREENS.HOME) { return; } From 47c32f4f54f79627a43d99d83bcc29818b84d3e0 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 17:57:58 -0700 Subject: [PATCH 81/90] Fix types --- src/libs/actions/Report.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 0649ad817262..88d760f2168a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2509,7 +2509,7 @@ function completeEngagementModal(text: string, choice: string) { const commandName = 'CompleteEngagementModal'; const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, undefined, conciergeAccountID); - const reportCommentAction: Partial = reportComment.reportAction; + const reportCommentAction: OptimisticAddCommentReportAction = reportComment.reportAction; const lastComment = reportCommentAction?.message?.[0]; const lastCommentText = ReportUtils.formatReportLastMessageText(lastComment?.text ?? ''); const reportCommentText = reportComment.commentText; @@ -2529,12 +2529,12 @@ function completeEngagementModal(text: string, choice: string) { const report = ReportUtils.getReport(conciergeChatReportID); - if (isNotEmptyObject(report) && ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { + if (!isEmptyObject(report) && ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { optimisticReport.notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; } // Optimistically add the new actions to the store before waiting to save them to the server - const optimisticReportActions: OnyxCollection> = {}; + const optimisticReportActions: OnyxCollection = {}; if (reportCommentAction?.reportActionID) { optimisticReportActions[reportCommentAction.reportActionID] = reportCommentAction; } @@ -2564,7 +2564,7 @@ function completeEngagementModal(text: string, choice: string) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReportID}`, - value: optimisticReportActions, + value: optimisticReportActions as ReportActions, }, { onyxMethod: Onyx.METHOD.MERGE, From 82b55525b47473cc8905a91a5f6bcc37bdc13775 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 18:15:32 -0700 Subject: [PATCH 82/90] Remove unnecessary type change and fix copy --- src/ONYXKEYS.ts | 2 +- src/components/MenuItemList.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index e165d943579b..8a2ce5a4b63d 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -110,7 +110,7 @@ const ONYXKEYS = { /** This NVP holds to most recent waypoints that a person has used when creating a distance request */ NVP_RECENT_WAYPOINTS: 'expensify_recentWaypoints', - /** This NVP will be `true` if the user has dismissed the engagement modal */ + /** This NVP will be `true` if the user has ever dismissed the engagement modal on either OldDot or NewDot. If it becomes true it should stay true forever. */ NVP_HAS_DISMISSED_IDLE_PANEL: 'hasDismissedIdlePanel', /** This NVP contains the choice that the user made on the engagement modal */ diff --git a/src/components/MenuItemList.tsx b/src/components/MenuItemList.tsx index e4333cbf6f19..4ba9260e23ff 100644 --- a/src/components/MenuItemList.tsx +++ b/src/components/MenuItemList.tsx @@ -6,7 +6,7 @@ import CONST from '@src/CONST'; import type {MenuItemProps} from './MenuItem'; import MenuItem from './MenuItem'; -type MenuItemLink = string | (() => Promise) | undefined; +type MenuItemLink = string | (() => Promise); type MenuItemWithLink = MenuItemProps & { /** The link to open when the menu item is clicked */ From a526027d90963c0ea701c36acfc4cf9b73f02e54 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 18:15:45 -0700 Subject: [PATCH 83/90] Memoize and callback --- .../PurposeForUsingExpensifyModal.tsx | 97 ++++++++++--------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 69a46ae92e56..3301fa22775e 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,5 +1,5 @@ import {useNavigation} from '@react-navigation/native'; -import React, {useCallback, useEffect, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ScrollView, View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -15,6 +15,7 @@ import HeaderWithBackButton from './HeaderWithBackButton'; import * as Expensicons from './Icon/Expensicons'; import Lottie from './Lottie'; import LottieAnimations from './LottieAnimations'; +import type {MenuItemProps} from './MenuItem'; import MenuItemList from './MenuItemList'; import Modal from './Modal'; import Text from './Text'; @@ -70,6 +71,12 @@ const messageCopy = { "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", }; +const menuItemBase: MenuItemProps = { + iconRight: Expensicons.ArrowRight, + shouldShowRightIcon: true, + numberOfLinesTitle: 2, +}; + function PurposeForUsingExpensifyModal() { const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); @@ -96,54 +103,54 @@ function PurposeForUsingExpensifyModal() { setIsModalOpen(false); }, []); - const completeModalAndClose = (message: string, choice: string) => { + const completeModalAndClose = useCallback((message: string, choice: string) => { Report.completeEngagementModal(message, choice); setIsModalOpen(false); Report.navigateToConciergeChat(); - }; + }, []); - const menuItems = [ - { - key: 'purposeForExpensify.track', - title: translate('purposeForExpensify.track'), - icon: Expensicons.ReceiptSearch, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - link: undefined, - }, - { - key: 'purposeForExpensify.submit', - title: translate('purposeForExpensify.submit'), - icon: Expensicons.Scan, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - link: undefined, - }, - { - key: 'purposeForExpensify.manageTeam', - title: translate('purposeForExpensify.manageTeam'), - icon: Expensicons.MoneyBag, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - link: undefined, - }, - { - key: 'purposeForExpensify.splitChat', - title: translate('purposeForExpensify.splitChat'), - icon: Expensicons.Briefcase, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - link: undefined, - }, - ]; + const menuItems: MenuItemProps[] = useMemo( + () => + [ + { + key: 'purposeForExpensify.track', + title: translate('purposeForExpensify.track'), + icon: Expensicons.ReceiptSearch, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + { + key: 'purposeForExpensify.submit', + title: translate('purposeForExpensify.submit'), + icon: Expensicons.Scan, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + { + key: 'purposeForExpensify.manageTeam', + title: translate('purposeForExpensify.manageTeam'), + icon: Expensicons.MoneyBag, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + { + key: 'purposeForExpensify.splitChat', + title: translate('purposeForExpensify.splitChat'), + icon: Expensicons.Briefcase, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }, + ].map((item) => ({...menuItemBase, ...item})), + [completeModalAndClose, translate], + ); return ( Date: Thu, 18 Jan 2024 19:22:50 -0700 Subject: [PATCH 84/90] Use const and condense menuitem logic --- src/CONST.ts | 7 ++ .../PurposeForUsingExpensifyModal.tsx | 67 ++++++------------- src/languages/en.ts | 8 +-- src/languages/es.ts | 8 +-- src/types/onyx/IntroSelected.ts | 5 +- 5 files changed, 40 insertions(+), 55 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 0b10e5767328..c1f310519a71 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3131,6 +3131,13 @@ const CONST = { REPORT: 'REPORT', }, + INTRO_CHOICES: { + TRACK: 'newDotTrack', + SUBMIT: 'newDotSubmit', + MANAGE_TEAM: 'newDotManageTeam', + CHAT_SPLIT: 'newDotSplitChat', + }, + MINI_CONTEXT_MENU_MAX_ITEMS: 4, } as const; diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 3301fa22775e..d590e2063117 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -22,7 +22,7 @@ import Text from './Text'; // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { - track: + [CONST.INTRO_CHOICES.TRACK]: 'Great! To track your expenses, I suggest you create a workspace to keep everything contained:\n' + '\n' + '1. Press your avatar icon\n' + @@ -38,7 +38,7 @@ const messageCopy = { "4. Choose what kind of expense you'd like to log, whether a manual expense, scanned receipt, or tracked distance.\n" + '\n' + "That'll be stored in your My Business Expenses room for your later access. Thanks for asking, and let me know how it goes!", - submit: + [CONST.INTRO_CHOICES.SUBMIT]: 'Hi there, to submit expenses for reimbursement, please:\n' + '\n' + '1. Press the big green + button\n' + @@ -47,7 +47,7 @@ const messageCopy = { '4. Enter the email address or phone number of your boss\n' + '\n' + "And we'll take it from there to get you paid back. Please give it a shot and let me know how it goes!", - business: + [CONST.INTRO_CHOICES.MANAGE_TEAM]: "Great! To manage your team's expenses, create a workspace to keep everything contained:\n" + '\n' + '1. Press your avatar icon\n' + @@ -56,7 +56,7 @@ const messageCopy = { '4. Name your workspace something meaningful (eg, "Galaxy Food Inc.")\n' + '\n' + 'Once you have your workspace set up, you can invite your team to it via the Members pane and connect a business bank account to reimburse them!', - chatSplit: + [CONST.INTRO_CHOICES.CHAT_SPLIT]: 'Hi there, to split an expense such as with a friend, please:\n' + '\n' + 'Press the big green + button\n' + @@ -71,10 +71,11 @@ const messageCopy = { "This will send a money request to each of your friends for however much they owe you, and we'll take care of getting you paid back. Thanks for asking, and let me know how it goes!", }; -const menuItemBase: MenuItemProps = { - iconRight: Expensicons.ArrowRight, - shouldShowRightIcon: true, - numberOfLinesTitle: 2, +const menuIcons = { + [CONST.INTRO_CHOICES.TRACK]: Expensicons.ReceiptSearch, + [CONST.INTRO_CHOICES.SUBMIT]: Expensicons.Scan, + [CONST.INTRO_CHOICES.MANAGE_TEAM]: Expensicons.MoneyBag, + [CONST.INTRO_CHOICES.CHAT_SPLIT]: Expensicons.Briefcase, }; function PurposeForUsingExpensifyModal() { @@ -111,44 +112,18 @@ function PurposeForUsingExpensifyModal() { const menuItems: MenuItemProps[] = useMemo( () => - [ - { - key: 'purposeForExpensify.track', - title: translate('purposeForExpensify.track'), - icon: Expensicons.ReceiptSearch, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.track, 'newDotTrack'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - { - key: 'purposeForExpensify.submit', - title: translate('purposeForExpensify.submit'), - icon: Expensicons.Scan, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.submit, 'newDotSubmit'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - { - key: 'purposeForExpensify.manageTeam', - title: translate('purposeForExpensify.manageTeam'), - icon: Expensicons.MoneyBag, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.business, 'newDotManageTeam'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - { - key: 'purposeForExpensify.splitChat', - title: translate('purposeForExpensify.splitChat'), - icon: Expensicons.Briefcase, - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy.chatSplit, 'newDotSplitChat'), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, - }, - ].map((item) => ({...menuItemBase, ...item})), + Object.values(CONST.INTRO_CHOICES).map((choice) => { + const translationKey = `purposeForExpensify.${choice}` as const; + return { + key: translationKey, + title: translate(translationKey), + icon: menuIcons[choice], + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy[choice], choice), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, + }; + }), [completeModalAndClose, translate], ); diff --git a/src/languages/en.ts b/src/languages/en.ts index 7e4455f7ac9e..8ee92156bc60 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2074,10 +2074,10 @@ export default { copyReferralLink: 'Copy invite link', }, purposeForExpensify: { - track: 'Track business spend for taxes', - submit: 'Get paid back by my employer', - manageTeam: "Manage my team's expenses", - splitChat: 'Chat and split bills with friends', + [CONST.INTRO_CHOICES.TRACK]: 'Track business spend for taxes', + [CONST.INTRO_CHOICES.SUBMIT]: 'Get paid back by my employer', + [CONST.INTRO_CHOICES.MANAGE_TEAM]: "Manage my team's expenses", + [CONST.INTRO_CHOICES.CHAT_SPLIT]: 'Chat and split bills with friends', welcomeMessage: 'Welcome to Expensify', welcomeSubtitle: 'What would you like to do?', }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 1844fc95a0a7..858fe29a8faf 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2562,10 +2562,10 @@ export default { copyReferralLink: 'Copiar enlace de invitación', }, purposeForExpensify: { - track: 'Seguimiento de los gastos de empresa para fines fiscales', - submit: 'Reclamar gastos a mi empleador', - manageTeam: 'Gestionar los gastos de mi equipo', - splitChat: 'Chatea y divide gastos con tus amigos', + [CONST.INTRO_CHOICES.TRACK]: 'Seguimiento de los gastos de empresa para fines fiscales', + [CONST.INTRO_CHOICES.SUBMIT]: 'Reclamar gastos a mi empleador', + [CONST.INTRO_CHOICES.MANAGE_TEAM]: 'Gestionar los gastos de mi equipo', + [CONST.INTRO_CHOICES.CHAT_SPLIT]: 'Chatea y divide gastos con tus amigos', welcomeMessage: 'Bienvenido a Expensify', welcomeSubtitle: '¿Qué te gustaría hacer?', }, diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index f7446cdd7a4c..f0047ac134ee 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -1,6 +1,9 @@ +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; + type IntroSelected = { /** The choice that the user selected in the engagement modal */ - choice: string; + choice: ValueOf; }; export default IntroSelected; From 25027781650db6426d9c68d7a7b0318475bfb7c5 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 19:23:42 -0700 Subject: [PATCH 85/90] Style --- src/components/PurposeForUsingExpensifyModal.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index d590e2063117..43fe45a5d4b1 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -116,16 +116,16 @@ function PurposeForUsingExpensifyModal() { const translationKey = `purposeForExpensify.${choice}` as const; return { key: translationKey, - title: translate(translationKey), + title: translate(translationKey), icon: menuIcons[choice], - iconRight: Expensicons.ArrowRight, - onPress: () => completeModalAndClose(messageCopy[choice], choice), - shouldShowRightIcon: true, - numberOfLinesTitle: 2, + iconRight: Expensicons.ArrowRight, + onPress: () => completeModalAndClose(messageCopy[choice], choice), + shouldShowRightIcon: true, + numberOfLinesTitle: 2, }; }), [completeModalAndClose, translate], - ); + ); return ( Date: Thu, 18 Jan 2024 19:29:39 -0700 Subject: [PATCH 86/90] Fix type --- src/libs/actions/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 88d760f2168a..62c4e21d3efb 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2505,7 +2505,7 @@ function getReportPrivateNote(reportID: string) { * - Sets the introSelected NVP to the choice the user made * - Creates an optimistic report comment from concierge */ -function completeEngagementModal(text: string, choice: string) { +function completeEngagementModal(text: string, choice: ValueOf) { const commandName = 'CompleteEngagementModal'; const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, undefined, conciergeAccountID); From 9bd6e2ecd2ab19d2b43b65299e0941d293e9f68c Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 19:35:29 -0700 Subject: [PATCH 87/90] More types --- src/components/PurposeForUsingExpensifyModal.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 43fe45a5d4b1..548e664dba5d 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -19,6 +19,7 @@ import type {MenuItemProps} from './MenuItem'; import MenuItemList from './MenuItemList'; import Modal from './Modal'; import Text from './Text'; +import type {ValueOf} from "type-fest"; // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { @@ -104,7 +105,7 @@ function PurposeForUsingExpensifyModal() { setIsModalOpen(false); }, []); - const completeModalAndClose = useCallback((message: string, choice: string) => { + const completeModalAndClose = useCallback((message: string, choice: ValueOf) => { Report.completeEngagementModal(message, choice); setIsModalOpen(false); Report.navigateToConciergeChat(); From 5fa240398a3287f14ae52b835afa9a0a74a2acb5 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Thu, 18 Jan 2024 19:42:48 -0700 Subject: [PATCH 88/90] More style --- src/components/PurposeForUsingExpensifyModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PurposeForUsingExpensifyModal.tsx b/src/components/PurposeForUsingExpensifyModal.tsx index 548e664dba5d..a8cab171ffca 100644 --- a/src/components/PurposeForUsingExpensifyModal.tsx +++ b/src/components/PurposeForUsingExpensifyModal.tsx @@ -1,6 +1,7 @@ import {useNavigation} from '@react-navigation/native'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {ScrollView, View} from 'react-native'; +import type {ValueOf} from 'type-fest'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -19,7 +20,6 @@ import type {MenuItemProps} from './MenuItem'; import MenuItemList from './MenuItemList'; import Modal from './Modal'; import Text from './Text'; -import type {ValueOf} from "type-fest"; // This is not translated because it is a message coming from concierge, which only supports english const messageCopy = { From a313c40cc4e52d8e1f4fe5c9b655b1478a623afd Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 19 Jan 2024 10:44:27 -0700 Subject: [PATCH 89/90] Fix type --- src/libs/actions/Welcome.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 720298403e62..cfe281546b16 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -138,7 +138,7 @@ function show(routes: NavigationState['routes'], showEngagem // If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global // create menu right now. We should also stay on the workspace page if that is our destination. const transitionRoute = routes.find( - (route): route is NavigationState>['routes'][number] => route.name === SCREENS.TRANSITION_BETWEEN_APPS, + (route): route is NavigationState>['routes'][number] => route.name === SCREENS.TRANSITION_BETWEEN_APPS, ); const isExitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new'; From da884be0e7c842bc336cfcfe070c2771acf55b85 Mon Sep 17 00:00:00 2001 From: Brandon Stites Date: Fri, 19 Jan 2024 12:41:58 -0700 Subject: [PATCH 90/90] Remove bad comments and copy/pasted code --- src/libs/actions/Report.ts | 12 ------------ src/libs/actions/Welcome.ts | 4 ---- 2 files changed, 16 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 62c4e21d3efb..a3cd8f52a411 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2581,18 +2581,6 @@ function completeEngagementModal(text: string, choice: ValueOf { - // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic - // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 hasSelectedChoice = !!value; checkOnReady(); @@ -68,8 +66,6 @@ Onyx.connect({ key: ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL, initWithStoredValues: true, callback: (value) => { - // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic - // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 hasDismissedModal = value ?? false; checkOnReady();