From 841e4bff4cdc3192dcfd77fbf7319dd75b18ca13 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 31 Jan 2024 16:09:06 +0700 Subject: [PATCH 001/102] remove MoneyRequestConfirmPage --- src/ROUTES.ts | 4 - src/SCREENS.ts | 1 - src/components/DistanceRequest/index.js | 2 +- .../AppNavigator/ModalStackNavigators.tsx | 1 - src/libs/Navigation/linkingConfig.ts | 1 - src/libs/Navigation/types.ts | 3 +- src/libs/actions/IOU.js | 4 +- src/pages/iou/MoneyRequestCategoryPage.js | 4 +- src/pages/iou/MoneyRequestDatePage.js | 2 +- src/pages/iou/MoneyRequestDescriptionPage.js | 2 +- src/pages/iou/MoneyRequestMerchantPage.js | 2 +- src/pages/iou/MoneyRequestTagPage.js | 2 +- src/pages/iou/NewDistanceRequestPage.js | 2 +- .../step/IOURequestStepConfirmation.js | 14 +- .../iou/steps/MoneyRequestConfirmPage.js | 473 ------------------ .../MoneyRequestParticipantsPage.js | 2 +- src/pages/iou/steps/NewRequestAmountPage.js | 4 +- 17 files changed, 17 insertions(+), 506 deletions(-) delete mode 100644 src/pages/iou/steps/MoneyRequestConfirmPage.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9c4375b84ab6..deabdc0ac853 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -267,10 +267,6 @@ const ROUTES = { route: ':iouType/new/participants/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/participants/${reportID}` as const, }, - MONEY_REQUEST_CONFIRMATION: { - route: ':iouType/new/confirmation/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/confirmation/${reportID}` as const, - }, MONEY_REQUEST_DATE: { route: ':iouType/new/date/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/date/${reportID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 2bf40caede57..5a8922ee01c3 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -141,7 +141,6 @@ const SCREENS = { ROOT: 'Money_Request', AMOUNT: 'Money_Request_Amount', PARTICIPANTS: 'Money_Request_Participants', - CONFIRMATION: 'Money_Request_Confirmation', CURRENCY: 'Money_Request_Currency', DATE: 'Money_Request_Date', DESCRIPTION: 'Money_Request_Description', diff --git a/src/components/DistanceRequest/index.js b/src/components/DistanceRequest/index.js index b63ce337a1d9..34295dda74e7 100644 --- a/src/components/DistanceRequest/index.js +++ b/src/components/DistanceRequest/index.js @@ -163,7 +163,7 @@ function DistanceRequest({transactionID, report, transaction, route, isEditingRe }, [waypoints, previousWaypoints]); const navigateBack = () => { - Navigation.goBack(isEditingNewRequest ? ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID) : ROUTES.HOME); + Navigation.goBack(isEditingNewRequest ? ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID) : ROUTES.HOME); }; /** diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index c9325206e5b2..3a843e400409 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -93,7 +93,6 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../pages/iou/MoneyRequestSelectorPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.AMOUNT]: () => require('../../../pages/iou/steps/NewRequestAmountPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: () => require('../../../pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage').default as React.ComponentType, - [SCREENS.MONEY_REQUEST.CONFIRMATION]: () => require('../../../pages/iou/steps/MoneyRequestConfirmPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CURRENCY]: () => require('../../../pages/iou/IOUCurrencySelection').default as React.ComponentType, [SCREENS.MONEY_REQUEST.DATE]: () => require('../../../pages/iou/MoneyRequestDatePage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.DESCRIPTION]: () => require('../../../pages/iou/MoneyRequestDescriptionPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index 5df2bcf0e57b..d4e04d5402e2 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -428,7 +428,6 @@ const linkingConfig: LinkingOptions = { [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: ROUTES.MONEY_REQUEST_STEP_TAX_RATE.route, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: ROUTES.MONEY_REQUEST_PARTICIPANTS.route, - [SCREENS.MONEY_REQUEST.CONFIRMATION]: ROUTES.MONEY_REQUEST_CONFIRMATION.route, [SCREENS.MONEY_REQUEST.DATE]: ROUTES.MONEY_REQUEST_DATE.route, [SCREENS.MONEY_REQUEST.CURRENCY]: ROUTES.MONEY_REQUEST_CURRENCY.route, [SCREENS.MONEY_REQUEST.DESCRIPTION]: ROUTES.MONEY_REQUEST_DESCRIPTION.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 2371c764f42a..29f7cd4aac30 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -185,8 +185,9 @@ type MoneyRequestNavigatorParamList = { iouType: string; reportID: string; }; - [SCREENS.MONEY_REQUEST.CONFIRMATION]: { + [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: { iouType: string; + transactionID: string; reportID: string; }; [SCREENS.MONEY_REQUEST.CURRENCY]: { diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index a9e1b09ed984..34fb20091493 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -3684,7 +3684,7 @@ function navigateToNextPage(iou, iouType, report, path = '') { // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', report.reportID)); return; } @@ -3705,7 +3705,7 @@ function navigateToNextPage(iou, iouType, report, path = '') { resetMoneyRequestCategory(); resetMoneyRequestTag(); } - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', report.reportID)); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); diff --git a/src/pages/iou/MoneyRequestCategoryPage.js b/src/pages/iou/MoneyRequestCategoryPage.js index ceb2152d2b49..b3ca0a5d7ae0 100644 --- a/src/pages/iou/MoneyRequestCategoryPage.js +++ b/src/pages/iou/MoneyRequestCategoryPage.js @@ -50,7 +50,7 @@ function MoneyRequestCategoryPage({route, report, iou}) { const iouType = lodashGet(route, 'params.iouType', ''); const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); }; const updateCategory = (category) => { @@ -60,7 +60,7 @@ function MoneyRequestCategoryPage({route, report, iou}) { IOU.setMoneyRequestCategory(category.searchText); } - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); }; return ( diff --git a/src/pages/iou/MoneyRequestDatePage.js b/src/pages/iou/MoneyRequestDatePage.js index f6159abd73f6..c99c07a80624 100644 --- a/src/pages/iou/MoneyRequestDatePage.js +++ b/src/pages/iou/MoneyRequestDatePage.js @@ -69,7 +69,7 @@ function MoneyRequestDatePage({iou, route, selectedTab}) { }, [iou.id, iou.participants, iou.amount, iou.receiptPath, iouType, reportID, isDistanceRequest]); function navigateBack() { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); } /** diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js index fe3100b8c3bd..a2209818ee1a 100644 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ b/src/pages/iou/MoneyRequestDescriptionPage.js @@ -92,7 +92,7 @@ function MoneyRequestDescriptionPage({iou, route, selectedTab}) { }, [iou.id, iou.participants, iou.amount, iou.receiptPath, iouType, reportID, isDistanceRequest]); function navigateBack() { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); } /** diff --git a/src/pages/iou/MoneyRequestMerchantPage.js b/src/pages/iou/MoneyRequestMerchantPage.js index ce96a09446b9..894bd317464c 100644 --- a/src/pages/iou/MoneyRequestMerchantPage.js +++ b/src/pages/iou/MoneyRequestMerchantPage.js @@ -68,7 +68,7 @@ function MoneyRequestMerchantPage({iou, route}) { }, [iou.id, iou.participants, iou.amount, iou.receiptPath, iouType, reportID]); function navigateBack() { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST__STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); } const validate = useCallback((value) => { diff --git a/src/pages/iou/MoneyRequestTagPage.js b/src/pages/iou/MoneyRequestTagPage.js index 60e40d665580..7fd08f20d652 100644 --- a/src/pages/iou/MoneyRequestTagPage.js +++ b/src/pages/iou/MoneyRequestTagPage.js @@ -60,7 +60,7 @@ function MoneyRequestTagPage({route, report, policyTags, iou}) { const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', report.reportID)); }; const updateTag = (selectedTag) => { diff --git a/src/pages/iou/NewDistanceRequestPage.js b/src/pages/iou/NewDistanceRequestPage.js index 750ac5d0141e..87f92b8c1907 100644 --- a/src/pages/iou/NewDistanceRequestPage.js +++ b/src/pages/iou/NewDistanceRequestPage.js @@ -57,7 +57,7 @@ function NewDistanceRequestPage({iou, report, route}) { const onSubmit = useCallback(() => { if (isEditingNewRequest) { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, lodashGet(iou, 'transactionID', '1'), report.reportID)); return; } IOU.navigateToNextPage(iou, iouType, report); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.js b/src/pages/iou/request/step/IOURequestStepConfirmation.js index 6028a735d132..cb9edfb5868b 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.js +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.js @@ -23,7 +23,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import personalDetailsPropType from '@pages/personalDetailsPropType'; +import {usePersonalDetails} from '@components/OnyxProvider'; import reportPropTypes from '@pages/reportPropTypes'; import {policyPropTypes} from '@pages/workspace/withPolicy'; import * as IOU from '@userActions/IOU'; @@ -43,9 +43,6 @@ const propTypes = { /** The personal details of the current user */ ...withCurrentUserPersonalDetailsPropTypes, - /** Personal details of all users */ - personalDetails: personalDetailsPropType, - /** The policy of the report */ ...policyPropTypes, @@ -62,7 +59,6 @@ const propTypes = { transaction: transactionPropTypes, }; const defaultProps = { - personalDetails: {}, policy: {}, policyCategories: {}, policyTags: {}, @@ -72,7 +68,6 @@ const defaultProps = { }; function IOURequestStepConfirmation({ currentUserPersonalDetails, - personalDetails, policy, policyTags, policyCategories, @@ -86,6 +81,7 @@ function IOURequestStepConfirmation({ const {translate} = useLocalize(); const {windowWidth} = useWindowDimensions(); const {isOffline} = useNetwork(); + const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; const [receiptFile, setReceiptFile] = useState(); const receiptFilename = lodashGet(transaction, 'filename'); const receiptPath = lodashGet(transaction, 'receipt.source'); @@ -385,12 +381,6 @@ export default compose( withCurrentUserPersonalDetails, withWritableReportOrNotFound, withFullTransactionOrNotFound, - withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file withOnyx({ policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js deleted file mode 100644 index 1738ac78df47..000000000000 --- a/src/pages/iou/steps/MoneyRequestConfirmPage.js +++ /dev/null @@ -1,473 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import categoryPropTypes from '@components/categoryPropTypes'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; -import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationList'; -import {usePersonalDetails} from '@components/OnyxProvider'; -import ScreenWrapper from '@components/ScreenWrapper'; -import tagPropTypes from '@components/tagPropTypes'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails'; -import withLocalize from '@components/withLocalize'; -import useInitialValue from '@hooks/useInitialValue'; -import useNetwork from '@hooks/useNetwork'; -import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import compose from '@libs/compose'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; -import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; -import Navigation from '@libs/Navigation/Navigation'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as ReportUtils from '@libs/ReportUtils'; -import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes'; -import reportPropTypes from '@pages/reportPropTypes'; -import {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy'; -import * as IOU from '@userActions/IOU'; -import * as Policy from '@userActions/Policy'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; - -const propTypes = { - /** React Navigation route */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - }).isRequired, - - report: reportPropTypes, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, - - /** The policy of the current request */ - policy: policyPropTypes, - - policyTags: tagPropTypes, - - policyCategories: PropTypes.objectOf(categoryPropTypes), - - ...withCurrentUserPersonalDetailsPropTypes, -}; - -const defaultProps = { - report: {}, - policyCategories: {}, - policyTags: {}, - iou: iouDefaultProps, - policy: policyDefaultProps, - ...withCurrentUserPersonalDetailsDefaultProps, -}; - -function MoneyRequestConfirmPage(props) { - const styles = useThemeStyles(); - const {isOffline} = useNetwork(); - const {windowWidth} = useWindowDimensions(); - const prevMoneyRequestId = useRef(props.iou.id); - const iouType = useInitialValue(() => lodashGet(props.route, 'params.iouType', '')); - const reportID = useInitialValue(() => lodashGet(props.route, 'params.reportID', '')); - const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType, props.selectedTab); - const isScanRequest = MoneyRequestUtils.isScanRequest(props.selectedTab); - const [receiptFile, setReceiptFile] = useState(); - const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; - - const participants = useMemo( - () => - _.map(props.iou.participants, (participant) => { - const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false); - return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails); - }), - [props.iou.participants, personalDetails], - ); - const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(props.report)), [props.report]); - const isManualRequestDM = props.selectedTab === CONST.TAB_REQUEST.MANUAL && iouType === CONST.IOU.TYPE.REQUEST; - - useEffect(() => { - const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat); - if (policyExpenseChat) { - Policy.openDraftWorkspaceRequest(policyExpenseChat.policyID); - } - }, [isOffline, participants, props.iou.billable, props.policy]); - - const defaultBillable = lodashGet(props.policy, 'defaultBillable', false); - useEffect(() => { - IOU.setMoneyRequestBillable(defaultBillable); - }, [defaultBillable, isOffline]); - - useEffect(() => { - if (!props.iou.receiptPath || !props.iou.receiptFilename) { - return; - } - const onSuccess = (file) => { - const receipt = file; - receipt.state = file && isManualRequestDM ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY; - setReceiptFile(receipt); - }; - const onFailure = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID)); - }; - FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename, onSuccess, onFailure); - }, [props.iou.receiptPath, props.iou.receiptFilename, isManualRequestDM, iouType, reportID]); - - useEffect(() => { - // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request - if (!isDistanceRequest && prevMoneyRequestId.current !== props.iou.id) { - // The ID is cleared on completing a request. In that case, we will do nothing. - if (props.iou.id) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - return; - } - - // Reset the money request Onyx if the ID in Onyx does not match the ID from params - const moneyRequestId = `${iouType}${reportID}`; - const shouldReset = !isDistanceRequest && props.iou.id !== moneyRequestId && !_.isEmpty(reportID); - if (shouldReset) { - IOU.resetMoneyRequestInfo(moneyRequestId); - } - - if (_.isEmpty(props.iou.participants) || (props.iou.amount === 0 && !props.iou.receiptPath && !isDistanceRequest) || shouldReset || ReportUtils.isArchivedRoom(props.report)) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - - return () => { - prevMoneyRequestId.current = props.iou.id; - }; - }, [props.iou.participants, props.iou.amount, props.iou.id, props.iou.receiptPath, isDistanceRequest, props.report, iouType, reportID]); - - const navigateBack = () => { - let fallback; - if (reportID) { - fallback = ROUTES.MONEY_REQUEST.getRoute(iouType, reportID); - } else { - fallback = ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType); - } - Navigation.goBack(fallback); - }; - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - * @param {File} [receipt] - */ - const requestMoney = useCallback( - (selectedParticipants, trimmedComment, receipt) => { - IOU.requestMoney( - props.report, - props.iou.amount, - props.iou.currency, - props.iou.created, - props.iou.merchant, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - selectedParticipants[0], - trimmedComment, - receipt, - props.iou.category, - props.iou.tag, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ); - }, - [ - props.report, - props.iou.amount, - props.iou.currency, - props.iou.created, - props.iou.merchant, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.category, - props.iou.tag, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ], - ); - - /** - * @param {Array} selectedParticipants - * @param {String} trimmedComment - */ - const createDistanceRequest = useCallback( - (selectedParticipants, trimmedComment) => { - IOU.createDistanceRequest( - props.report, - selectedParticipants[0], - trimmedComment, - props.iou.created, - props.iou.transactionID, - props.iou.category, - props.iou.tag, - props.iou.amount, - props.iou.currency, - props.iou.merchant, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ); - }, - [ - props.report, - props.iou.created, - props.iou.transactionID, - props.iou.category, - props.iou.tag, - props.iou.amount, - props.iou.currency, - props.iou.merchant, - props.iou.billable, - props.policy, - props.policyTags, - props.policyCategories, - ], - ); - - const createTransaction = useCallback( - (selectedParticipants) => { - const trimmedComment = props.iou.comment.trim(); - - // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed - if (iouType === CONST.IOU.TYPE.SPLIT && props.iou.receiptPath) { - const existingSplitChatReportID = CONST.REGEX.NUMBER.test(reportID) ? reportID : ''; - const onSuccess = (receipt) => { - IOU.startSplitBill( - selectedParticipants, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - trimmedComment, - receipt, - existingSplitChatReportID, - ); - }; - FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename, onSuccess); - return; - } - - // IOUs created from a group report will have a reportID param in the route. - // Since the user is already viewing the report, we don't need to navigate them to the report - if (iouType === CONST.IOU.TYPE.SPLIT && CONST.REGEX.NUMBER.test(reportID)) { - IOU.splitBill( - selectedParticipants, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.amount, - trimmedComment, - props.iou.currency, - props.iou.category, - props.iou.tag, - reportID, - props.iou.merchant, - ); - return; - } - - // If the request is created from the global create menu, we also navigate the user to the group report - if (iouType === CONST.IOU.TYPE.SPLIT) { - IOU.splitBillAndOpenReport( - selectedParticipants, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.amount, - trimmedComment, - props.iou.currency, - props.iou.category, - props.iou.tag, - props.iou.merchant, - ); - return; - } - - if (receiptFile) { - requestMoney(selectedParticipants, trimmedComment, receiptFile); - return; - } - - if (isDistanceRequest) { - createDistanceRequest(selectedParticipants, trimmedComment); - return; - } - - requestMoney(selectedParticipants, trimmedComment); - }, - [ - props.iou.amount, - props.iou.comment, - props.currentUserPersonalDetails.login, - props.currentUserPersonalDetails.accountID, - props.iou.currency, - props.iou.category, - props.iou.tag, - props.iou.receiptPath, - props.iou.receiptFilename, - isDistanceRequest, - requestMoney, - createDistanceRequest, - receiptFile, - iouType, - reportID, - props.iou.merchant, - ], - ); - - /** - * Checks if user has a GOLD wallet then creates a paid IOU report on the fly - * - * @param {String} paymentMethodType - */ - const sendMoney = useCallback( - (paymentMethodType) => { - const currency = props.iou.currency; - const trimmedComment = props.iou.comment.trim(); - const participant = participants[0]; - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { - IOU.sendMoneyElsewhere(props.report, props.iou.amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); - return; - } - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { - IOU.sendMoneyWithWallet(props.report, props.iou.amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); - } - }, - [props.iou.amount, props.iou.comment, participants, props.iou.currency, props.currentUserPersonalDetails.accountID, props.report], - ); - - const headerTitle = () => { - if (isDistanceRequest) { - return props.translate('common.distance'); - } - - if (iouType === CONST.IOU.TYPE.SPLIT) { - return props.translate('iou.split'); - } - - if (iouType === CONST.IOU.TYPE.SEND) { - return props.translate('common.send'); - } - - if (isScanRequest) { - return props.translate('tabSelector.scan'); - } - - return props.translate('tabSelector.manual'); - }; - - return ( - - {({safeAreaPaddingBottomStyle}) => ( - - Navigation.navigate(ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, reportID)), - }, - ]} - /> - { - const newParticipants = _.map(props.iou.participants, (participant) => { - if (participant.accountID === option.accountID) { - return {...participant, selected: !participant.selected}; - } - return participant; - }); - IOU.setMoneyRequestParticipants(newParticipants); - }} - receiptPath={props.iou.receiptPath} - receiptFilename={props.iou.receiptFilename} - iouType={iouType} - reportID={reportID} - isPolicyExpenseChat={isPolicyExpenseChat} - // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. - // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, - // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill - // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from - // the floating-action-button (since it is something that exists outside the context of a report). - canModifyParticipants={!_.isEmpty(reportID)} - policyID={props.report.policyID} - bankAccountRoute={ReportUtils.getBankAccountRoute(props.report)} - iouMerchant={props.iou.merchant} - iouCreated={props.iou.created} - isScanRequest={isScanRequest} - isDistanceRequest={isDistanceRequest} - shouldShowSmartScanFields={_.isEmpty(props.iou.receiptPath)} - /> - - )} - - ); -} - -MoneyRequestConfirmPage.displayName = 'MoneyRequestConfirmPage'; -MoneyRequestConfirmPage.propTypes = propTypes; -MoneyRequestConfirmPage.defaultProps = defaultProps; - -export default compose( - withCurrentUserPersonalDetails, - withLocalize, - withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - report: { - key: ({route, iou}) => { - const reportID = IOU.getIOUReportID(iou, route); - - return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - }, - }, - selectedTab: { - key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`, - }, - }), - withOnyx({ - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(MoneyRequestConfirmPage); diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 216154be9cd4..1feb7a2c32fd 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -89,7 +89,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route, transaction}) { IOU.setMoneyRequestId(moneyRequestType); IOU.resetMoneyRequestCategory(); IOU.resetMoneyRequestTag(); - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(moneyRequestType, lodashGet(transaction, 'transactionID', 1), reportID)); }; const navigateBack = useCallback((forceFallback = false) => { diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index 1df74569e4c3..007a63bdb713 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -113,7 +113,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { }, [iou.participants, iou.amount, iou.id, isEditing, iouType, reportID, isDistanceRequestTab]); const navigateBack = () => { - Navigation.goBack(isEditing ? ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID) : ROUTES.HOME); + Navigation.goBack(isEditing ? ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID) : ROUTES.HOME); }; const navigateToCurrencySelectionPage = () => { @@ -134,7 +134,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { IOU.setMoneyRequestCurrency(currency); if (isEditing) { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); return; } From 8e4e4d803f40cd0c35b05ee1a51da2c4899154a3 Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 31 Jan 2024 16:54:59 +0700 Subject: [PATCH 002/102] fix lint --- src/pages/iou/request/step/IOURequestStepConfirmation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.js b/src/pages/iou/request/step/IOURequestStepConfirmation.js index cb9edfb5868b..f867e57f9a13 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.js +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.js @@ -8,6 +8,7 @@ import categoryPropTypes from '@components/categoryPropTypes'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestConfirmationList from '@components/MoneyTemporaryForRefactorRequestConfirmationList'; +import {usePersonalDetails} from '@components/OnyxProvider'; import ScreenWrapper from '@components/ScreenWrapper'; import tagPropTypes from '@components/tagPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; @@ -23,7 +24,6 @@ import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import {usePersonalDetails} from '@components/OnyxProvider'; import reportPropTypes from '@pages/reportPropTypes'; import {policyPropTypes} from '@pages/workspace/withPolicy'; import * as IOU from '@userActions/IOU'; From ee1efe95e93aea8be888b50338534cf3f6f28bff Mon Sep 17 00:00:00 2001 From: Dylan Date: Wed, 31 Jan 2024 17:09:35 +0700 Subject: [PATCH 003/102] update send money flow --- .../SidebarScreen/FloatingActionButtonAndPopover.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index bbcdc5cebef4..7281868f47d9 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -182,7 +182,14 @@ function FloatingActionButtonAndPopover(props) { { icon: Expensicons.Send, text: props.translate('iou.sendMoney'), - onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SEND)), + onSelected: () => + interceptAnonymousUser(() => + Navigation.navigate( + // When starting to create a money request from the global FAB, there is not an existing report yet. A random optimistic reportID is generated and used + // for all of the routes in the creation flow. + ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.TYPE.SEND, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()), + ), + ), }, ...[ { From 6364ee97a9b52a3edd970134a2d9a786e5477459 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 5 Feb 2024 16:58:36 +0700 Subject: [PATCH 004/102] remove NewRequestAmountPage --- src/ROUTES.ts | 20 ++++++------ src/SCREENS.ts | 1 - .../MoneyRequestConfirmationList.js | 10 +++++- ...oraryForRefactorRequestConfirmationList.js | 7 ++--- .../ReportActionItem/MoneyRequestView.tsx | 4 ++- src/libs/IOUUtils.ts | 2 +- .../AppNavigator/ModalStackNavigators.tsx | 1 - src/libs/Navigation/linkingConfig/config.ts | 1 - src/libs/Navigation/types.ts | 1 - .../AttachmentPickerWithMenuItems.js | 6 ++-- .../FloatingActionButtonAndPopover.js | 7 ++++- .../request/IOURequestRedirectToStartPage.js | 2 +- .../iou/request/step/IOURequestStepAmount.js | 31 ++++++++++++++++--- .../step/withFullTransactionOrNotFound.js | 11 ++++++- 14 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index a84dc9c8f9ae..7156ecdfd2fb 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -265,10 +265,6 @@ const ROUTES = { route: ':iouType/new/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}` as const, }, - MONEY_REQUEST_AMOUNT: { - route: ':iouType/new/amount/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/amount/${reportID}` as const, - }, MONEY_REQUEST_PARTICIPANTS: { route: ':iouType/new/participants/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/participants/${reportID}` as const, @@ -317,17 +313,18 @@ const ROUTES = { MONEY_REQUEST_SCAN_TAB: ':iouType/new/:reportID?/scan', MONEY_REQUEST_CREATE: { - route: 'create/:iouType/start/:transactionID/:reportID', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}` as const, + route: ':action/:iouType/start/:transactionID/:reportID', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string) => + `${action}/${iouType}/start/${transactionID}/${reportID}` as const, }, MONEY_REQUEST_STEP_CONFIRMATION: { route: 'create/:iouType/confirmation/:transactionID/:reportID', getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/confirmation/${transactionID}/${reportID}` as const, }, MONEY_REQUEST_STEP_AMOUNT: { - route: 'create/:iouType/amount/:transactionID/:reportID', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => - getUrlWithBackToParam(`create/${iouType}/amount/${transactionID}/${reportID}`, backTo), + route: ':action/:iouType/amount/:transactionID/:reportID', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, backTo = '') => + getUrlWithBackToParam(`${action}/${iouType}/amount/${transactionID}/${reportID}`, backTo), }, MONEY_REQUEST_STEP_TAX_RATE: { route: 'create/:iouType/taxRate/:transactionID/:reportID?', @@ -400,8 +397,9 @@ const ROUTES = { getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}/distance` as const, }, MONEY_REQUEST_CREATE_TAB_MANUAL: { - route: 'create/:iouType/start/:transactionID/:reportID/manual', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}/manual` as const, + route: ':action/:iouType/start/:transactionID/:reportID/manual', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string) => + `${action}/${iouType}/start/${transactionID}/${reportID}/manual` as const, }, MONEY_REQUEST_CREATE_TAB_SCAN: { route: 'create/:iouType/start/:transactionID/:reportID/scan', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 96b284dbea2f..8fc25571c9d9 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -145,7 +145,6 @@ const SCREENS = { STEP_TAX_AMOUNT: 'Money_Request_Step_Tax_Amount', STEP_TAX_RATE: 'Money_Request_Step_Tax_Rate', ROOT: 'Money_Request', - AMOUNT: 'Money_Request_Amount', PARTICIPANTS: 'Money_Request_Participants', CONFIRMATION: 'Money_Request_Confirmation', CURRENCY: 'Money_Request_Currency', diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index afabb40fd9f4..4f4861bdc2e5 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -645,7 +645,15 @@ function MoneyRequestConfirmationList(props) { return; } if (props.isEditingSplitBill) { - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute( + CONST.IOU.ACTION.EDIT, + CONST.IOU.TYPE.SPLIT, + props.transaction.transactionID, + props.reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_AMOUNT.getRoute(props.iouType, props.reportID)); diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 2aff0444a59e..34212facfdc4 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -672,11 +672,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (isDistanceRequest) { return; } - if (isEditingSplitBill) { - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(reportID, reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); - return; - } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams())); + const action = isEditingSplitBill ? CONST.IOU.ACTION.EDIT : CONST.IOU.ACTION.CREATE; + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams())); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 3533506797bb..1d9267f09a91 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -254,7 +254,9 @@ function MoneyRequestView({ titleStyle={styles.newKansasLarge} interactive={canEditAmount} shouldShowRightIcon={canEditAmount} - onPress={() => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.AMOUNT))} + onPress={() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID)) + } brickRoadIndicator={hasViolations('amount') || (hasErrors && transactionAmount === 0) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={hasErrors && transactionAmount === 0 ? translate('common.error.enterAmount') : ''} /> diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index c0fb4c6195b1..fcaafd961950 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -17,7 +17,7 @@ function navigateToStartMoneyRequestStep(requestType: ValueOf require('../../../pages/iou/request/step/IOURequestStepTag').default as React.ComponentType, [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: () => require('../../../pages/iou/request/step/IOURequestStepWaypoint').default as React.ComponentType, [SCREENS.MONEY_REQUEST.ROOT]: () => require('../../../pages/iou/MoneyRequestSelectorPage').default as React.ComponentType, - [SCREENS.MONEY_REQUEST.AMOUNT]: () => require('../../../pages/iou/steps/NewRequestAmountPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: () => require('../../../pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CONFIRMATION]: () => require('../../../pages/iou/steps/MoneyRequestConfirmPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CURRENCY]: () => require('../../../pages/iou/IOUCurrencySelection').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index f1c9c316fe93..7cdf9c3679fa 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -397,7 +397,6 @@ const config: LinkingOptions['config'] = { }, }, }, - [SCREENS.MONEY_REQUEST.AMOUNT]: ROUTES.MONEY_REQUEST_AMOUNT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: ROUTES.MONEY_REQUEST_STEP_TAX_RATE.route, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: ROUTES.MONEY_REQUEST_PARTICIPANTS.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 3c4cf17853f1..077ebd4caaac 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -194,7 +194,6 @@ type RoomInviteNavigatorParamList = { type MoneyRequestNavigatorParamList = { [SCREENS.MONEY_REQUEST.ROOT]: undefined; - [SCREENS.MONEY_REQUEST.AMOUNT]: undefined; [SCREENS.MONEY_REQUEST.PARTICIPANTS]: { iouType: string; reportID: string; diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js index df5645ae61ad..7f10e7fa96bd 100644 --- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js +++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js @@ -145,12 +145,14 @@ function AttachmentPickerWithMenuItems({ [CONST.IOU.TYPE.SPLIT]: { icon: Expensicons.Receipt, text: translate('iou.splitBill'), - onSelected: () => Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.TYPE.SPLIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID)), + onSelected: () => + Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SPLIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID)), }, [CONST.IOU.TYPE.REQUEST]: { icon: Expensicons.MoneyCircle, text: translate('iou.requestMoney'), - onSelected: () => Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.TYPE.REQUEST, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID)), + onSelected: () => + Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.REQUEST, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID)), }, [CONST.IOU.TYPE.SEND]: { icon: Expensicons.Send, diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 0df490fa4466..0dc290f53f2a 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -169,7 +169,12 @@ function FloatingActionButtonAndPopover(props) { Navigation.navigate( // When starting to create a money request from the global FAB, there is not an existing report yet. A random optimistic reportID is generated and used // for all of the routes in the creation flow. - ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.TYPE.REQUEST, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()), + ROUTES.MONEY_REQUEST_CREATE.getRoute( + CONST.IOU.ACTION.CREATE, + CONST.IOU.TYPE.REQUEST, + CONST.IOU.OPTIMISTIC_TRANSACTION_ID, + ReportUtils.generateReportID(), + ), ), ), }, diff --git a/src/pages/iou/request/IOURequestRedirectToStartPage.js b/src/pages/iou/request/IOURequestRedirectToStartPage.js index ee98c8006cdb..e4091c48f1b8 100644 --- a/src/pages/iou/request/IOURequestRedirectToStartPage.js +++ b/src/pages/iou/request/IOURequestRedirectToStartPage.js @@ -43,7 +43,7 @@ function IOURequestRedirectToStartPage({ if (iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE_TAB_DISTANCE.getRoute(iouType, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, optimisticReportID)); } else if (iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL) { - Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL.getRoute(iouType, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, optimisticReportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL.getRoute(CONST.IOU.ACTION.CREATE, iouType, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, optimisticReportID)); } else if (iouRequestType === CONST.IOU.REQUEST_TYPE.SCAN) { Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(iouType, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, optimisticReportID)); } diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 84e0ac8533c5..4c2b24c87be2 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -59,7 +59,7 @@ const getTaxAmount = (transaction, defaultTaxValue, amount) => { function IOURequestStepAmount({ report, route: { - params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency}, + params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency, action}, }, transaction, transaction: {currency: originalCurrency}, @@ -71,6 +71,8 @@ function IOURequestStepAmount({ const focusTimeoutRef = useRef(null); const iouRequestType = getRequestType(transaction); const currency = selectedCurrency || originalCurrency; + const isEditing = action === CONST.IOU.ACTION.EDIT; + const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); const isTaxTrackingEnabled = isPolicyExpenseChat && policy.isTaxTrackingEnabled; @@ -128,21 +130,40 @@ function IOURequestStepAmount({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); }; + const saveAmountAndCurrency = ({amount}) => { + const newAmount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); + + // If the value hasn't changed, don't request to save changes on the server and just close the modal + if (newAmount === TransactionUtils.getAmount(transaction) && currency === TransactionUtils.getCurrency(transaction)) { + Navigation.dismissModal(); + return; + } + + if (isSplitBill) { + IOU.setDraftSplitTransaction(transactionID, {amount: newAmount, currency}); + Navigation.goBack(backTo); + return; + } + + IOU.updateMoneyRequestAmountAndCurrency(transactionID, reportID, currency, newAmount); + Navigation.dismissModal(); + }; + return ( (textInput.current = e)} onCurrencyButtonPress={navigateToCurrencySelectionPage} - onSubmitButtonPress={navigateToNextPage} + onSubmitButtonPress={isEditing ? saveAmountAndCurrency : navigateToNextPage} selectedTab={iouRequestType} /> diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.js b/src/pages/iou/request/step/withFullTransactionOrNotFound.js index 7cdbb3484999..801ad403af2a 100644 --- a/src/pages/iou/request/step/withFullTransactionOrNotFound.js +++ b/src/pages/iou/request/step/withFullTransactionOrNotFound.js @@ -71,7 +71,16 @@ export default function (WrappedComponent) { key: ({route}) => { const transactionID = lodashGet(route, 'params.transactionID', 0); const userAction = lodashGet(route, 'params.action', CONST.IOU.ACTION.CREATE); - return `${userAction === CONST.IOU.ACTION.CREATE ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; + const isSplitBill = lodashGet(route, 'params.iouType', CONST.IOU.TYPE.REQUEST) === CONST.IOU.TYPE.SPLIT; + let transactionCollectionKey = ONYXKEYS.COLLECTION.TRANSACTION_DRAFT; + if (userAction === CONST.IOU.ACTION.EDIT) { + if (isSplitBill) { + transactionCollectionKey = ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT; + } else { + transactionCollectionKey = ONYXKEYS.COLLECTION.TRANSACTION; + } + } + return `${transactionCollectionKey}${transactionID}`; }, }, })(WithFullTransactionOrNotFoundWithRef); From 02a8a1897982b3d356a8541246c2545be55a5c6d Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 5 Feb 2024 17:20:20 +0700 Subject: [PATCH 005/102] fix negative amount case --- src/libs/TransactionUtils.ts | 4 ++-- src/pages/iou/request/step/IOURequestStepAmount.js | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 8e48eddea0ac..6f55eb961b14 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -281,12 +281,12 @@ function getAmount(transaction: OnyxEntry, isFromExpenseReport?: bo // we need to return an opposite sign than is saved in the transaction object let amount = transaction?.modifiedAmount ?? 0; if (amount) { - return -amount; + return Math.abs(amount); } // To avoid -0 being shown, lets only change the sign if the value is other than 0. amount = transaction?.amount ?? 0; - return amount ? -amount : 0; + return amount ? Math.abs(amount) : 0; } /** diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 4c2b24c87be2..fdc07f38eed6 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -71,9 +71,12 @@ function IOURequestStepAmount({ const focusTimeoutRef = useRef(null); const iouRequestType = getRequestType(transaction); const currency = selectedCurrency || originalCurrency; + const {amount: transactionAmount} = ReportUtils.getTransactionDetails(transaction); const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; + console.log(transaction); + const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); const isTaxTrackingEnabled = isPolicyExpenseChat && policy.isTaxTrackingEnabled; @@ -160,7 +163,7 @@ function IOURequestStepAmount({ (textInput.current = e)} onCurrencyButtonPress={navigateToCurrencySelectionPage} onSubmitButtonPress={isEditing ? saveAmountAndCurrency : navigateToNextPage} From a719511f5f925628405cb595599cf2fcb2f444d2 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 5 Feb 2024 22:57:09 +0700 Subject: [PATCH 006/102] fix the case edit split --- .../iou/request/step/IOURequestStepAmount.js | 10 ++++--- .../step/withFullTransactionOrNotFound.js | 26 +++++++++++-------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index fdc07f38eed6..63cf19299a80 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -2,6 +2,7 @@ import {useFocusEffect} from '@react-navigation/native'; import PropTypes from 'prop-types'; import React, {useCallback, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import taxPropTypes from '@components/taxPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; @@ -33,6 +34,9 @@ const propTypes = { /** The transaction object being modified in Onyx */ transaction: transactionPropTypes, + /** The draft transaction of scan split bill */ + splitTransactionDraft: transactionPropTypes, + /* Onyx Props */ /** Collection of tax rates attached to a policy */ policyTaxRates: taxPropTypes, @@ -49,6 +53,7 @@ const defaultProps = { transaction: {}, policyTaxRates: {}, policy: {}, + splitTransactionDraft: {}, }; const getTaxAmount = (transaction, defaultTaxValue, amount) => { @@ -62,6 +67,7 @@ function IOURequestStepAmount({ params: {iouType, reportID, transactionID, backTo, currency: selectedCurrency, action}, }, transaction, + splitTransactionDraft, transaction: {currency: originalCurrency}, policyTaxRates, policy, @@ -71,12 +77,10 @@ function IOURequestStepAmount({ const focusTimeoutRef = useRef(null); const iouRequestType = getRequestType(transaction); const currency = selectedCurrency || originalCurrency; - const {amount: transactionAmount} = ReportUtils.getTransactionDetails(transaction); + const {amount: transactionAmount} = ReportUtils.getTransactionDetails(_.isEmpty(splitTransactionDraft) ? transaction : splitTransactionDraft); const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; - console.log(transaction); - const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); const isTaxTrackingEnabled = isPolicyExpenseChat && policy.isTaxTrackingEnabled; diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.js b/src/pages/iou/request/step/withFullTransactionOrNotFound.js index 801ad403af2a..1999b3a90574 100644 --- a/src/pages/iou/request/step/withFullTransactionOrNotFound.js +++ b/src/pages/iou/request/step/withFullTransactionOrNotFound.js @@ -18,12 +18,16 @@ const propTypes = { /** The report corresponding to the reportID in the route params */ transaction: transactionPropTypes, + /** The draft transaction of scan split bill */ + splitTransactionDraft: transactionPropTypes, + route: IOURequestStepRoutePropTypes.isRequired, }; const defaultProps = { forwardedRef: () => {}, transaction: {}, + splitTransactionDraft: {}, }; export default function (WrappedComponent) { @@ -31,6 +35,7 @@ export default function (WrappedComponent) { function WithFullTransactionOrNotFound({forwardedRef, ...props}) { const { transaction: {transactionID}, + splitTransactionDraft: {transactionID: splitTransactionDraftID}, } = props; const isFocused = useIsFocused(); @@ -38,7 +43,7 @@ export default function (WrappedComponent) { // If the transaction does not have a transactionID, then the transaction no longer exists in Onyx as a full transaction and the not-found page should be shown. // In addition, the not-found page should be shown only if the component screen's route is active (i.e. is focused). // This is to prevent it from showing when the modal is being dismissed while navigating to a different route (e.g. on requesting money). - if (!transactionID) { + if (!transactionID && !splitTransactionDraftID) { return ; } @@ -71,16 +76,15 @@ export default function (WrappedComponent) { key: ({route}) => { const transactionID = lodashGet(route, 'params.transactionID', 0); const userAction = lodashGet(route, 'params.action', CONST.IOU.ACTION.CREATE); - const isSplitBill = lodashGet(route, 'params.iouType', CONST.IOU.TYPE.REQUEST) === CONST.IOU.TYPE.SPLIT; - let transactionCollectionKey = ONYXKEYS.COLLECTION.TRANSACTION_DRAFT; - if (userAction === CONST.IOU.ACTION.EDIT) { - if (isSplitBill) { - transactionCollectionKey = ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT; - } else { - transactionCollectionKey = ONYXKEYS.COLLECTION.TRANSACTION; - } - } - return `${transactionCollectionKey}${transactionID}`; + return `${userAction === CONST.IOU.ACTION.CREATE ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; + }, + }, + splitTransactionDraft: { + key: ({route}) => { + const transactionID = lodashGet(route, 'params.transactionID', 0); + const userAction = lodashGet(route, 'params.action', CONST.IOU.ACTION.CREATE); + const isEditingSplitBill = userAction === CONST.IOU.ACTION.EDIT && lodashGet(route, 'params.iouType', CONST.IOU.TYPE.REQUEST) === CONST.IOU.TYPE.SPLIT; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${isEditingSplitBill ? transactionID : '0'}`; }, }, })(WithFullTransactionOrNotFoundWithRef); From ae15fd56fb9fbfb41f4ca201e0e1fb3ed1f232fa Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 5 Feb 2024 23:03:08 +0700 Subject: [PATCH 007/102] delete old page --- src/pages/iou/MoneyRequestSelectorPage.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/pages/iou/MoneyRequestSelectorPage.js b/src/pages/iou/MoneyRequestSelectorPage.js index 0a0efc38313a..b8b81a904499 100644 --- a/src/pages/iou/MoneyRequestSelectorPage.js +++ b/src/pages/iou/MoneyRequestSelectorPage.js @@ -25,7 +25,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import NewDistanceRequestPage from './NewDistanceRequestPage'; import IOURequestStepScan from './request/step/IOURequestStepScan'; -import NewRequestAmountPage from './steps/NewRequestAmountPage'; const propTypes = { /** React Navigation route */ @@ -127,11 +126,6 @@ function MoneyRequestSelectorPage(props) { /> )} > - {() => } {shouldDisplayDistanceRequest && ( ) : ( - + null )} From 8b9ff58d8d120f31934862eaa5a39420472b5245 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 19 Feb 2024 15:13:58 +0700 Subject: [PATCH 008/102] fix ts check --- src/libs/Navigation/Navigation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 8009c963ade7..4e56586bf1f5 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -94,7 +94,7 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number function parseHybridAppUrl(url: HybridAppRoute | Route): Route { switch (url) { case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE: - return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.TYPE.REQUEST, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); + return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.REQUEST, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); default: return url; } From cc3916e18595f463f7d4647cf7cfcc3d99afc25a Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 28 Feb 2024 05:28:16 +0700 Subject: [PATCH 009/102] feature: empty state ui for lhn --- src/components/BlockingViews/BlockingView.tsx | 63 +++++++++++++++---- .../LHNOptionsList/LHNOptionsList.tsx | 58 +++++++++++++++++ src/languages/en.ts | 6 ++ src/languages/es.ts | 6 ++ src/styles/index.ts | 9 +++ src/styles/variables.ts | 2 + 6 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index 7b33c8054950..f83deaf1477c 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,9 +1,11 @@ import React from 'react'; -import type {ImageSourcePropType} from 'react-native'; +import type {ImageSourcePropType, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; import AutoEmailLink from '@components/AutoEmailLink'; import Icon from '@components/Icon'; +import Lottie from '@components/Lottie'; +import type DotLottieAnimation from '@components/LottieAnimations/types'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; @@ -12,10 +14,29 @@ import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; import type {TranslationPaths} from '@src/languages/types'; -type BlockingViewProps = { - /** Expensicon for the page */ - icon: React.FC | ImageSourcePropType; +type RequiredIllustrationProps = + | { + /** Expensicon for the page */ + icon: React.FC | ImageSourcePropType; + /** + * Animation for the page + * If icon is provided, animation is not required + */ + animation?: DotLottieAnimation; + } + | { + /** Animation for the page */ + animation: DotLottieAnimation; + + /** + * Expensicon for the page + * If animation is provided, icon is not required + */ + icon?: React.FC | ImageSourcePropType; + }; + +type BlockingViewProps = RequiredIllustrationProps & { /** Color for the icon (should be from theme) */ iconColor?: string; @@ -42,9 +63,16 @@ type BlockingViewProps = { /** Whether we should embed the link with subtitle */ shouldEmbedLinkWithSubtitle?: boolean; + + /** Style for the animation */ + animationStyles?: StyleProp; + + /** Render custom subtitle */ + renderSubtitle?: () => React.ReactElement; }; function BlockingView({ + animation, icon, iconColor, title, @@ -55,6 +83,8 @@ function BlockingView({ iconHeight = variables.iconSizeSuperLarge, onLinkPress = () => Navigation.dismissModal(), shouldEmbedLinkWithSubtitle = false, + animationStyles = [], + renderSubtitle, }: BlockingViewProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -79,16 +109,27 @@ function BlockingView({ return ( - + {animation && ( + + )} + {icon && ( + + )} {title} - {shouldEmbedLinkWithSubtitle ? ( + {renderSubtitle ? ( + renderSubtitle() + ) : shouldEmbedLinkWithSubtitle ? ( {renderContent()} ) : ( {renderContent()} diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 27f424ad1b70..18832440082b 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -3,9 +3,17 @@ import type {ReactElement} from 'react'; import React, {memo, useCallback} from 'react'; import {StyleSheet, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import BlockingView from '@components/BlockingViews/BlockingView'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import LottieAnimations from '@components/LottieAnimations'; +import Text from '@components/Text'; import withCurrentReportID from '@components/withCurrentReportID'; +import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -33,8 +41,11 @@ function LHNOptionsList({ transactionViolations = {}, onFirstItemRendered = () => {}, }: LHNOptionsListProps) { + const theme = useTheme(); const styles = useThemeStyles(); const {canUseViolations} = usePermissions(); + const {translate} = useLocalize(); + const {isSmallScreenWidth} = useWindowDimensions(); // When the first item renders we want to call the onFirstItemRendered callback. // At this point in time we know that the list is actually displaying items. @@ -48,6 +59,40 @@ function LHNOptionsList({ onFirstItemRendered(); }, [onFirstItemRendered]); + const renderEmptyStateSubtitle = useCallback( + () => ( + + + {translate('common.emptyLHN.subtitleText1')} + + {translate('common.emptyLHN.subtitleText2')} + + {translate('common.emptyLHN.subtitleText3')} + + + ), + [theme, styles.dFlex, styles.gap1, styles.alignItemsCenter, styles.justifyContentCenter, styles.textAlignCenter, translate], + ); + /** * Function which renders a row in the list */ @@ -125,6 +170,19 @@ function LHNOptionsList({ estimatedItemSize={optionMode === CONST.OPTION_MODE.COMPACT ? variables.optionRowHeightCompact : variables.optionRowHeight} extraData={[currentReportID]} showsVerticalScrollIndicator={false} + ListEmptyComponent={ + isSmallScreenWidth ? ( + + + + ) : null + } /> ); diff --git a/src/languages/en.ts b/src/languages/en.ts index 4d7041d4a791..1fbc9ac0e198 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -312,6 +312,12 @@ export default { update: 'Update', member: 'Member', role: 'Role', + emptyLHN: { + title: 'Woohoo! All caught up.', + subtitleText1: 'Find a chat using the', + subtitleText2: 'button above, or create something using the', + subtitleText3: 'button below.', + }, }, location: { useCurrent: 'Use current location', diff --git a/src/languages/es.ts b/src/languages/es.ts index c9ff087d0de7..d42d0aa1faf2 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -302,6 +302,12 @@ export default { update: 'Actualizar', member: 'Miembro', role: 'Role', + emptyLHN: { + title: 'Woohoo! Todo al día.', + subtitleText1: 'Encuentra un chat usando el botón', + subtitleText2: 'o crea algo usando el botón', + subtitleText3: '.', + }, }, location: { useCurrent: 'Usar ubicación actual', diff --git a/src/styles/index.ts b/src/styles/index.ts index 32392d62e5c4..3bce9d90c8ea 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3166,6 +3166,15 @@ const styles = (theme: ThemeColors) => alignItems: 'center', }, + emptyLHNAnimation: { + width: 180, + height: 180, + }, + + emptyLHNBlockingView: { + marginTop: 120, + }, + locationErrorLinkText: { textAlignVertical: 'center', fontSize: variables.fontSizeLabel, diff --git a/src/styles/variables.ts b/src/styles/variables.ts index f7c9bd055041..2f8ecac14c32 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -121,6 +121,8 @@ export default { avatarChatSpacing: 12, chatInputSpacing: 52, // 40 + avatarChatSpacing borderTopWidth: 1, + emptyLHNIconWidth: 24, // iconSizeSmall + 4*2 horizontal margin + emptyLHNIconHeight: 16, emptyWorkspaceIconWidth: 84, emptyWorkspaceIconHeight: 84, modalTopIconWidth: 200, From ec0cc2775357d90870636edc2bee226ba3c86eeb Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 28 Feb 2024 14:17:01 +0700 Subject: [PATCH 010/102] middle align UI --- src/components/BlockingViews/BlockingView.tsx | 6 ++++ .../LHNOptionsList/LHNOptionsList.tsx | 30 +++++++++---------- src/styles/index.ts | 7 +++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index f83deaf1477c..afdc2d547d07 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import type {CSSProperties} from 'react'; import type {ImageSourcePropType, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; @@ -67,6 +68,8 @@ type BlockingViewProps = RequiredIllustrationProps & { /** Style for the animation */ animationStyles?: StyleProp; + animationWebStyle?: CSSProperties; + /** Render custom subtitle */ renderSubtitle?: () => React.ReactElement; }; @@ -84,6 +87,7 @@ function BlockingView({ onLinkPress = () => Navigation.dismissModal(), shouldEmbedLinkWithSubtitle = false, animationStyles = [], + animationWebStyle = {}, renderSubtitle, }: BlockingViewProps) { const styles = useThemeStyles(); @@ -112,8 +116,10 @@ function BlockingView({ {animation && ( )} {icon && ( diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 18832440082b..b032d5f0ccd5 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -45,7 +45,7 @@ function LHNOptionsList({ const styles = useThemeStyles(); const {canUseViolations} = usePermissions(); const {translate} = useLocalize(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isExtraSmallScreenHeight, isSmallScreenWidth} = useWindowDimensions(); // When the first item renders we want to call the onFirstItemRendered callback. // At this point in time we know that the list is actually displaying items. @@ -90,7 +90,7 @@ function LHNOptionsList({ ), - [theme, styles.dFlex, styles.gap1, styles.alignItemsCenter, styles.justifyContentCenter, styles.textAlignCenter, translate], + [theme, styles.alignItemsCenter, styles.textAlignCenter, translate], ); /** @@ -157,6 +157,19 @@ function LHNOptionsList({ ], ); + if (isSmallScreenWidth && data.length === 0) { + return ( + + ); + } + return ( - - - ) : null - } /> ); diff --git a/src/styles/index.ts b/src/styles/index.ts index 3bce9d90c8ea..a0de88de3cf3 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3171,9 +3171,10 @@ const styles = (theme: ThemeColors) => height: 180, }, - emptyLHNBlockingView: { - marginTop: 120, - }, + emptyLHNAnimationWeb: (isExtraSmallScreenHeight: boolean) => ({ + width: isExtraSmallScreenHeight ? 160 : 180, + height: isExtraSmallScreenHeight ? 160 : 180, + }), locationErrorLinkText: { textAlignVertical: 'center', From 0dbec9ef30fdf08d2af0fa10b48a1f1130be58da Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 28 Feb 2024 14:57:01 +0700 Subject: [PATCH 011/102] fix nested teneray operation --- src/components/BlockingViews/BlockingView.tsx | 28 +++++++++++-------- .../LHNOptionsList/LHNOptionsList.tsx | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index afdc2d547d07..05ffbd6a0d58 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import type {CSSProperties} from 'react'; -import type {ImageSourcePropType, StyleProp, ViewStyle} from 'react-native'; +import type {ImageSourcePropType, StyleProp, ViewStyle, WebStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; import AutoEmailLink from '@components/AutoEmailLink'; @@ -68,10 +67,10 @@ type BlockingViewProps = RequiredIllustrationProps & { /** Style for the animation */ animationStyles?: StyleProp; - animationWebStyle?: CSSProperties; + animationWebStyle?: WebStyle; /** Render custom subtitle */ - renderSubtitle?: () => React.ReactElement; + renderCustomSubtitle?: () => React.ReactElement; }; function BlockingView({ @@ -88,7 +87,7 @@ function BlockingView({ shouldEmbedLinkWithSubtitle = false, animationStyles = [], animationWebStyle = {}, - renderSubtitle, + renderCustomSubtitle, }: BlockingViewProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -111,6 +110,17 @@ function BlockingView({ ); } + function renderSubtitle() { + if (renderCustomSubtitle) { + return renderCustomSubtitle(); + } + return shouldEmbedLinkWithSubtitle ? ( + {renderContent()} + ) : ( + {renderContent()} + ); + } + return ( {animation && ( @@ -133,13 +143,7 @@ function BlockingView({ {title} - {renderSubtitle ? ( - renderSubtitle() - ) : shouldEmbedLinkWithSubtitle ? ( - {renderContent()} - ) : ( - {renderContent()} - )} + {renderSubtitle()} ); diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index b032d5f0ccd5..40c79c45946c 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -165,7 +165,7 @@ function LHNOptionsList({ animationWebStyle={styles.emptyLHNAnimationWeb(isExtraSmallScreenHeight)} title={translate('common.emptyLHN.title')} shouldShowLink={false} - renderSubtitle={renderEmptyStateSubtitle} + renderCustomSubtitle={renderEmptyStateSubtitle} /> ); } From d824c5a0f93facf39c70dc3ac925cfca2bc23310 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 28 Feb 2024 16:25:36 +0700 Subject: [PATCH 012/102] remove storybook warning --- .storybook/webpack.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 204f70344b18..89f7699465bf 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -37,6 +37,12 @@ module.exports = ({config}) => { config.plugins[definePluginIndex].definitions.__REACT_WEB_CONFIG__ = JSON.stringify(env); config.resolve.extensions = custom.resolve.extensions; + config.stats = { + // We can ignore the "module not installed" warning from lottie-react-native + // because we are not using the library for JSON format of Lottie animations. + warningsFilter: ['../node_modules/lottie-react-native/lib/module/LottieView/index.web.js'], + }; + const babelRulesIndex = _.findIndex(custom.module.rules, (rule) => rule.loader === 'babel-loader'); const babelRule = custom.module.rules[babelRulesIndex]; config.module.rules.push(babelRule); From 2197773a853b801bdabd3cccbb3d3ada812b629d Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 4 Mar 2024 22:15:19 +0700 Subject: [PATCH 013/102] middle align the ui --- .../LHNOptionsList/LHNOptionsList.tsx | 51 +++++++++---------- src/libs/SidebarUtils.ts | 8 --- src/styles/index.ts | 4 ++ 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 40c79c45946c..37354571c2ae 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -46,6 +46,7 @@ function LHNOptionsList({ const {canUseViolations} = usePermissions(); const {translate} = useLocalize(); const {isExtraSmallScreenHeight, isSmallScreenWidth} = useWindowDimensions(); + const shouldShowEmptyUI = isSmallScreenWidth && data.length === 0; // When the first item renders we want to call the onFirstItemRendered callback. // At this point in time we know that the list is actually displaying items. @@ -157,33 +158,31 @@ function LHNOptionsList({ ], ); - if (isSmallScreenWidth && data.length === 0) { - return ( - - ); - } - return ( - - + + {shouldShowEmptyUI ? ( + + ) : ( + + )} ); } diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index a9cbefddec94..9f6767406c36 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -96,14 +96,6 @@ function getOrderedReportIDs( }); }); - if (reportsToDisplay.length === 0) { - // Display Concierge chat report when there is no report to be displayed - const conciergeChatReport = allReportsDictValues.find(ReportUtils.isConciergeChatReport); - if (conciergeChatReport) { - reportsToDisplay.push(conciergeChatReport); - } - } - // The LHN is split into four distinct groups, and each group is sorted a little differently. The groups will ALWAYS be in this order: // 1. Pinned/GBR - Always sorted by reportDisplayName // 2. Drafts - Always sorted by reportDisplayName diff --git a/src/styles/index.ts b/src/styles/index.ts index 5a6266759331..68f9772c6158 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3186,6 +3186,10 @@ const styles = (theme: ThemeColors) => alignItems: 'center', }, + emptyLHNWrapper: { + marginBottom: variables.bottomTabHeight, + }, + emptyLHNAnimation: { width: 180, height: 180, From 9e55810c4787ff1afd70655a835cf62feb7f1f34 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 7 Mar 2024 18:19:12 +0700 Subject: [PATCH 014/102] resolve feedbacks --- .storybook/webpack.config.js | 6 ------ src/components/LHNOptionsList/LHNOptionsList.tsx | 10 +++++----- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 89f7699465bf..204f70344b18 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -37,12 +37,6 @@ module.exports = ({config}) => { config.plugins[definePluginIndex].definitions.__REACT_WEB_CONFIG__ = JSON.stringify(env); config.resolve.extensions = custom.resolve.extensions; - config.stats = { - // We can ignore the "module not installed" warning from lottie-react-native - // because we are not using the library for JSON format of Lottie animations. - warningsFilter: ['../node_modules/lottie-react-native/lib/module/LottieView/index.web.js'], - }; - const babelRulesIndex = _.findIndex(custom.module.rules, (rule) => rule.loader === 'babel-loader'); const babelRule = custom.module.rules[babelRulesIndex]; config.module.rules.push(babelRule); diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 17dc4f4bfb6a..df8b1e23f0d4 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -47,7 +47,7 @@ function LHNOptionsList({ const {canUseViolations} = usePermissions(); const {translate} = useLocalize(); const {isExtraSmallScreenHeight, isSmallScreenWidth} = useWindowDimensions(); - const shouldShowEmptyUI = isSmallScreenWidth && data.length === 0; + const shouldShowEmptyLHN = isSmallScreenWidth && data.length === 0; // When the first item renders we want to call the onFirstItemRendered callback. // At this point in time we know that the list is actually displaying items. @@ -61,7 +61,7 @@ function LHNOptionsList({ onFirstItemRendered(); }, [onFirstItemRendered]); - const renderEmptyStateSubtitle = useCallback( + const renderEmptyLHNSubtitle = useCallback( () => ( - {shouldShowEmptyUI ? ( + + {shouldShowEmptyLHN ? ( ) : ( Date: Mon, 11 Mar 2024 16:56:17 +0700 Subject: [PATCH 015/102] remove custom web style --- src/components/BlockingViews/BlockingView.tsx | 1 + src/components/LHNOptionsList/LHNOptionsList.tsx | 4 ++-- src/styles/index.ts | 5 ----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index 05ffbd6a0d58..3733075c2025 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -67,6 +67,7 @@ type BlockingViewProps = RequiredIllustrationProps & { /** Style for the animation */ animationStyles?: StyleProp; + /** Style for the animation on web */ animationWebStyle?: WebStyle; /** Render custom subtitle */ diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index 1481b309949f..2005b5493202 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -44,7 +44,7 @@ function LHNOptionsList({ const styles = useThemeStyles(); const {canUseViolations} = usePermissions(); const {translate} = useLocalize(); - const {isExtraSmallScreenHeight, isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useWindowDimensions(); const shouldShowEmptyLHN = isSmallScreenWidth && data.length === 0; // When the first item renders we want to call the onFirstItemRendered callback. @@ -167,7 +167,7 @@ function LHNOptionsList({ height: 180, }, - emptyLHNAnimationWeb: (isExtraSmallScreenHeight: boolean) => ({ - width: isExtraSmallScreenHeight ? 160 : 180, - height: isExtraSmallScreenHeight ? 160 : 180, - }), - locationErrorLinkText: { textAlignVertical: 'center', fontSize: variables.fontSizeLabel, From 73dff71e03d9163de1e41d69a77f22575f715bb3 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 18 Mar 2024 19:42:55 +0700 Subject: [PATCH 016/102] merge main --- src/pages/iou/MoneyRequestCategoryPage.js | 106 ------------ src/pages/iou/MoneyRequestDatePage.js | 126 -------------- src/pages/iou/MoneyRequestDescriptionPage.js | 165 ------------------- src/pages/iou/MoneyRequestMerchantPage.js | 140 ---------------- src/pages/iou/MoneyRequestTagPage.js | 127 -------------- 5 files changed, 664 deletions(-) delete mode 100644 src/pages/iou/MoneyRequestCategoryPage.js delete mode 100644 src/pages/iou/MoneyRequestDatePage.js delete mode 100644 src/pages/iou/MoneyRequestDescriptionPage.js delete mode 100644 src/pages/iou/MoneyRequestMerchantPage.js delete mode 100644 src/pages/iou/MoneyRequestTagPage.js diff --git a/src/pages/iou/MoneyRequestCategoryPage.js b/src/pages/iou/MoneyRequestCategoryPage.js deleted file mode 100644 index b3ca0a5d7ae0..000000000000 --- a/src/pages/iou/MoneyRequestCategoryPage.js +++ /dev/null @@ -1,106 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import CategoryPicker from '@components/CategoryPicker'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Text from '@components/Text'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as IOU from '@userActions/IOU'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen via route :iouType/new/category/:reportID? */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - }).isRequired, - - /* Onyx Props */ - /** The report currently being used */ - report: reportPropTypes, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, -}; - -const defaultProps = { - report: {}, - iou: iouDefaultProps, -}; - -function MoneyRequestCategoryPage({route, report, iou}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - - const reportID = lodashGet(route, 'params.reportID', ''); - const iouType = lodashGet(route, 'params.iouType', ''); - - const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); - }; - - const updateCategory = (category) => { - if (category.searchText === iou.category) { - IOU.resetMoneyRequestCategory(); - } else { - IOU.setMoneyRequestCategory(category.searchText); - } - - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); - }; - - return ( - - - {translate('iou.categorySelection')} - - - ); -} - -MoneyRequestCategoryPage.displayName = 'MoneyRequestCategoryPage'; -MoneyRequestCategoryPage.propTypes = propTypes; -MoneyRequestCategoryPage.defaultProps = defaultProps; - -export default compose( - withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - report: { - key: ({route, iou}) => { - const reportID = IOU.getIOUReportID(iou, route); - - return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - }, - }, - }), -)(MoneyRequestCategoryPage); diff --git a/src/pages/iou/MoneyRequestDatePage.js b/src/pages/iou/MoneyRequestDatePage.js deleted file mode 100644 index c99c07a80624..000000000000 --- a/src/pages/iou/MoneyRequestDatePage.js +++ /dev/null @@ -1,126 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useEffect} from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import DatePicker from '@components/DatePicker'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; -import Navigation from '@libs/Navigation/Navigation'; -import * as IOU from '@userActions/IOU'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, - - /** Route from navigation */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - - /** Which field we are editing */ - field: PropTypes.string, - - /** reportID for the "transaction thread" */ - threadReportID: PropTypes.string, - }), - }).isRequired, - - /** The current tab we have navigated to in the request modal. String that corresponds to the request type. */ - selectedTab: PropTypes.oneOf(_.values(CONST.TAB_REQUEST)).isRequired, -}; - -const defaultProps = { - iou: iouDefaultProps, -}; - -function MoneyRequestDatePage({iou, route, selectedTab}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const iouType = lodashGet(route, 'params.iouType', ''); - const reportID = lodashGet(route, 'params.reportID', ''); - const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType, selectedTab); - - useEffect(() => { - const moneyRequestId = `${iouType}${reportID}`; - const shouldReset = iou.id !== moneyRequestId; - if (shouldReset) { - IOU.resetMoneyRequestInfo(moneyRequestId); - } - - if (!isDistanceRequest && (_.isEmpty(iou.participants) || (iou.amount === 0 && !iou.receiptPath) || shouldReset)) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - }, [iou.id, iou.participants, iou.amount, iou.receiptPath, iouType, reportID, isDistanceRequest]); - - function navigateBack() { - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); - } - - /** - * Sets the money request comment by saving it to Onyx. - * - * @param {Object} value - * @param {String} value.moneyRequestCreated - */ - function updateDate(value) { - IOU.setMoneyRequestCreated(value.moneyRequestCreated); - navigateBack(); - } - - return ( - - navigateBack()} - /> - updateDate(value)} - submitButtonText={translate('common.save')} - enabledWhenOffline - > - - - - ); -} - -MoneyRequestDatePage.propTypes = propTypes; -MoneyRequestDatePage.defaultProps = defaultProps; -MoneyRequestDatePage.displayName = 'MoneyRequestDatePage'; - -export default withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - selectedTab: { - key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`, - }, -})(MoneyRequestDatePage); diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js deleted file mode 100644 index a2209818ee1a..000000000000 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ /dev/null @@ -1,165 +0,0 @@ -import {useFocusEffect} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useRef} from 'react'; -import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapperWithRef from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import TextInput from '@components/TextInput'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import * as IOU from '@libs/actions/IOU'; -import * as Browser from '@libs/Browser'; -import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; -import Navigation from '@libs/Navigation/Navigation'; -import updateMultilineInputRange from '@libs/updateMultilineInputRange'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, - - /** Route from navigation */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - - /** Which field we are editing */ - field: PropTypes.string, - - /** reportID for the "transaction thread" */ - threadReportID: PropTypes.string, - }), - }).isRequired, - - /** The current tab we have navigated to in the request modal. String that corresponds to the request type. */ - selectedTab: PropTypes.oneOf(_.values(CONST.TAB_REQUEST)), -}; - -const defaultProps = { - iou: iouDefaultProps, - selectedTab: '', -}; - -function MoneyRequestDescriptionPage({iou, route, selectedTab}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const inputRef = useRef(null); - const focusTimeoutRef = useRef(null); - const iouType = lodashGet(route, 'params.iouType', ''); - const reportID = lodashGet(route, 'params.reportID', ''); - const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType, selectedTab); - - useFocusEffect( - useCallback(() => { - focusTimeoutRef.current = setTimeout(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - return () => { - if (!focusTimeoutRef.current) { - return; - } - clearTimeout(focusTimeoutRef.current); - }; - }, CONST.ANIMATED_TRANSITION); - }, []), - ); - - useEffect(() => { - const moneyRequestId = `${iouType}${reportID}`; - const shouldReset = iou.id !== moneyRequestId; - if (shouldReset) { - IOU.resetMoneyRequestInfo(moneyRequestId); - } - - if (!isDistanceRequest && (_.isEmpty(iou.participants) || (iou.amount === 0 && !iou.receiptPath) || shouldReset)) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - }, [iou.id, iou.participants, iou.amount, iou.receiptPath, iouType, reportID, isDistanceRequest]); - - function navigateBack() { - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); - } - - /** - * Sets the money request comment by saving it to Onyx. - * - * @param {Object} value - * @param {String} value.moneyRequestComment - */ - function updateComment(value) { - IOU.setMoneyRequestDescription(value.moneyRequestComment); - navigateBack(); - } - - return ( - - <> - navigateBack()} - /> - updateComment(value)} - submitButtonText={translate('common.save')} - enabledWhenOffline - > - - { - if (!el) { - return; - } - inputRef.current = el; - updateMultilineInputRange(inputRef.current); - }} - autoGrowHeight - containerStyles={[styles.autoGrowHeightMultilineInput]} - submitOnEnter={!Browser.isMobile()} - /> - - - - - ); -} - -MoneyRequestDescriptionPage.propTypes = propTypes; -MoneyRequestDescriptionPage.defaultProps = defaultProps; -MoneyRequestDescriptionPage.displayName = 'MoneyRequestDescriptionPage'; - -export default withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - selectedTab: { - key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`, - }, -})(MoneyRequestDescriptionPage); diff --git a/src/pages/iou/MoneyRequestMerchantPage.js b/src/pages/iou/MoneyRequestMerchantPage.js deleted file mode 100644 index 1d3fc6f19584..000000000000 --- a/src/pages/iou/MoneyRequestMerchantPage.js +++ /dev/null @@ -1,140 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect} from 'react'; -import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapperWithRef from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import TextInput from '@components/TextInput'; -import useAutoFocusInput from '@hooks/useAutoFocusInput'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; -import * as IOU from '@userActions/IOU'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import INPUT_IDS from '@src/types/form/MoneyRequestMerchantForm'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, - - /** Route from navigation */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - - /** Which field we are editing */ - field: PropTypes.string, - - /** reportID for the "transaction thread" */ - threadReportID: PropTypes.string, - }), - }).isRequired, -}; - -const defaultProps = { - iou: iouDefaultProps, -}; - -function MoneyRequestMerchantPage({iou, route}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const {inputCallbackRef} = useAutoFocusInput(); - const iouType = lodashGet(route, 'params.iouType', ''); - const reportID = lodashGet(route, 'params.reportID', ''); - const isEmptyMerchant = iou.merchant === '' || iou.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; - - useEffect(() => { - const moneyRequestId = `${iouType}${reportID}`; - const shouldReset = iou.id !== moneyRequestId; - if (shouldReset) { - IOU.resetMoneyRequestInfo(moneyRequestId); - } - - if (_.isEmpty(iou.participants) || (iou.amount === 0 && !iou.receiptPath) || shouldReset) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - }, [iou.id, iou.participants, iou.amount, iou.receiptPath, iouType, reportID]); - - function navigateBack() { - Navigation.goBack(ROUTES.MONEY_REQUEST__STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); - } - - const validate = useCallback((value) => { - const errors = {}; - - if (_.isEmpty(value.moneyRequestMerchant)) { - errors.moneyRequestMerchant = 'common.error.fieldRequired'; - } - - return errors; - }, []); - - /** - * Sets the money request comment by saving it to Onyx. - * - * @param {Object} value - * @param {String} value.moneyRequestMerchant - */ - function updateMerchant(value) { - IOU.setMoneyRequestMerchant(value.moneyRequestMerchant); - navigateBack(); - } - - return ( - - navigateBack()} - /> - updateMerchant(value)} - validate={validate} - submitButtonText={translate('common.save')} - enabledWhenOffline - > - - - - - - ); -} - -MoneyRequestMerchantPage.propTypes = propTypes; -MoneyRequestMerchantPage.defaultProps = defaultProps; -MoneyRequestMerchantPage.displayName = 'MoneyRequestMerchantPage'; - -export default withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, -})(MoneyRequestMerchantPage); diff --git a/src/pages/iou/MoneyRequestTagPage.js b/src/pages/iou/MoneyRequestTagPage.js deleted file mode 100644 index 7fd08f20d652..000000000000 --- a/src/pages/iou/MoneyRequestTagPage.js +++ /dev/null @@ -1,127 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import TagPicker from '@components/TagPicker'; -import tagPropTypes from '@components/tagPropTypes'; -import Text from '@components/Text'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import Navigation from '@libs/Navigation/Navigation'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import reportPropTypes from '@pages/reportPropTypes'; -import * as IOU from '@userActions/IOU'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import {iouDefaultProps, iouPropTypes} from './propTypes'; - -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen via route :iouType/new/tag/:reportID? */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - }).isRequired, - - /* Onyx props */ - /** The report currently being used */ - report: reportPropTypes, - - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, -}; - -const defaultProps = { - report: {}, - policyTags: {}, - iou: iouDefaultProps, -}; - -function MoneyRequestTagPage({route, report, policyTags, iou}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - - const iouType = lodashGet(route, 'params.iouType', ''); - - // Fetches the first tag list of the policy - const tagListKey = _.first(_.keys(policyTags)); - const policyTagListName = PolicyUtils.getTagListName(policyTags) || translate('common.tag'); - - const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', report.reportID)); - }; - - const updateTag = (selectedTag) => { - if (selectedTag.searchText === iou.tag) { - IOU.resetMoneyRequestTag(); - } else { - IOU.setMoneyRequestTag(selectedTag.searchText); - } - navigateBack(); - }; - - return ( - - {({insets}) => ( - <> - - {translate('iou.tagSelection', {tagName: policyTagListName})} - - - )} - - ); -} - -MoneyRequestTagPage.displayName = 'MoneyRequestTagPage'; -MoneyRequestTagPage.propTypes = propTypes; -MoneyRequestTagPage.defaultProps = defaultProps; - -export default compose( - withOnyx({ - iou: { - key: ONYXKEYS.IOU, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - report: { - key: ({route, iou}) => { - const reportID = IOU.getIOUReportID(iou, route); - - return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; - }, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - }), -)(MoneyRequestTagPage); From 26801e73a92c0e86bb9e379ab3cfe037dcb2f156 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 18 Mar 2024 19:45:19 +0700 Subject: [PATCH 017/102] merge main --- src/pages/EditRequestMerchantPage.js | 85 ---------------------------- 1 file changed, 85 deletions(-) delete mode 100644 src/pages/EditRequestMerchantPage.js diff --git a/src/pages/EditRequestMerchantPage.js b/src/pages/EditRequestMerchantPage.js deleted file mode 100644 index 33c04df39e3e..000000000000 --- a/src/pages/EditRequestMerchantPage.js +++ /dev/null @@ -1,85 +0,0 @@ -import PropTypes from 'prop-types'; -import React, {useCallback, useRef} from 'react'; -import {View} from 'react-native'; -import _ from 'underscore'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import TextInput from '@components/TextInput'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import INPUT_IDS from '@src/types/form/MoneyRequestMerchantForm'; - -const propTypes = { - /** Transaction default merchant value */ - defaultMerchant: PropTypes.string.isRequired, - - /** Callback to fire when the Save button is pressed */ - onSubmit: PropTypes.func.isRequired, - - /** Boolean to enable validation */ - isPolicyExpenseChat: PropTypes.bool, -}; - -const defaultProps = { - isPolicyExpenseChat: false, -}; - -function EditRequestMerchantPage({defaultMerchant, onSubmit, isPolicyExpenseChat}) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const merchantInputRef = useRef(null); - const isEmptyMerchant = defaultMerchant === '' || defaultMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; - - const validate = useCallback( - (value) => { - const errors = {}; - if (_.isEmpty(value.merchant) && value.merchant.trim() === '' && isPolicyExpenseChat) { - errors.merchant = 'common.error.fieldRequired'; - } - return errors; - }, - [isPolicyExpenseChat], - ); - - return ( - merchantInputRef.current && merchantInputRef.current.focus()} - testID={EditRequestMerchantPage.displayName} - > - - - - (merchantInputRef.current = e)} - /> - - - - ); -} - -EditRequestMerchantPage.propTypes = propTypes; -EditRequestMerchantPage.defaultProps = defaultProps; -EditRequestMerchantPage.displayName = 'EditRequestMerchantPage'; - -export default EditRequestMerchantPage; From 0abc91308b5bd675562a1689bfa795e904b9e5be Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 18 Mar 2024 19:49:33 +0700 Subject: [PATCH 018/102] merge main --- src/libs/Navigation/linkingConfig.ts | 506 --------------------------- 1 file changed, 506 deletions(-) delete mode 100644 src/libs/Navigation/linkingConfig.ts diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts deleted file mode 100644 index d4e04d5402e2..000000000000 --- a/src/libs/Navigation/linkingConfig.ts +++ /dev/null @@ -1,506 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import type {LinkingOptions} from '@react-navigation/native'; -import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import type {RootStackParamList} from './types'; - -const linkingConfig: LinkingOptions = { - prefixes: [ - 'app://-/', - 'new-expensify://', - 'https://www.expensify.cash', - 'https://staging.expensify.cash', - 'https://dev.new.expensify.com', - CONST.NEW_EXPENSIFY_URL, - CONST.STAGING_NEW_EXPENSIFY_URL, - ], - config: { - initialRouteName: SCREENS.HOME, - screens: { - // Main Routes - [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, - [SCREENS.UNLINK_LOGIN]: ROUTES.UNLINK_LOGIN, - [SCREENS.TRANSITION_BETWEEN_APPS]: ROUTES.TRANSITION_BETWEEN_APPS, - [SCREENS.CONCIERGE]: ROUTES.CONCIERGE, - [SCREENS.SIGN_IN_WITH_APPLE_DESKTOP]: ROUTES.APPLE_SIGN_IN, - [SCREENS.SIGN_IN_WITH_GOOGLE_DESKTOP]: ROUTES.GOOGLE_SIGN_IN, - [SCREENS.SAML_SIGN_IN]: ROUTES.SAML_SIGN_IN, - [SCREENS.DESKTOP_SIGN_IN_REDIRECT]: ROUTES.DESKTOP_SIGN_IN_REDIRECT, - [SCREENS.REPORT_ATTACHMENTS]: ROUTES.REPORT_ATTACHMENTS.route, - [SCREENS.PROFILE_AVATAR]: ROUTES.PROFILE_AVATAR.route, - [SCREENS.WORKSPACE_AVATAR]: ROUTES.WORKSPACE_AVATAR.route, - [SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route, - - // Sidebar - [SCREENS.HOME]: { - path: ROUTES.HOME, - }, - - [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: { - screens: { - [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, - }, - }, - [SCREENS.NOT_FOUND]: '*', - [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: { - screens: { - [SCREENS.LEFT_MODAL.SEARCH]: { - screens: { - [SCREENS.SEARCH_ROOT]: ROUTES.SEARCH, - }, - }, - }, - }, - [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: { - screens: { - [SCREENS.RIGHT_MODAL.SETTINGS]: { - screens: { - [SCREENS.SETTINGS.ROOT]: { - path: ROUTES.SETTINGS, - }, - [SCREENS.SETTINGS.WORKSPACES]: { - path: ROUTES.SETTINGS_WORKSPACES, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES.ROOT]: { - path: ROUTES.SETTINGS_PREFERENCES, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: { - path: ROUTES.SETTINGS_PRIORITY_MODE, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES.LANGUAGE]: { - path: ROUTES.SETTINGS_LANGUAGE, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES.THEME]: { - path: ROUTES.SETTINGS_THEME, - exact: true, - }, - [SCREENS.SETTINGS.CLOSE]: { - path: ROUTES.SETTINGS_CLOSE, - exact: true, - }, - [SCREENS.SETTINGS.SECURITY]: { - path: ROUTES.SETTINGS_SECURITY, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.ROOT]: { - path: ROUTES.SETTINGS_WALLET, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: { - path: ROUTES.SETTINGS_WALLET_DOMAINCARD.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD]: { - path: ROUTES.SETTINGS_REPORT_FRAUD.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME]: { - path: ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_NAME.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE]: { - path: ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_PHONE.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.ADDRESS]: { - path: ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_ADDRESS.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.CONFIRM]: { - path: ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_CONFIRM.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: { - path: ROUTES.SETTINGS_ENABLE_PAYMENTS, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE]: { - path: ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT]: { - path: ROUTES.SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT, - exact: true, - }, - [SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: { - path: ROUTES.SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CARD_ACTIVATE]: { - path: ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.route, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: { - path: ROUTES.SETTINGS_WALLET_CARD_DIGITAL_DETAILS_UPDATE_ADDRESS.route, - exact: true, - }, - [SCREENS.SETTINGS.ADD_DEBIT_CARD]: { - path: ROUTES.SETTINGS_ADD_DEBIT_CARD, - exact: true, - }, - [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: { - path: ROUTES.SETTINGS_ADD_BANK_ACCOUNT, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.ROOT]: { - path: ROUTES.SETTINGS_PROFILE, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.PRONOUNS]: { - path: ROUTES.SETTINGS_PRONOUNS, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.DISPLAY_NAME]: { - path: ROUTES.SETTINGS_DISPLAY_NAME, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.TIMEZONE]: { - path: ROUTES.SETTINGS_TIMEZONE, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT]: { - path: ROUTES.SETTINGS_TIMEZONE_SELECT, - exact: true, - }, - [SCREENS.SETTINGS.ABOUT]: { - path: ROUTES.SETTINGS_ABOUT, - exact: true, - }, - [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS]: { - path: ROUTES.SETTINGS_APP_DOWNLOAD_LINKS, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.CONTACT_METHODS]: { - path: ROUTES.SETTINGS_CONTACT_METHODS.route, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS]: { - path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.route, - }, - [SCREENS.SETTINGS.LOUNGE_ACCESS]: { - path: ROUTES.SETTINGS_LOUNGE_ACCESS, - }, - [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: { - path: ROUTES.SETTINGS_NEW_CONTACT_METHOD.route, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.PERSONAL_DETAILS.INITIAL]: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.PERSONAL_DETAILS.LEGAL_NAME]: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_LEGAL_NAME, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.PERSONAL_DETAILS.DATE_OF_BIRTH]: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.PERSONAL_DETAILS.ADDRESS]: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.PERSONAL_DETAILS.ADDRESS_COUNTRY]: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY.route, - exact: true, - }, - [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: { - path: ROUTES.SETTINGS_2FA.route, - exact: true, - }, - [SCREENS.SETTINGS.SHARE_CODE]: { - path: ROUTES.SETTINGS_SHARE_CODE, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.STATUS]: { - path: ROUTES.SETTINGS_STATUS, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER]: { - path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER, - }, - [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE]: { - path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_DATE, - }, - [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME]: { - path: ROUTES.SETTINGS_STATUS_CLEAR_AFTER_TIME, - }, - [SCREENS.WORKSPACE.INITIAL]: { - path: ROUTES.WORKSPACE_INITIAL.route, - }, - [SCREENS.WORKSPACE.SETTINGS]: { - path: ROUTES.WORKSPACE_SETTINGS.route, - }, - [SCREENS.WORKSPACE.CURRENCY]: { - path: ROUTES.WORKSPACE_SETTINGS_CURRENCY.route, - }, - [SCREENS.WORKSPACE.CARD]: { - path: ROUTES.WORKSPACE_CARD.route, - }, - [SCREENS.WORKSPACE.REIMBURSE]: { - path: ROUTES.WORKSPACE_REIMBURSE.route, - }, - [SCREENS.WORKSPACE.RATE_AND_UNIT]: { - path: ROUTES.WORKSPACE_RATE_AND_UNIT.route, - }, - [SCREENS.WORKSPACE.BILLS]: { - path: ROUTES.WORKSPACE_BILLS.route, - }, - [SCREENS.WORKSPACE.INVOICES]: { - path: ROUTES.WORKSPACE_INVOICES.route, - }, - [SCREENS.WORKSPACE.TRAVEL]: { - path: ROUTES.WORKSPACE_TRAVEL.route, - }, - [SCREENS.WORKSPACE.MEMBERS]: { - path: ROUTES.WORKSPACE_MEMBERS.route, - }, - [SCREENS.WORKSPACE.INVITE]: { - path: ROUTES.WORKSPACE_INVITE.route, - }, - [SCREENS.WORKSPACE.INVITE_MESSAGE]: { - path: ROUTES.WORKSPACE_INVITE_MESSAGE.route, - }, - [SCREENS.REIMBURSEMENT_ACCOUNT]: { - path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, - exact: true, - }, - [SCREENS.GET_ASSISTANCE]: { - path: ROUTES.GET_ASSISTANCE.route, - }, - [SCREENS.KEYBOARD_SHORTCUTS]: { - path: ROUTES.KEYBOARD_SHORTCUTS, - }, - }, - }, - [SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: { - screens: { - [SCREENS.PRIVATE_NOTES.LIST]: ROUTES.PRIVATE_NOTES_LIST.route, - [SCREENS.PRIVATE_NOTES.EDIT]: ROUTES.PRIVATE_NOTES_EDIT.route, - }, - }, - [SCREENS.RIGHT_MODAL.REPORT_DETAILS]: { - screens: { - [SCREENS.REPORT_DETAILS.ROOT]: ROUTES.REPORT_WITH_ID_DETAILS.route, - [SCREENS.REPORT_DETAILS.SHARE_CODE]: ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.route, - }, - }, - [SCREENS.RIGHT_MODAL.REPORT_SETTINGS]: { - screens: { - [SCREENS.REPORT_SETTINGS.ROOT]: { - path: ROUTES.REPORT_SETTINGS.route, - }, - [SCREENS.REPORT_SETTINGS.ROOM_NAME]: { - path: ROUTES.REPORT_SETTINGS_ROOM_NAME.route, - }, - [SCREENS.REPORT_SETTINGS.NOTIFICATION_PREFERENCES]: { - path: ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.route, - }, - [SCREENS.REPORT_SETTINGS.WRITE_CAPABILITY]: { - path: ROUTES.REPORT_SETTINGS_WRITE_CAPABILITY.route, - }, - }, - }, - [SCREENS.RIGHT_MODAL.REPORT_WELCOME_MESSAGE]: { - screens: { - [SCREENS.REPORT_WELCOME_MESSAGE_ROOT]: ROUTES.REPORT_WELCOME_MESSAGE.route, - }, - }, - [SCREENS.RIGHT_MODAL.NEW_CHAT]: { - screens: { - [SCREENS.NEW_CHAT.ROOT]: { - path: ROUTES.NEW, - exact: true, - screens: { - [SCREENS.NEW_CHAT.NEW_CHAT]: { - path: ROUTES.NEW_CHAT, - exact: true, - }, - [SCREENS.NEW_CHAT.NEW_ROOM]: { - path: ROUTES.NEW_ROOM, - exact: true, - }, - }, - }, - }, - }, - [SCREENS.RIGHT_MODAL.NEW_TASK]: { - screens: { - [SCREENS.NEW_TASK.ROOT]: ROUTES.NEW_TASK, - [SCREENS.NEW_TASK.TASK_ASSIGNEE_SELECTOR]: ROUTES.NEW_TASK_ASSIGNEE, - [SCREENS.NEW_TASK.TASK_SHARE_DESTINATION_SELECTOR]: ROUTES.NEW_TASK_SHARE_DESTINATION, - [SCREENS.NEW_TASK.DETAILS]: ROUTES.NEW_TASK_DETAILS, - [SCREENS.NEW_TASK.TITLE]: ROUTES.NEW_TASK_TITLE, - [SCREENS.NEW_TASK.DESCRIPTION]: ROUTES.NEW_TASK_DESCRIPTION, - }, - }, - [SCREENS.RIGHT_MODAL.TEACHERS_UNITE]: { - screens: { - [SCREENS.SAVE_THE_WORLD.ROOT]: ROUTES.TEACHERS_UNITE, - [SCREENS.I_KNOW_A_TEACHER]: ROUTES.I_KNOW_A_TEACHER, - [SCREENS.INTRO_SCHOOL_PRINCIPAL]: ROUTES.INTRO_SCHOOL_PRINCIPAL, - [SCREENS.I_AM_A_TEACHER]: ROUTES.I_AM_A_TEACHER, - }, - }, - [SCREENS.RIGHT_MODAL.DETAILS]: { - screens: { - [SCREENS.DETAILS_ROOT]: ROUTES.DETAILS.route, - }, - }, - [SCREENS.RIGHT_MODAL.PROFILE]: { - screens: { - [SCREENS.PROFILE_ROOT]: ROUTES.PROFILE.route, - }, - }, - [SCREENS.RIGHT_MODAL.PARTICIPANTS]: { - screens: { - [SCREENS.REPORT_PARTICIPANTS_ROOT]: ROUTES.REPORT_PARTICIPANTS.route, - }, - }, - [SCREENS.RIGHT_MODAL.ROOM_INVITE]: { - screens: { - [SCREENS.ROOM_INVITE_ROOT]: ROUTES.ROOM_INVITE.route, - }, - }, - [SCREENS.RIGHT_MODAL.ROOM_MEMBERS]: { - screens: { - [SCREENS.ROOM_MEMBERS_ROOT]: ROUTES.ROOM_MEMBERS.route, - }, - }, - [SCREENS.RIGHT_MODAL.MONEY_REQUEST]: { - screens: { - [SCREENS.MONEY_REQUEST.START]: ROUTES.MONEY_REQUEST_START.route, - [SCREENS.MONEY_REQUEST.CREATE]: { - path: ROUTES.MONEY_REQUEST_CREATE.route, - exact: true, - screens: { - distance: { - path: ROUTES.MONEY_REQUEST_CREATE_TAB_DISTANCE.route, - exact: true, - }, - manual: { - path: ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL.route, - exact: true, - }, - scan: { - path: ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.route, - exact: true, - }, - }, - }, - [SCREENS.MONEY_REQUEST.STEP_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_AMOUNT.route, - [SCREENS.MONEY_REQUEST.STEP_CATEGORY]: ROUTES.MONEY_REQUEST_STEP_CATEGORY.route, - [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.route, - [SCREENS.MONEY_REQUEST.STEP_CURRENCY]: ROUTES.MONEY_REQUEST_STEP_CURRENCY.route, - [SCREENS.MONEY_REQUEST.STEP_DATE]: ROUTES.MONEY_REQUEST_STEP_DATE.route, - [SCREENS.MONEY_REQUEST.STEP_DESCRIPTION]: ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.route, - [SCREENS.MONEY_REQUEST.STEP_DISTANCE]: ROUTES.MONEY_REQUEST_STEP_DISTANCE.route, - [SCREENS.MONEY_REQUEST.STEP_MERCHANT]: ROUTES.MONEY_REQUEST_STEP_MERCHANT.route, - [SCREENS.MONEY_REQUEST.STEP_PARTICIPANTS]: ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.route, - [SCREENS.MONEY_REQUEST.STEP_SCAN]: ROUTES.MONEY_REQUEST_STEP_SCAN.route, - [SCREENS.MONEY_REQUEST.STEP_TAG]: ROUTES.MONEY_REQUEST_STEP_TAG.route, - [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: ROUTES.MONEY_REQUEST_STEP_WAYPOINT.route, - [SCREENS.MONEY_REQUEST.ROOT]: { - path: ROUTES.MONEY_REQUEST.route, - exact: true, - screens: { - [SCREENS.MONEY_REQUEST.MANUAL_TAB]: { - path: ROUTES.MONEY_REQUEST_MANUAL_TAB, - exact: true, - }, - [SCREENS.MONEY_REQUEST.SCAN_TAB]: { - path: ROUTES.MONEY_REQUEST_SCAN_TAB, - exact: true, - }, - [SCREENS.MONEY_REQUEST.DISTANCE_TAB]: { - path: ROUTES.MONEY_REQUEST_DISTANCE_TAB.route, - exact: true, - }, - }, - }, - [SCREENS.MONEY_REQUEST.AMOUNT]: ROUTES.MONEY_REQUEST_AMOUNT.route, - [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.route, - [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: ROUTES.MONEY_REQUEST_STEP_TAX_RATE.route, - [SCREENS.MONEY_REQUEST.PARTICIPANTS]: ROUTES.MONEY_REQUEST_PARTICIPANTS.route, - [SCREENS.MONEY_REQUEST.DATE]: ROUTES.MONEY_REQUEST_DATE.route, - [SCREENS.MONEY_REQUEST.CURRENCY]: ROUTES.MONEY_REQUEST_CURRENCY.route, - [SCREENS.MONEY_REQUEST.DESCRIPTION]: ROUTES.MONEY_REQUEST_DESCRIPTION.route, - [SCREENS.MONEY_REQUEST.CATEGORY]: ROUTES.MONEY_REQUEST_CATEGORY.route, - [SCREENS.MONEY_REQUEST.TAG]: ROUTES.MONEY_REQUEST_TAG.route, - [SCREENS.MONEY_REQUEST.MERCHANT]: ROUTES.MONEY_REQUEST_MERCHANT.route, - [SCREENS.MONEY_REQUEST.RECEIPT]: ROUTES.MONEY_REQUEST_RECEIPT.route, - [SCREENS.MONEY_REQUEST.DISTANCE]: ROUTES.MONEY_REQUEST_DISTANCE.route, - [SCREENS.IOU_SEND.ENABLE_PAYMENTS]: ROUTES.IOU_SEND_ENABLE_PAYMENTS, - [SCREENS.IOU_SEND.ADD_BANK_ACCOUNT]: ROUTES.IOU_SEND_ADD_BANK_ACCOUNT, - [SCREENS.IOU_SEND.ADD_DEBIT_CARD]: ROUTES.IOU_SEND_ADD_DEBIT_CARD, - }, - }, - [SCREENS.RIGHT_MODAL.SPLIT_DETAILS]: { - screens: { - [SCREENS.SPLIT_DETAILS.ROOT]: ROUTES.SPLIT_BILL_DETAILS.route, - [SCREENS.SPLIT_DETAILS.EDIT_REQUEST]: ROUTES.EDIT_SPLIT_BILL.route, - [SCREENS.SPLIT_DETAILS.EDIT_CURRENCY]: ROUTES.EDIT_SPLIT_BILL_CURRENCY.route, - }, - }, - [SCREENS.RIGHT_MODAL.TASK_DETAILS]: { - screens: { - [SCREENS.TASK.TITLE]: ROUTES.TASK_TITLE.route, - [SCREENS.TASK.DESCRIPTION]: ROUTES.TASK_DESCRIPTION.route, - [SCREENS.TASK.ASSIGNEE]: ROUTES.TASK_ASSIGNEE.route, - }, - }, - [SCREENS.RIGHT_MODAL.ADD_PERSONAL_BANK_ACCOUNT]: { - screens: { - [SCREENS.ADD_PERSONAL_BANK_ACCOUNT_ROOT]: ROUTES.BANK_ACCOUNT_PERSONAL, - }, - }, - [SCREENS.RIGHT_MODAL.ENABLE_PAYMENTS]: { - screens: { - [SCREENS.ENABLE_PAYMENTS_ROOT]: ROUTES.ENABLE_PAYMENTS, - }, - }, - [SCREENS.RIGHT_MODAL.WALLET_STATEMENT]: { - screens: { - [SCREENS.WALLET_STATEMENT_ROOT]: ROUTES.WALLET_STATEMENT_WITH_DATE, - }, - }, - [SCREENS.RIGHT_MODAL.FLAG_COMMENT]: { - screens: { - [SCREENS.FLAG_COMMENT_ROOT]: ROUTES.FLAG_COMMENT.route, - }, - }, - [SCREENS.RIGHT_MODAL.EDIT_REQUEST]: { - screens: { - [SCREENS.EDIT_REQUEST.ROOT]: ROUTES.EDIT_REQUEST.route, - [SCREENS.EDIT_REQUEST.CURRENCY]: ROUTES.EDIT_CURRENCY_REQUEST.route, - [SCREENS.EDIT_REQUEST.REPORT_FIELD]: ROUTES.EDIT_REPORT_FIELD_REQUEST.route, - }, - }, - [SCREENS.RIGHT_MODAL.SIGN_IN]: { - screens: { - [SCREENS.SIGN_IN_ROOT]: ROUTES.SIGN_IN_MODAL, - }, - }, - [SCREENS.RIGHT_MODAL.REFERRAL]: { - screens: { - [SCREENS.REFERRAL_DETAILS]: ROUTES.REFERRAL_DETAILS_MODAL.route, - }, - }, - ProcessMoneyRequestHold: { - screens: { - ProcessMoneyRequestHold_Root: ROUTES.PROCESS_MONEY_REQUEST_HOLD, - }, - }, - }, - }, - }, - }, -}; - -export default linkingConfig; From 544ee16a55777002c039028f5a6b8a6816a0ef2c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Mar 2024 17:20:25 +0100 Subject: [PATCH 019/102] Add getPolicyIDFromNavigationState method --- src/libs/Navigation/Navigation.ts | 11 ++++++++++- .../home/sidebar/SidebarScreen/BaseSidebarScreen.js | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c55145a5d580..099996d7393a 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -13,13 +13,14 @@ import type {Report} from '@src/types/onyx'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import originalDismissModal from './dismissModal'; import originalDismissModalWithReport from './dismissModalWithReport'; +import getPolicyIDFromState from './getPolicyIDFromState'; import originalGetTopmostReportActionId from './getTopmostReportActionID'; import originalGetTopmostReportId from './getTopmostReportId'; import linkingConfig from './linkingConfig'; import linkTo from './linkTo'; import navigationRef from './navigationRef'; import switchPolicyID from './switchPolicyID'; -import type {NavigationStateRoute, State, StateOrRoute, SwitchPolicyIDParams} from './types'; +import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute, SwitchPolicyIDParams} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -359,6 +360,13 @@ function navigateWithSwitchPolicyID(params: SwitchPolicyIDParams) { return switchPolicyID(navigationRef.current, params); } +/** + * Returns the currently selected policy ID stored in the navigation state. + */ +function getPolicyIDFromNavigationState() { + return getPolicyIDFromState(navigationRef.getRootState() as State); +} + export default { setShouldPopAllStateOnUP, navigate, @@ -379,6 +387,7 @@ export default { closeFullScreen, navigateWithSwitchPolicyID, resetToHome, + getPolicyIDFromNavigationState, }; export {navigationRef}; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js index 2c2d28a0edbc..9dafeb796fb2 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js @@ -1,10 +1,10 @@ import React, {useEffect} from 'react'; import {View} from 'react-native'; import ScreenWrapper from '@components/ScreenWrapper'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; +import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; @@ -21,7 +21,7 @@ const startTimer = () => { function BaseSidebarScreen(props) { const styles = useThemeStyles(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = Navigation.getPolicyIDFromNavigationState(); useEffect(() => { Performance.markStart(CONST.TIMING.SIDEBAR_LOADED); Timing.start(CONST.TIMING.SIDEBAR_LOADED, true); From 245ae01c5aad8fd4881da3d55b89259b54c1d244 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 20 Mar 2024 10:51:10 +0700 Subject: [PATCH 020/102] Fix get parentReportAction --- src/pages/home/HeaderView.tsx | 3 +- src/pages/home/ReportScreen.tsx | 78 ++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 8e0aefc39257..6b7d8d3c4586 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -102,6 +102,7 @@ function HeaderView({report, personalDetails, parentReport, parentReportAction, const policyName = ReportUtils.getPolicyName(report, true); const policyDescription = ReportUtils.getPolicyDescriptionText(policy); const isPersonalExpenseChat = isPolicyExpenseChat && ReportUtils.isCurrentUserSubmitter(report.reportID); + console.log(parentReportAction); const shouldShowSubtitle = () => { if (!subtitle) { return false; @@ -334,7 +335,7 @@ function HeaderView({report, personalDetails, parentReport, parentReportAction, )} - {isTaskReport && !isSmallScreenWidth && ReportUtils.isOpenTaskReport(report) && } + {isTaskReport && !isSmallScreenWidth && ReportUtils.isOpenTaskReport(report, parentReportAction) && } {canJoin && !isSmallScreenWidth && joinButton} {shouldShowThreeDotsButton && ( ; @@ -77,10 +77,7 @@ type ReportScreenOnyxProps = { /** The report metadata loading states */ reportMetadata: OnyxEntry; - - /** The report's parentReportAction */ - parentReportAction: OnyxEntry; -}; +} type OnyxHOCProps = { /** Onyx function that marks the component ready for hydration */ @@ -89,7 +86,15 @@ type OnyxHOCProps = { type ReportScreenNavigationProps = StackScreenProps; -type ReportScreenProps = OnyxHOCProps & ViewportOffsetTopProps & CurrentReportIDContextValue & ReportScreenOnyxProps & ReportScreenNavigationProps; +type ReportScreenPropsWithoutParentReportAction = OnyxHOCProps & CurrentReportIDContextValue & ViewportOffsetTopProps & ReportScreenOnyxPropsWithoutParentReportAction & ReportScreenNavigationProps; + +type ReportScreenParentReportActionOnyxProps = { + /** The report's parentReportAction */ + parentReportAction: OnyxEntry; +} + +type ReportScreenProps = ReportScreenPropsWithoutParentReportAction & ReportScreenParentReportActionOnyxProps + /** Get the currently viewed report ID as number */ function getReportID(route: ReportScreenNavigationProps['route']): string { @@ -122,7 +127,7 @@ function ReportScreen({ isLoadingNewerReportActions: false, }, reportActions = [], - parentReportAction, + parentReportAction: parentReportActions, accountManagerReportID, markReadyForHydration, policies = {}, @@ -226,6 +231,13 @@ function ReportScreen({ ], ); + const parentReportAction = useMemo(() => { + if (!parentReportActions || !report.parentReportActionID) { + return null; + } + return parentReportActions[report.parentReportActionID ?? '0']; + }, [parentReportActions, report.parentReportActionID]) + const prevReport = usePrevious(report); const prevUserLeavingStatus = usePrevious(userLeavingStatus); const [isBannerVisible, setIsBannerVisible] = useState(true); @@ -582,7 +594,7 @@ ReportScreen.displayName = 'ReportScreen'; export default withViewportOffsetTop( withCurrentReportID( - withOnyx( + withOnyx( { isSidebarLoaded: { key: ONYXKEYS.IS_SIDEBAR_LOADED, @@ -623,37 +635,33 @@ export default withViewportOffsetTop( userLeavingStatus: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${getReportID(route)}`, initialValue: false, - }, + } + }, + true, + )( + withOnyx({ parentReportAction: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : 0}`, - selector: (parentReportActions: OnyxEntry, props: WithOnyxInstanceState): OnyxEntry => { - const parentReportActionID = props?.report?.parentReportActionID; - if (!parentReportActionID) { - return null; - } - return parentReportActions?.[parentReportActionID] ?? null; - }, canEvict: false, }, - }, - true, - )( - memo( - ReportScreen, - (prevProps, nextProps) => - prevProps.isSidebarLoaded === nextProps.isSidebarLoaded && - lodashIsEqual(prevProps.reportActions, nextProps.reportActions) && - lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) && - prevProps.isComposerFullSize === nextProps.isComposerFullSize && - lodashIsEqual(prevProps.betas, nextProps.betas) && - lodashIsEqual(prevProps.policies, nextProps.policies) && - prevProps.accountManagerReportID === nextProps.accountManagerReportID && - prevProps.userLeavingStatus === nextProps.userLeavingStatus && - prevProps.currentReportID === nextProps.currentReportID && - prevProps.viewportOffsetTop === nextProps.viewportOffsetTop && - lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && - lodashIsEqual(prevProps.report, nextProps.report), + })( + memo( + ReportScreen, + (prevProps, nextProps) => + prevProps.isSidebarLoaded === nextProps.isSidebarLoaded && + lodashIsEqual(prevProps.reportActions, nextProps.reportActions) && + lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) && + prevProps.isComposerFullSize === nextProps.isComposerFullSize && + lodashIsEqual(prevProps.betas, nextProps.betas) && + lodashIsEqual(prevProps.policies, nextProps.policies) && + prevProps.accountManagerReportID === nextProps.accountManagerReportID && + prevProps.userLeavingStatus === nextProps.userLeavingStatus && + prevProps.currentReportID === nextProps.currentReportID && + prevProps.viewportOffsetTop === nextProps.viewportOffsetTop && + lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && + lodashIsEqual(prevProps.report, nextProps.report), + ), ), - ), + ) ), ); From b10eb48614466d94b0bed878b37baad4ab841a2a Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 20 Mar 2024 11:00:38 +0700 Subject: [PATCH 021/102] resolve another conflict --- .../SidebarScreen/FloatingActionButtonAndPopover.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 0673f22a7261..ec27112ab4b7 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -170,16 +170,7 @@ function FloatingActionButtonAndPopover(props) { CONST.IOU.TYPE.REQUEST, // When starting to create a money request from the global FAB, there is not an existing report yet. A random optimistic reportID is generated and used // for all of the routes in the creation flow. -<<<<<<< HEAD - ROUTES.MONEY_REQUEST_CREATE.getRoute( - CONST.IOU.ACTION.CREATE, - CONST.IOU.TYPE.REQUEST, - CONST.IOU.OPTIMISTIC_TRANSACTION_ID, - ReportUtils.generateReportID(), - ), -======= ReportUtils.generateReportID(), ->>>>>>> main ), ), }, From 15d6a41e79d5688c1789d82b659c567b62311319 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 20 Mar 2024 11:15:47 +0700 Subject: [PATCH 022/102] fix ts check --- src/components/MoneyRequestConfirmationList.tsx | 6 ++---- src/libs/actions/IOU.ts | 2 +- src/pages/iou/request/step/IOURequestStepAmount.js | 4 +++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index d54636c56c6e..d3ff5f974e6b 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -645,10 +645,8 @@ function MoneyRequestConfirmationList({ if (isDistanceRequest) { return; } - const action = props.isEditingSplitBill ? CONST.IOU.ACTION.EDIT : CONST.IOU.ACTION.CREATE; - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, props.iouType, props.transaction.transactionID, props.reportID, Navigation.getActiveRouteWithoutParams()), - ); + const action = isEditingSplitBill ? CONST.IOU.ACTION.EDIT : CONST.IOU.ACTION.CREATE; + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams())); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 91a74c593926..7a9e9989652e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -312,7 +312,7 @@ function updateMoneyRequestTypeParams(routes: StackNavigationState, reportID: string) { clearMoneyRequest(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); - Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE.getRoute(iouType, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, iouType, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, reportID)); } // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 6fc6b433d2fb..44944d41e2c9 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -1,5 +1,6 @@ import {useFocusEffect} from '@react-navigation/native'; import lodashGet from 'lodash/get'; +import lodashIsEmpty from 'lodash/isEmpty'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; @@ -86,7 +87,8 @@ function IOURequestStepAmount({ const iouRequestType = getRequestType(transaction); const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; - const {amount: transactionAmount} = ReportUtils.getTransactionDetails(isEditing && isSplitBill ? splitDraftTransaction : transaction); + const isEditingSplitBill = isEditing && isSplitBill; + const {amount: transactionAmount} = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction); const taxRates = lodashGet(policy, 'taxRates', {}); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); From fe2e60c9fd70f8de3b27a6192f5f2a5d2d05260c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 21 Mar 2024 17:06:54 +0700 Subject: [PATCH 023/102] remove unnecessary code --- src/ROUTES.ts | 4 - src/SCREENS.ts | 1 - .../MoneyRequestConfirmationList.tsx | 5 +- .../AppNavigator/ModalStackNavigators.tsx | 1 - src/libs/Navigation/linkingConfig/config.ts | 1 - src/libs/Navigation/types.ts | 1 - src/pages/EditRequestPage.js | 37 +--- src/pages/EditSplitBillPage.tsx | 28 +-- src/pages/iou/steps/NewRequestAmountPage.js | 195 ------------------ 9 files changed, 6 insertions(+), 267 deletions(-) delete mode 100644 src/pages/iou/steps/NewRequestAmountPage.js diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6868773a8290..7a7cb8d3e3ef 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -276,10 +276,6 @@ const ROUTES = { route: 'r/:reportID/invite', getRoute: (reportID: string) => `r/${reportID}/invite` as const, }, - MONEY_REQUEST_AMOUNT: { - route: ':iouType/new/amount/:reportID?', - getRoute: (iouType: string, reportID = '') => `${iouType}/new/amount/${reportID}` as const, - }, MONEY_REQUEST_PARTICIPANTS: { route: ':iouType/new/participants/:reportID?', getRoute: (iouType: string, reportID = '') => `${iouType}/new/participants/${reportID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 4d4e9ea327c6..84739d2da010 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -149,7 +149,6 @@ const SCREENS = { STEP_WAYPOINT: 'Money_Request_Step_Waypoint', STEP_TAX_AMOUNT: 'Money_Request_Step_Tax_Amount', STEP_TAX_RATE: 'Money_Request_Step_Tax_Rate', - AMOUNT: 'Money_Request_Amount', PARTICIPANTS: 'Money_Request_Participants', CONFIRMATION: 'Money_Request_Confirmation', CURRENCY: 'Money_Request_Currency', diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 63ca7c016bfc..7d5a0527fc10 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -645,8 +645,9 @@ function MoneyRequestConfirmationList({ if (isDistanceRequest) { return; } - const action = isEditingSplitBill ? CONST.IOU.ACTION.EDIT : CONST.IOU.ACTION.CREATE; - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(action, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams())); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index bd5bfc46134a..22f06089ab05 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -94,7 +94,6 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../pages/iou/request/step/IOURequestStepScan').default as React.ComponentType, [SCREENS.MONEY_REQUEST.STEP_TAG]: () => require('../../../pages/iou/request/step/IOURequestStepTag').default as React.ComponentType, [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: () => require('../../../pages/iou/request/step/IOURequestStepWaypoint').default as React.ComponentType, - [SCREENS.MONEY_REQUEST.AMOUNT]: () => require('../../../pages/iou/steps/NewRequestAmountPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: () => require('../../../pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CONFIRMATION]: () => require('../../../pages/iou/steps/MoneyRequestConfirmPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CURRENCY]: () => require('../../../pages/iou/IOUCurrencySelection').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 130fdf23732f..bc9143dfacc3 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -503,7 +503,6 @@ const config: LinkingOptions['config'] = { [SCREENS.MONEY_REQUEST.STEP_SCAN]: ROUTES.MONEY_REQUEST_STEP_SCAN.route, [SCREENS.MONEY_REQUEST.STEP_TAG]: ROUTES.MONEY_REQUEST_STEP_TAG.route, [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: ROUTES.MONEY_REQUEST_STEP_WAYPOINT.route, - [SCREENS.MONEY_REQUEST.AMOUNT]: ROUTES.MONEY_REQUEST_AMOUNT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.route, [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: ROUTES.MONEY_REQUEST_STEP_TAX_RATE.route, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: ROUTES.MONEY_REQUEST_PARTICIPANTS.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 9b0d9ce4decc..5a12b2168d9e 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -315,7 +315,6 @@ type RoomInviteNavigatorParamList = { }; type MoneyRequestNavigatorParamList = { - [SCREENS.MONEY_REQUEST.AMOUNT]: undefined; [SCREENS.MONEY_REQUEST.PARTICIPANTS]: { iouType: string; reportID: string; diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index de17d16a7c38..ab0fd6b1a609 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -8,7 +8,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import tagPropTypes from '@components/tagPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; import compose from '@libs/compose'; -import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; @@ -18,8 +17,6 @@ import * as TransactionUtils from '@libs/TransactionUtils'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import EditRequestAmountPage from './EditRequestAmountPage'; import EditRequestDistancePage from './EditRequestDistancePage'; import EditRequestReceiptPage from './EditRequestReceiptPage'; import EditRequestTagPage from './EditRequestTagPage'; @@ -75,9 +72,8 @@ const defaultProps = { function EditRequestPage({report, route, policy, policyCategories, policyTags, parentReportActions, transaction}) { const parentReportActionID = lodashGet(report, 'parentReportActionID', '0'); const parentReportAction = lodashGet(parentReportActions, parentReportActionID, {}); - const {amount: transactionAmount, currency: transactionCurrency, tag: transactionTag} = ReportUtils.getTransactionDetails(transaction); + const {tag: transactionTag} = ReportUtils.getTransactionDetails(transaction); - const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; const fieldToEdit = lodashGet(route, ['params', 'field'], ''); const tagIndex = Number(lodashGet(route, ['params', 'tagIndex'], undefined)); @@ -104,22 +100,6 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p }); }, [parentReportAction, fieldToEdit]); - const saveAmountAndCurrency = useCallback( - ({amount, currency: newCurrency}) => { - const newAmount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); - - // If the value hasn't changed, don't request to save changes on the server and just close the modal - if (newAmount === TransactionUtils.getAmount(transaction) && newCurrency === TransactionUtils.getCurrency(transaction)) { - Navigation.dismissModal(); - return; - } - - IOU.updateMoneyRequestAmountAndCurrency(transaction.transactionID, report.reportID, newCurrency, newAmount, policy, policyTags, policyCategories); - Navigation.dismissModal(); - }, - [transaction, report, policy, policyTags, policyCategories], - ); - const saveTag = useCallback( ({tag: newTag}) => { let updatedTag = newTag; @@ -140,21 +120,6 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p [tag, transaction.transactionID, report.reportID, transactionTag, tagIndex, policy, policyTags, policyCategories], ); - if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT) { - return ( - { - const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams()); - Navigation.navigate(ROUTES.EDIT_CURRENCY_REQUEST.getRoute(report.reportID, defaultCurrency, activeRoute)); - }} - /> - ); - } - if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.TAG && shouldShowTags) { return ( ; function EditSplitBillPage({route, transaction, draftTransaction, report}: EditSplitBillProps) { - const {field: fieldToEdit, reportID, reportActionID, currency, tagIndex} = route.params; + const {field: fieldToEdit, reportID, reportActionID, tagIndex} = route.params; - const {amount: transactionAmount, currency: transactionCurrency, tag: transactionTag} = ReportUtils.getTransactionDetails(draftTransaction ?? transaction) ?? {}; + const {tag: transactionTag} = ReportUtils.getTransactionDetails(draftTransaction ?? transaction) ?? {}; - const defaultCurrency = currency ?? transactionCurrency; function navigateBackToSplitDetails() { Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(reportID, reportActionID)); } @@ -53,27 +50,6 @@ function EditSplitBillPage({route, transaction, draftTransaction, report}: EditS navigateBackToSplitDetails(); }; - if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT) { - return ( - { - const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges.amount)); - - setDraftSplitTransaction({ - amount, - currency: transactionChanges.currency, - }); - }} - onNavigateToCurrency={() => { - const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams()); - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL_CURRENCY.getRoute(reportID, reportActionID, defaultCurrency, activeRoute)); - }} - /> - ); - } - if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.TAG) { return ( { - focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); - return () => { - if (!focusTimeoutRef.current) { - return; - } - clearTimeout(focusTimeoutRef.current); - }; - }, []), - ); - - // Because we use Onyx to store IOU info, when we try to make two different money requests from different tabs, - // it can result in an IOU sent with improper values. In such cases we want to reset the flow and redirect the user to the first step of the IOU. - useEffect(() => { - if (isEditing) { - // ID in Onyx could change by initiating a new request in a separate browser tab or completing a request - if (prevMoneyRequestID.current !== iou.id) { - // The ID is cleared on completing a request. In that case, we will do nothing. - if (!iou.id) { - return; - } - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - return; - } - const moneyRequestID = `${iouType}${reportID}`; - const shouldReset = iou.id !== moneyRequestID; - if (shouldReset) { - IOU.resetMoneyRequestInfo(moneyRequestID); - } - - if (!isDistanceRequestTab && (_.isEmpty(iou.participants) || iou.amount === 0 || shouldReset)) { - Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true); - } - } - - return () => { - prevMoneyRequestID.current = iou.id; - }; - }, [iou.participants, iou.amount, iou.id, isEditing, iouType, reportID, isDistanceRequestTab]); - - const navigateBack = () => { - Navigation.goBack(isEditing ? ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID) : ROUTES.HOME); - }; - - const navigateToCurrencySelectionPage = () => { - // If the money request being created is a distance request, don't allow the user to choose the currency. - // Only USD is allowed for distance requests. - if (isDistanceRequestTab) { - return; - } - - // Remove query from the route and encode it. - const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams()); - Navigation.navigate(ROUTES.MONEY_REQUEST_CURRENCY.getRoute(iouType, reportID, currency, activeRoute)); - }; - - const navigateToNextPage = ({amount}) => { - const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); - IOU.setMoneyRequestAmount(amountInSmallestCurrencyUnits); - IOU.setMoneyRequestCurrency(currency); - - if (isEditing) { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, reportID)); - return; - } - - IOU.navigateToNextPage(iou, iouType, report); - }; - - const content = ( - (textInput.current = e)} - onCurrencyButtonPress={navigateToCurrencySelectionPage} - onSubmitButtonPress={navigateToNextPage} - selectedTab={selectedTab} - /> - ); - - // ScreenWrapper is only needed in edit mode because we have a dedicated route for the edit amount page (MoneyRequestEditAmountPage). - // The rest of the cases this component is rendered through which has it's own ScreenWrapper - if (!isEditing) { - return content; - } - - return ( - - {({safeAreaPaddingBottomStyle}) => ( - - - - {content} - - - )} - - ); -} - -NewRequestAmountPage.propTypes = propTypes; -NewRequestAmountPage.defaultProps = defaultProps; -NewRequestAmountPage.displayName = 'NewRequestAmountPage'; - -export default withOnyx({ - iou: {key: ONYXKEYS.IOU}, - report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`, - }, - selectedTab: { - key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`, - }, -})(NewRequestAmountPage); From d11cf7364741cfe6fb8e60a0097fc1a002749557 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 22 Mar 2024 16:27:01 +0700 Subject: [PATCH 024/102] add type for step amount page --- src/libs/Navigation/types.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 210c1fd006b4..80021e92a0fd 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -323,6 +323,13 @@ type RoomInviteNavigatorParamList = { }; type MoneyRequestNavigatorParamList = { + [SCREENS.MONEY_REQUEST.STEP_AMOUNT]: { + action: ValueOf; + iouType: ValueOf; + transactionID: string; + reportID: string; + backTo: string; + }; [SCREENS.MONEY_REQUEST.PARTICIPANTS]: { iouType: string; reportID: string; From 40cd298ea720e517bd60ea01ae549b48e649687a Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 22 Mar 2024 18:10:18 +0700 Subject: [PATCH 025/102] fix TS error --- src/libs/actions/IOU.ts | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 8b7f289da381..3a82ea42e965 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4984,7 +4984,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', report.reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType as ValueOf, '1', report?.reportID ?? '1')); return; } @@ -5000,23 +5000,12 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); setMoneyRequestParticipants(participants); } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', report.reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType as ValueOf, '1', report.reportID)); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); } -/** - * When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation - * parameter. - * Gets a report id from the first participant of the IOU object stored in Onyx. - */ -function getIOUReportID(iou?: OnyxTypes.IOU, route?: MoneyRequestRoute): string { - // Disabling this line for safeness as nullish coalescing works only if the value is undefined or null - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return route?.params.reportID || iou?.participants?.[0]?.reportID || ''; -} - /** * Put money request on HOLD */ @@ -5199,7 +5188,6 @@ export { updateMoneyRequestDescription, replaceReceipt, detachReceipt, - getIOUReportID, editMoneyRequest, putOnHold, unholdRequest, From d284a391048e8e2813c4f33d3677ea05581df87e Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 22 Mar 2024 18:14:18 +0700 Subject: [PATCH 026/102] fix TS error --- src/libs/actions/IOU.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3a82ea42e965..e2ea7a8cbd10 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -63,8 +63,6 @@ import * as CachedPDFPaths from './CachedPDFPaths'; import * as Policy from './Policy'; import * as Report from './Report'; -type MoneyRequestRoute = StackScreenProps['route']; - type IOURequestType = ValueOf; type OneOnOneIOUReport = OnyxTypes.Report | undefined | null; From 40c5970c9013f8bfc010cfdfd6287ce6a21f6cc9 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 22 Mar 2024 18:15:00 +0700 Subject: [PATCH 027/102] fix lint --- src/libs/actions/IOU.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e2ea7a8cbd10..94c454fba38e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1,5 +1,4 @@ import type {ParamListBase, StackNavigationState} from '@react-navigation/native'; -import type {StackScreenProps} from '@react-navigation/stack'; import {format} from 'date-fns'; import fastMerge from 'expensify-common/lib/fastMerge'; import Str from 'expensify-common/lib/str'; @@ -45,11 +44,10 @@ import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUR import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; -import type {MoneyRequestNavigatorParamList, NavigationPartialRoute} from '@navigation/types'; +import type {NavigationPartialRoute} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; From eb11d74f2ca7fea0cbb2dab78a34a5bb495345da Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 22 Mar 2024 16:26:52 +0100 Subject: [PATCH 028/102] Move getPolicyIDFromNavigationState to PolicyUtils --- src/libs/Navigation/Navigation.ts | 11 +---------- src/libs/PolicyUtils.ts | 12 +++++++++++- .../home/sidebar/SidebarScreen/BaseSidebarScreen.js | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index f6d871724291..d57d0272738b 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -13,14 +13,13 @@ import type {Report} from '@src/types/onyx'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import originalDismissModal from './dismissModal'; import originalDismissModalWithReport from './dismissModalWithReport'; -import getPolicyIDFromState from './getPolicyIDFromState'; import originalGetTopmostReportActionId from './getTopmostReportActionID'; import originalGetTopmostReportId from './getTopmostReportId'; import linkingConfig from './linkingConfig'; import linkTo from './linkTo'; import navigationRef from './navigationRef'; import switchPolicyID from './switchPolicyID'; -import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute, SwitchPolicyIDParams} from './types'; +import type {NavigationStateRoute, State, StateOrRoute, SwitchPolicyIDParams} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -360,13 +359,6 @@ function navigateWithSwitchPolicyID(params: SwitchPolicyIDParams) { return switchPolicyID(navigationRef.current, params); } -/** - * Returns the currently selected policy ID stored in the navigation state. - */ -function getPolicyIDFromNavigationState() { - return getPolicyIDFromState(navigationRef.getRootState() as State); -} - export default { setShouldPopAllStateOnUP, navigate, @@ -387,7 +379,6 @@ export default { closeFullScreen, navigateWithSwitchPolicyID, resetToHome, - getPolicyIDFromNavigationState, }; export {navigationRef}; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 7717513d3f59..687f39fdf7c5 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -8,7 +8,9 @@ import type {PersonalDetailsList, Policy, PolicyCategories, PolicyMembers, Polic import type {PolicyFeatureName} from '@src/types/onyx/Policy'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import Navigation from './Navigation/Navigation'; +import getPolicyIDFromState from './Navigation/getPolicyIDFromState'; +import Navigation, {navigationRef} from './Navigation/Navigation'; +import type {RootStackParamList, State} from './Navigation/types'; type MemberEmailsToAccountIDs = Record; type UnitRate = {rate: number}; @@ -297,6 +299,13 @@ function isPolicyFeatureEnabled(policy: OnyxEntry | EmptyObject, feature return Boolean(policy?.[featureName]); } +/** + * Get the currently selected policy ID stored in the navigation state. + */ +function getPolicyIDFromNavigationState() { + return getPolicyIDFromState(navigationRef.getRootState() as State); +} + export { getActivePolicies, hasAccountingConnections, @@ -332,6 +341,7 @@ export { hasTaxRateError, getTaxByID, hasPolicyCategoriesError, + getPolicyIDFromNavigationState, }; export type {MemberEmailsToAccountIDs}; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js index 9dafeb796fb2..d34f821b4b9b 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js @@ -4,8 +4,8 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; -import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; +import {getPolicyIDFromNavigationState} from '@libs/PolicyUtils'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; @@ -21,7 +21,7 @@ const startTimer = () => { function BaseSidebarScreen(props) { const styles = useThemeStyles(); - const activeWorkspaceID = Navigation.getPolicyIDFromNavigationState(); + const activeWorkspaceID = getPolicyIDFromNavigationState(); useEffect(() => { Performance.markStart(CONST.TIMING.SIDEBAR_LOADED); Timing.start(CONST.TIMING.SIDEBAR_LOADED, true); From a20a9e59b5658dbe34341248525620910c8cb973 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 22 Mar 2024 22:30:52 +0700 Subject: [PATCH 029/102] update route of currency page --- src/ROUTES.ts | 6 +++--- src/pages/iou/request/step/IOURequestStepAmount.js | 2 +- src/pages/iou/request/step/IOURequestStepTaxAmountPage.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 7b4b8a97bdc9..8c912d80f14b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -334,9 +334,9 @@ const ROUTES = { getUrlWithBackToParam(`${action}/${iouType}/category/${transactionID}/${reportID}${reportActionID ? `/${reportActionID}` : ''}`, backTo), }, MONEY_REQUEST_STEP_CURRENCY: { - route: 'create/:iouType/currency/:transactionID/:reportID/:pageIndex?', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') => - getUrlWithBackToParam(`create/${iouType}/currency/${transactionID}/${reportID}/${pageIndex}`, backTo), + route: ':action/:iouType/currency/:transactionID/:reportID/:pageIndex?', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') => + getUrlWithBackToParam(`${action}/${iouType}/currency/${transactionID}/${reportID}/${pageIndex}`, backTo), }, MONEY_REQUEST_STEP_DATE: { route: ':action/:iouType/date/:transactionID/:reportID', diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 44944d41e2c9..bf664ace5c6d 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -127,7 +127,7 @@ function IOURequestStepAmount({ }; const navigateToCurrencySelectionPage = () => { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams())); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(action, iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams())); }; /** diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js index 7a75e9f48805..e568cf917781 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js @@ -112,7 +112,7 @@ function IOURequestStepTaxAmountPage({ // If the money request being created is a distance request, don't allow the user to choose the currency. // Only USD is allowed for distance requests. // Remove query from the route and encode it. - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams())); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams())); }; const updateTaxAmount = (currentAmount) => { From 927004f737e726f2cc055a0a2f90951eb8caed9b Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Mon, 25 Mar 2024 08:21:40 +0530 Subject: [PATCH 030/102] Fix central pane change --- .../Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 95233bfed079..f45e47173335 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -19,6 +19,9 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.PROFILE.ADDRESS, SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, SCREENS.SETTINGS.SHARE_CODE, + SCREENS.SETTINGS.EXIT_SURVEY.REASON, + SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, + SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM ], [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], [SCREENS.SETTINGS.WALLET.ROOT]: [ From 0dc5f633635c5798352e63df6da170987d675d6b Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Mon, 25 Mar 2024 08:34:56 +0530 Subject: [PATCH 031/102] Fix Prettier --- .../Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index f45e47173335..4ec955784d92 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -21,7 +21,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.EXIT_SURVEY.REASON, SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, - SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM + SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, ], [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], [SCREENS.SETTINGS.WALLET.ROOT]: [ From 78195aeb07046692812b17ee619e4944c3d14510 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 25 Mar 2024 14:10:14 +0700 Subject: [PATCH 032/102] add temporary solution for edit currency --- src/libs/actions/IOU.ts | 7 ++--- src/libs/actions/TransactionEdit.ts | 1 - .../iou/request/step/IOURequestStepAmount.js | 27 ++++++++++++++++++- .../request/step/IOURequestStepCurrency.js | 22 ++++++++++----- .../step/IOURequestStepTaxAmountPage.js | 4 ++- 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5632268ef6ca..24786321b5eb 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -343,12 +343,13 @@ function setMoneyRequestCreated(transactionID: string, created: string, isDraft: } // eslint-disable-next-line @typescript-eslint/naming-convention -function setMoneyRequestCurrency_temporaryForRefactor(transactionID: string, currency: string, removeOriginalCurrency = false) { +function setMoneyRequestCurrency_temporaryForRefactor(transactionID: string, currency: string, removeOriginalCurrency = false, isEditing = false) { + const fieldToUpdate = isEditing ? 'modifiedCurrency' : 'currency'; if (removeOriginalCurrency) { - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency, originalCurrency: null}); + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {[fieldToUpdate]: currency, originalCurrency: null}); return; } - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {currency}); + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {[fieldToUpdate]: currency}); } // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/src/libs/actions/TransactionEdit.ts b/src/libs/actions/TransactionEdit.ts index b1710aa72cbb..9d5ebcd1ec88 100644 --- a/src/libs/actions/TransactionEdit.ts +++ b/src/libs/actions/TransactionEdit.ts @@ -38,5 +38,4 @@ function restoreOriginalTransactionFromBackup(transactionID: string) { }, }); } - export {createBackupTransaction, removeBackupTransaction, restoreOriginalTransactionFromBackup}; diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index bf664ace5c6d..f61bab102d2a 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -7,6 +7,7 @@ import {withOnyx} from 'react-native-onyx'; import taxPropTypes from '@components/taxPropTypes'; import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; +import * as TransactionEdit from '@libs/actions/TransactionEdit'; import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; @@ -38,6 +39,9 @@ const propTypes = { /** The draft transaction that holds data to be persisted on the current transaction */ splitDraftTransaction: transactionPropTypes, + /** The draft transaction object being modified in Onyx */ + draftTransaction: transactionPropTypes, + /** The policy of the report */ policy: PropTypes.shape({ /** @@ -61,6 +65,7 @@ const defaultProps = { report: {}, transaction: {}, splitDraftTransaction: {}, + draftTransaction: {}, policy: {}, }; @@ -76,7 +81,7 @@ function IOURequestStepAmount({ }, transaction, splitDraftTransaction, - transaction: {currency}, + draftTransaction, policy, }) { const {translate} = useLocalize(); @@ -89,6 +94,7 @@ function IOURequestStepAmount({ const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const isEditingSplitBill = isEditing && isSplitBill; const {amount: transactionAmount} = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction); + const {currency} = ReportUtils.getTransactionDetails(isEditing ? draftTransaction : transaction); const taxRates = lodashGet(policy, 'taxRates', {}); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)); @@ -107,6 +113,19 @@ function IOURequestStepAmount({ ); useEffect(() => { + if (isEditing) { + // A temporary solution to not prevent users from editing the currency + // We create a backup transaction and use it to save the currency and remove this transaction backup if we don't save the amount + // It should be removed after this issue https://github.com/Expensify/App/issues/34607 is fixed + TransactionEdit.createBackupTransaction(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction); + + return () => { + if (isSaveButtonPressed.current) { + return; + } + TransactionEdit.removeBackupTransaction(transaction.transactionID || ''); + }; + } if (transaction.originalCurrency) { originalCurrency.current = transaction.originalCurrency; } else { @@ -221,5 +240,11 @@ export default compose( policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, }, + draftTransaction: { + key: ({route}) => { + const transactionID = lodashGet(route, 'params.transactionID', 0); + return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`; + }, + }, }), )(IOURequestStepAmount); diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index 43e4e9bf0eaa..ec8803937da0 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -1,4 +1,5 @@ import Str from 'expensify-common/lib/str'; +import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useMemo, useRef, useState} from 'react'; import {Keyboard} from 'react-native'; @@ -11,7 +12,9 @@ import useLocalize from '@hooks/useLocalize'; import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES, {getUrlWithBackToParam} from '@src/ROUTES'; import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; @@ -40,25 +43,26 @@ const propTypes = { ), /* Onyx Props */ - /** The transaction being modified */ - transaction: transactionPropTypes, + /** The draft transaction object being modified in Onyx */ + draftTransaction: transactionPropTypes, }; const defaultProps = { currencyList: {}, - transaction: {}, + draftTransaction: {}, }; function IOURequestStepCurrency({ currencyList, route: { - params: {backTo, iouType, pageIndex, reportID, transactionID}, + params: {backTo, iouType, pageIndex, reportID, transactionID, action}, }, - transaction: {currency}, + draftTransaction, }) { const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); const optionsSelectorRef = useRef(); + const {currency} = ReportUtils.getTransactionDetails(draftTransaction); const navigateBack = () => { // If the currency selection was done from the confirmation step (eg. + > request money > manual > confirm > amount > currency) @@ -79,7 +83,7 @@ function IOURequestStepCurrency({ */ const confirmCurrencySelection = (option) => { Keyboard.dismiss(); - IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, option.currencyCode); + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, option.currencyCode, false, action === CONST.IOU.ACTION.EDIT); navigateBack(); }; @@ -154,5 +158,11 @@ export default compose( withFullTransactionOrNotFound, withOnyx({ currencyList: {key: ONYXKEYS.CURRENCY_LIST}, + draftTransaction: { + key: ({route}) => { + const transactionID = lodashGet(route, 'params.transactionID', 0); + return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`; + }, + }, }), )(IOURequestStepCurrency); diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js index e568cf917781..a45263d8bee1 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js @@ -112,7 +112,9 @@ function IOURequestStepTaxAmountPage({ // If the money request being created is a distance request, don't allow the user to choose the currency. // Only USD is allowed for distance requests. // Remove query from the route and encode it. - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams())); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams()), + ); }; const updateTaxAmount = (currentAmount) => { From db1aa3f0812072464195367ab8f5b58fd9cd299a Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 25 Mar 2024 14:11:29 +0700 Subject: [PATCH 033/102] remove un-use function --- src/libs/actions/IOU.ts | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 24786321b5eb..a71a7a640e79 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4978,41 +4978,6 @@ function setShownHoldUseExplanation() { Onyx.set(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, true); } -/** Navigates to the next IOU page based on where the IOU request was started */ -function navigateToNextPage(iou: OnyxEntry, iouType: string, report?: OnyxTypes.Report, path = '') { - const moneyRequestID = `${iouType}${report?.reportID ?? ''}`; - const shouldReset = iou?.id !== moneyRequestID && !!report?.reportID; - - // If the money request ID in Onyx does not match the ID from params, we want to start a new request - // with the ID from params. We need to clear the participants in case the new request is initiated from FAB. - if (shouldReset) { - resetMoneyRequestInfo(moneyRequestID); - } - - // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. - if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID)); - return; - } - - // If a request is initiated on a report, skip the participants selection step and navigate to the confirmation page. - if (report?.reportID) { - // If the report is iou or expense report, we should get the chat report to set participant for request money - const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReport(report.chatReportID) : report; - // Reinitialize the participants when the money request ID in Onyx does not match the ID from params - if (!iou?.participants?.length || shouldReset) { - const currentUserAccountID = currentUserPersonalDetails.accountID; - const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) - ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}] - : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); - setMoneyRequestParticipants(participants); - } - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); - return; - } - Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); -} - /** * When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation * parameter. @@ -5195,7 +5160,6 @@ export { setMoneyRequestTaxAmount, setMoneyRequestTaxRate, setShownHoldUseExplanation, - navigateToNextPage, updateMoneyRequestDate, updateMoneyRequestBillable, updateMoneyRequestMerchant, From 8982f33cf8be5360430efef653fba6507a3a65b3 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 25 Mar 2024 16:27:20 +0700 Subject: [PATCH 034/102] remove edit amount page and revert the unnecessary change --- src/libs/actions/TransactionEdit.ts | 1 + src/pages/EditRequestAmountPage.js | 66 ----------------------------- 2 files changed, 1 insertion(+), 66 deletions(-) delete mode 100644 src/pages/EditRequestAmountPage.js diff --git a/src/libs/actions/TransactionEdit.ts b/src/libs/actions/TransactionEdit.ts index 9d5ebcd1ec88..b1710aa72cbb 100644 --- a/src/libs/actions/TransactionEdit.ts +++ b/src/libs/actions/TransactionEdit.ts @@ -38,4 +38,5 @@ function restoreOriginalTransactionFromBackup(transactionID: string) { }, }); } + export {createBackupTransaction, removeBackupTransaction, restoreOriginalTransactionFromBackup}; diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js deleted file mode 100644 index bc77b9ecca75..000000000000 --- a/src/pages/EditRequestAmountPage.js +++ /dev/null @@ -1,66 +0,0 @@ -import {useFocusEffect} from '@react-navigation/native'; -import PropTypes from 'prop-types'; -import React, {useCallback, useRef} from 'react'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; -import CONST from '@src/CONST'; -import MoneyRequestAmountForm from './iou/steps/MoneyRequestAmountForm'; - -const propTypes = { - /** Transaction default amount value */ - defaultAmount: PropTypes.number.isRequired, - - /** Transaction default currency value */ - defaultCurrency: PropTypes.string.isRequired, - - /** Callback to fire when the Save button is pressed */ - onSubmit: PropTypes.func.isRequired, - - /** Callback to fire when we press on the currency */ - onNavigateToCurrency: PropTypes.func.isRequired, -}; - -function EditRequestAmountPage({defaultAmount, defaultCurrency, onNavigateToCurrency, onSubmit}) { - const {translate} = useLocalize(); - - const textInput = useRef(null); - const focusTimeoutRef = useRef(null); - - useFocusEffect( - useCallback(() => { - focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); - return () => { - if (!focusTimeoutRef.current) { - return; - } - clearTimeout(focusTimeoutRef.current); - }; - }, []), - ); - - return ( - - - (textInput.current = e)} - onCurrencyButtonPress={onNavigateToCurrency} - onSubmitButtonPress={onSubmit} - isEditing - /> - - ); -} - -EditRequestAmountPage.propTypes = propTypes; -EditRequestAmountPage.displayName = 'EditRequestAmountPage'; - -export default EditRequestAmountPage; From 11da8b2af1da2c32c181cb85f68a4f614b4c1d25 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 25 Mar 2024 16:40:47 +0700 Subject: [PATCH 035/102] update saveAmountAndCurrency function to include the create case --- src/pages/iou/request/step/IOURequestStepAmount.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index f61bab102d2a..b0e013d85f16 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -184,6 +184,11 @@ function IOURequestStepAmount({ }; const saveAmountAndCurrency = ({amount}) => { + if (!isEditing) { + navigateToNextPage({amount}); + return; + } + const newAmount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); // If the value hasn't changed, don't request to save changes on the server and just close the modal @@ -216,7 +221,7 @@ function IOURequestStepAmount({ amount={Math.abs(transactionAmount)} ref={(e) => (textInput.current = e)} onCurrencyButtonPress={navigateToCurrencySelectionPage} - onSubmitButtonPress={isEditing ? saveAmountAndCurrency : navigateToNextPage} + onSubmitButtonPress={saveAmountAndCurrency} selectedTab={iouRequestType} /> From 7304fbe01ae399ab49cca48927c9f028c94937d5 Mon Sep 17 00:00:00 2001 From: gaber Date: Mon, 25 Mar 2024 21:16:50 +0200 Subject: [PATCH 036/102] update MentionUserRenderer.tsx display text --- .../HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx index 0327b6bc6f56..d3376a798a8b 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx @@ -59,8 +59,8 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona if (!isEmpty(htmlAttribAccountID)) { const user = personalDetails[htmlAttribAccountID]; accountID = parseInt(htmlAttribAccountID, 10); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - displayNameOrLogin = PersonalDetailsUtils.getDisplayNameOrDefault(user, LocalePhoneNumber.formatPhoneNumber(user?.login ?? '')); + displayNameOrLogin = LocalePhoneNumber.formatPhoneNumber(user?.login ?? '') || PersonalDetailsUtils.getDisplayNameOrDefault(user); + displayNameOrLogin = Str.removeSMSDomain(getMentionDisplayText(displayNameOrLogin, htmlAttributeAccountID, user?.login ?? '')); navigationRoute = ROUTES.PROFILE.getRoute(htmlAttribAccountID); } else if ('data' in tnodeClone && !isEmptyObject(tnodeClone.data)) { // We need to remove the LTR unicode and leading @ from data as it is not part of the login From eda996e5232c9d0a1dc6c8dc4a19af933a0cf3d0 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 26 Mar 2024 15:25:21 +0800 Subject: [PATCH 037/102] fix anchor text can't show both underline and line through on iOS --- .../HTMLRenderers/AnchorRenderer.tsx | 25 +++++++++++++++++-- src/styles/utils/textDecorationLine.ts | 4 +++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.tsx index 465a4f747bcb..d918007e5750 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.tsx @@ -55,6 +55,9 @@ function AnchorRenderer({tnode, style, key}: AnchorRendererProps) { ); } + const hasStrikethroughStyle = 'textDecorationLine' in parentStyle && parentStyle.textDecorationLine === 'line-through'; + const textDecorationLineStyle = hasStrikethroughStyle ? styles.underlineLineThrough : {}; + return ( Link.openLink(attrHref, environmentURL, isAttachment) : undefined} > - + { + if (props.childTnode.tagName === 'br') { + return {'\n'}; + } + if (props.childTnode.type === 'text') { + return ( + + {props.childTnode.data} + + ); + } + return props.childElement; + }} + /> ); } diff --git a/src/styles/utils/textDecorationLine.ts b/src/styles/utils/textDecorationLine.ts index e5f079150e78..5e830cbf08c1 100644 --- a/src/styles/utils/textDecorationLine.ts +++ b/src/styles/utils/textDecorationLine.ts @@ -5,4 +5,8 @@ export default { textDecorationLine: 'line-through', textDecorationStyle: 'solid', }, + underlineLineThrough: { + textDecorationLine: 'underline line-through', + textDecorationStyle: 'solid', + }, } satisfies Record; From 52ee85a4c9813e7a3001e21b452b03c86ce62ad9 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 26 Mar 2024 17:31:36 +0700 Subject: [PATCH 038/102] memo parentReportActions --- src/pages/home/HeaderView.tsx | 1 - src/pages/home/ReportScreen.tsx | 48 ++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index a82549e5993d..aa2ed1209490 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -102,7 +102,6 @@ function HeaderView({report, personalDetails, parentReport, parentReportAction, const policyName = ReportUtils.getPolicyName(report, true); const policyDescription = ReportUtils.getPolicyDescriptionText(policy); const isPersonalExpenseChat = isPolicyExpenseChat && ReportUtils.isCurrentUserSubmitter(report.reportID); - console.log(parentReportAction); const shouldShowSubtitle = () => { if (!subtitle) { return false; diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index b3d27e9517f3..c6d99eae1c40 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -6,7 +6,6 @@ import {InteractionManager, View} from 'react-native'; import type {FlatList, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import type {WithOnyxInstanceState} from 'react-native-onyx/dist/types'; import type {LayoutChangeEvent} from 'react-native/Libraries/Types/CoreEventTypes'; import Banner from '@components/Banner'; import BlockingView from '@components/BlockingViews/BlockingView'; @@ -81,7 +80,7 @@ type ReportScreenOnyxPropsWithoutParentReportAction = { /** The report metadata loading states */ reportMetadata: OnyxEntry; -} +}; type OnyxHOCProps = { /** Onyx function that marks the component ready for hydration */ @@ -90,15 +89,18 @@ type OnyxHOCProps = { type ReportScreenNavigationProps = StackScreenProps; -type ReportScreenPropsWithoutParentReportAction = OnyxHOCProps & CurrentReportIDContextValue & ViewportOffsetTopProps & ReportScreenOnyxPropsWithoutParentReportAction & ReportScreenNavigationProps; +type ReportScreenPropsWithoutParentReportAction = OnyxHOCProps & + CurrentReportIDContextValue & + ViewportOffsetTopProps & + ReportScreenOnyxPropsWithoutParentReportAction & + ReportScreenNavigationProps; type ReportScreenParentReportActionOnyxProps = { - /** The report's parentReportAction */ + /** The report's parentReportActions */ parentReportActions: OnyxEntry; -} - -type ReportScreenProps = ReportScreenPropsWithoutParentReportAction & ReportScreenParentReportActionOnyxProps +}; +type ReportScreenProps = ReportScreenPropsWithoutParentReportAction & ReportScreenParentReportActionOnyxProps; /** Get the currently viewed report ID as number */ function getReportID(route: ReportScreenNavigationProps['route']): string { @@ -121,6 +123,13 @@ function isEmpty(report: OnyxTypes.Report): boolean { return !Object.values(report).some((value) => value !== undefined && value !== ''); } +function getParentReportAction(parentReportActions: OnyxEntry, parentReportActionID: string | undefined): OnyxEntry { + if (!parentReportActions || !parentReportActionID) { + return null; + } + return parentReportActions[parentReportActionID ?? '0']; +} + function ReportScreen({ betas = [], route, @@ -237,12 +246,7 @@ function ReportScreen({ ], ); - const parentReportAction = useMemo(() => { - if (!parentReportActions || !report.parentReportActionID) { - return null; - } - return parentReportActions[report.parentReportActionID ?? '0']; - }, [parentReportActions, report.parentReportActionID]) + const parentReportAction = useMemo(() => getParentReportAction(parentReportActions, report?.parentReportActionID), [parentReportActions, report.parentReportActionID]); const prevReport = usePrevious(report); const prevUserLeavingStatus = usePrevious(userLeavingStatus); @@ -718,7 +722,7 @@ export default withViewportOffsetTop( userLeavingStatus: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${getReportID(route)}`, initialValue: false, - } + }, }, true, )( @@ -728,9 +732,10 @@ export default withViewportOffsetTop( canEvict: false, }, })( - memo( - ReportScreen, - (prevProps, nextProps) => + memo(ReportScreen, (prevProps, nextProps) => { + const prevParentReportAction = getParentReportAction(prevProps.parentReportActions, prevProps.report?.parentReportActionID); + const nextParentReportAction = getParentReportAction(nextProps.parentReportActions, nextProps.report?.parentReportActionID); + return ( prevProps.isSidebarLoaded === nextProps.isSidebarLoaded && lodashIsEqual(prevProps.sortedAllReportActions, nextProps.sortedAllReportActions) && lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) && @@ -741,11 +746,12 @@ export default withViewportOffsetTop( prevProps.userLeavingStatus === nextProps.userLeavingStatus && prevProps.currentReportID === nextProps.currentReportID && prevProps.viewportOffsetTop === nextProps.viewportOffsetTop && - lodashIsEqual(prevProps.parentReportActions, nextProps.parentReportActions) && + lodashIsEqual(prevParentReportAction, nextParentReportAction) && lodashIsEqual(prevProps.route, nextProps.route) && - lodashIsEqual(prevProps.report, nextProps.report), - ), + lodashIsEqual(prevProps.report, nextProps.report) + ); + }), ), - ) + ), ), ); From 073a059ed7c3eaa457c5c7f48d0e6b6b9a7e1a78 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Tue, 26 Mar 2024 22:35:53 +0700 Subject: [PATCH 039/102] update route --- src/ROUTES.ts | 4 ++-- src/libs/actions/IOU.ts | 4 ++-- src/pages/iou/request/step/IOURequestStepAmount.js | 2 +- src/pages/iou/request/step/IOURequestStepCurrency.js | 2 +- src/pages/iou/request/step/IOURequestStepDistance.js | 2 +- src/pages/iou/request/step/IOURequestStepParticipants.js | 2 +- src/pages/iou/request/step/IOURequestStepScan/index.js | 2 +- src/pages/iou/request/step/IOURequestStepScan/index.native.js | 2 +- src/pages/iou/request/step/IOURequestStepTaxAmountPage.js | 2 +- .../MoneyRequestParticipantsPage.js | 2 +- src/pages/iou/steps/NewRequestAmountPage.js | 4 ++-- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6d3f78864fa5..4e8b746cee70 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -306,8 +306,8 @@ const ROUTES = { `create/${iouType}/start/${transactionID}/${reportID}` as const, }, MONEY_REQUEST_STEP_CONFIRMATION: { - route: 'create/:iouType/confirmation/:transactionID/:reportID', - getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/confirmation/${transactionID}/${reportID}` as const, + route: ':action/:iouType/confirmation/:transactionID/:reportID', + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string) => `${action}/${iouType}/confirmation/${transactionID}/${reportID}` as const, }, MONEY_REQUEST_STEP_AMOUNT: { route: 'create/:iouType/amount/:transactionID/:reportID', diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 94c454fba38e..85d82e54fa71 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4980,7 +4980,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType as ValueOf, '1', report?.reportID ?? '1')); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, '1', report?.reportID ?? '1')); return; } @@ -4996,7 +4996,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); setMoneyRequestParticipants(participants); } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType as ValueOf, '1', report.reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, '1', report.reportID)); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.js index 9fdd2bea24f4..781bcbda0dbb 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.js @@ -145,7 +145,7 @@ function IOURequestStepAmount({ // to the confirm step. if (report.reportID) { IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); return; } diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index 43e4e9bf0eaa..4ce5c483bde7 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -66,7 +66,7 @@ function IOURequestStepCurrency({ // are only able to handle one backTo param at a time and the user needs to go back to the amount page before going back // to the confirmation page if (pageIndex === 'confirm') { - const routeToAmountPageWithConfirmationAsBackTo = getUrlWithBackToParam(backTo, `/${ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)}`); + const routeToAmountPageWithConfirmationAsBackTo = getUrlWithBackToParam(backTo, `/${ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)}`); Navigation.goBack(routeToAmountPageWithConfirmationAsBackTo); return; } diff --git a/src/pages/iou/request/step/IOURequestStepDistance.js b/src/pages/iou/request/step/IOURequestStepDistance.js index dad610cbc636..302494d1f8b5 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.js +++ b/src/pages/iou/request/step/IOURequestStepDistance.js @@ -135,7 +135,7 @@ function IOURequestStepDistance({ // to the confirm step. if (report.reportID) { IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); return; } diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.js b/src/pages/iou/request/step/IOURequestStepParticipants.js index 5ca465d8fb78..7ccbdb18ee03 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.js +++ b/src/pages/iou/request/step/IOURequestStepParticipants.js @@ -128,7 +128,7 @@ function IOURequestStepParticipants({ IOU.setMoneyRequestTag(transactionID, ''); IOU.setMoneyRequestCategory(transactionID, ''); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(nextStepIOUType, transactionID, selectedReportID.current || reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, nextStepIOUType, transactionID, selectedReportID.current || reportID)); }, [iouType, transactionID, reportID], ); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.js b/src/pages/iou/request/step/IOURequestStepScan/index.js index 6bf517c30eb0..d2fc54ffbe4c 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.js @@ -187,7 +187,7 @@ function IOURequestStepScan({ // If the transaction was created from the + menu from the composer inside of a chat, the participants can automatically // be added to the transaction (taken from the chat report participants) and then the person is taken to the confirmation step. IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); }, [iouType, report, reportID, transactionID, isFromGlobalCreate, backTo]); const updateScanAndNavigate = useCallback( diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.js b/src/pages/iou/request/step/IOURequestStepScan/index.native.js index 03eb12fc3b03..7c57c7483fe7 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.js @@ -195,7 +195,7 @@ function IOURequestStepScan({ // If the transaction was created from the + menu from the composer inside of a chat, the participants can automatically // be added to the transaction (taken from the chat report participants) and then the person is taken to the confirmation step. IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); }, [iouType, report, reportID, transactionID, isFromGlobalCreate, backTo]); const updateScanAndNavigate = useCallback( diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js index 7a75e9f48805..1c3e4197a146 100644 --- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js +++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.js @@ -133,7 +133,7 @@ function IOURequestStepTaxAmountPage({ if (report.reportID) { // TODO: Is this really needed at all? IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, transactionID, reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); return; } diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js index 9b8ed32fc197..b5d11faac6c4 100644 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js @@ -87,7 +87,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route, transaction}) { const navigateToConfirmationStep = (moneyRequestType) => { IOU.setMoneyRequestId(moneyRequestType); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(moneyRequestType, lodashGet(transaction, 'transactionID', 1), reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, moneyRequestType, lodashGet(transaction, 'transactionID', 1), reportID)); }; const navigateBack = useCallback((forceFallback = false) => { diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index 007a63bdb713..f4a38d23c861 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -113,7 +113,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { }, [iou.participants, iou.amount, iou.id, isEditing, iouType, reportID, isDistanceRequestTab]); const navigateBack = () => { - Navigation.goBack(isEditing ? ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID) : ROUTES.HOME); + Navigation.goBack(isEditing ? ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, '1', reportID) : ROUTES.HOME); }; const navigateToCurrencySelectionPage = () => { @@ -134,7 +134,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { IOU.setMoneyRequestCurrency(currency); if (isEditing) { - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(iouType, '1', reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, '1', reportID)); return; } From 8594d01bd4564ab30b8dd9576680ef7abbdccc10 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Tue, 26 Mar 2024 23:48:07 +0700 Subject: [PATCH 040/102] fix lint --- src/pages/iou/request/step/IOURequestStepCurrency.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index 4ce5c483bde7..7e3d5a1b7079 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -14,6 +14,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as IOU from '@userActions/IOU'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES, {getUrlWithBackToParam} from '@src/ROUTES'; +import CONST from '@src/CONST'; import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; import StepScreenWrapper from './StepScreenWrapper'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; From d835235478e61c1ace6bfaf15cb10d37736dc6cc Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Tue, 26 Mar 2024 23:56:32 +0700 Subject: [PATCH 041/102] lint fix --- src/ROUTES.ts | 3 ++- src/pages/iou/request/step/IOURequestStepCurrency.js | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index e6dc082c60c8..06182f944979 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -307,7 +307,8 @@ const ROUTES = { }, MONEY_REQUEST_STEP_CONFIRMATION: { route: ':action/:iouType/confirmation/:transactionID/:reportID', - getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string) => `${action}/${iouType}/confirmation/${transactionID}/${reportID}` as const, + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string) => + `${action}/${iouType}/confirmation/${transactionID}/${reportID}` as const, }, MONEY_REQUEST_STEP_AMOUNT: { route: 'create/:iouType/amount/:transactionID/:reportID', diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.js b/src/pages/iou/request/step/IOURequestStepCurrency.js index 7e3d5a1b7079..f6a39dfbf216 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.js +++ b/src/pages/iou/request/step/IOURequestStepCurrency.js @@ -12,9 +12,9 @@ import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as IOU from '@userActions/IOU'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES, {getUrlWithBackToParam} from '@src/ROUTES'; -import CONST from '@src/CONST'; import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; import StepScreenWrapper from './StepScreenWrapper'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; @@ -67,7 +67,10 @@ function IOURequestStepCurrency({ // are only able to handle one backTo param at a time and the user needs to go back to the amount page before going back // to the confirmation page if (pageIndex === 'confirm') { - const routeToAmountPageWithConfirmationAsBackTo = getUrlWithBackToParam(backTo, `/${ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)}`); + const routeToAmountPageWithConfirmationAsBackTo = getUrlWithBackToParam( + backTo, + `/${ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)}`, + ); Navigation.goBack(routeToAmountPageWithConfirmationAsBackTo); return; } From d65a8f306201d12577c65d04f50754003130b377 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 27 Mar 2024 13:58:25 +0800 Subject: [PATCH 042/102] don't optimistically add the violation if it's a partial transaction --- src/libs/actions/IOU.ts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index b67e44fcf5ad..51656e2ea405 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -807,16 +807,18 @@ function buildOnyxDataForMoneyRequest( if (!policy || !PolicyUtils.isPaidGroupPolicy(policy)) { return [optimisticData, successData, failureData]; } + const isPartialTransaction = TransactionUtils.isMerchantMissing(transaction) && TransactionUtils.isAmountMissing(transaction); + if (!isPartialTransaction) { + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTagList ?? {}, !!policy.requiresCategory, policyCategories ?? {}); - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTagList ?? {}, !!policy.requiresCategory, policyCategories ?? {}); - - if (violationsOnyxData) { - optimisticData.push(violationsOnyxData); - failureData.push({ - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, - value: [], - }); + if (violationsOnyxData) { + optimisticData.push(violationsOnyxData); + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, + value: [], + }); + } } return [optimisticData, successData, failureData]; @@ -1698,7 +1700,8 @@ function getUpdateMoneyRequestParams( }); } - if (policy && PolicyUtils.isPaidGroupPolicy(policy) && updatedTransaction) { + const isPartialTransaction = TransactionUtils.isMerchantMissing(updatedTransaction) && TransactionUtils.isAmountMissing(updatedTransaction); + if (policy && PolicyUtils.isPaidGroupPolicy(policy) && updatedTransaction && !isPartialTransaction) { const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; optimisticData.push( ViolationsUtils.getViolationsOnyxData( From f9fc96d8a2a857834c1a82561c70250ddd78b600 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 27 Mar 2024 18:31:45 +0800 Subject: [PATCH 043/102] move the partial transaciton check to getViolationsOnyxData --- src/libs/Violations/ViolationsUtils.ts | 8 +++- src/libs/actions/IOU.ts | 66 +++++++++++++------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index fe2e5af537a7..be8fe79445dc 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -2,6 +2,7 @@ import reject from 'lodash/reject'; import Onyx from 'react-native-onyx'; import type {OnyxUpdate} from 'react-native-onyx'; import type {Phrase, PhraseParameters} from '@libs/Localize'; +import * as TransactionUtils from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -119,7 +120,12 @@ const ViolationsUtils = { policyTagList: PolicyTagList, policyRequiresCategories: boolean, policyCategories: PolicyCategories, - ): OnyxUpdate { + ): OnyxUpdate | null { + const isPartialTransaction = TransactionUtils.isMerchantMissing(updatedTransaction) && TransactionUtils.isAmountMissing(updatedTransaction); + if (isPartialTransaction) { + return null; + } + let newTransactionViolations = [...transactionViolations]; // Calculate client-side category violations diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 51656e2ea405..f6bd73afd082 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -807,18 +807,16 @@ function buildOnyxDataForMoneyRequest( if (!policy || !PolicyUtils.isPaidGroupPolicy(policy)) { return [optimisticData, successData, failureData]; } - const isPartialTransaction = TransactionUtils.isMerchantMissing(transaction) && TransactionUtils.isAmountMissing(transaction); - if (!isPartialTransaction) { - const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTagList ?? {}, !!policy.requiresCategory, policyCategories ?? {}); - if (violationsOnyxData) { - optimisticData.push(violationsOnyxData); - failureData.push({ - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, - value: [], - }); - } + const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(transaction, [], !!policy.requiresTag, policyTagList ?? {}, !!policy.requiresCategory, policyCategories ?? {}); + + if (violationsOnyxData) { + optimisticData.push(violationsOnyxData); + failureData.push({ + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`, + value: [], + }); } return [optimisticData, successData, failureData]; @@ -1700,24 +1698,24 @@ function getUpdateMoneyRequestParams( }); } - const isPartialTransaction = TransactionUtils.isMerchantMissing(updatedTransaction) && TransactionUtils.isAmountMissing(updatedTransaction); - if (policy && PolicyUtils.isPaidGroupPolicy(policy) && updatedTransaction && !isPartialTransaction) { + if (policy && PolicyUtils.isPaidGroupPolicy(policy) && updatedTransaction) { const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; - optimisticData.push( - ViolationsUtils.getViolationsOnyxData( - updatedTransaction, - currentTransactionViolations, - !!policy.requiresTag, - policyTagList ?? {}, - !!policy.requiresCategory, - policyCategories ?? {}, - ), + const updatedViolationsOnyxData = ViolationsUtils.getViolationsOnyxData( + updatedTransaction, + currentTransactionViolations, + !!policy.requiresTag, + policyTagList ?? {}, + !!policy.requiresCategory, + policyCategories ?? {}, ); - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: currentTransactionViolations, - }); + if (updatedViolationsOnyxData) { + optimisticData.push(updatedViolationsOnyxData); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: currentTransactionViolations, + }); + } } // Reset the transaction thread to its original state @@ -3508,12 +3506,14 @@ function editRegularMoneyRequest( !!policy.requiresCategory, policyCategories, ); - optimisticData.push(updatedViolationsOnyxData); - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: currentTransactionViolations, - }); + if (updatedViolationsOnyxData) { + optimisticData.push(updatedViolationsOnyxData); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: currentTransactionViolations, + }); + } } // STEP 6: Call the API endpoint From bdcdc471543de25c3107e3e5c9c2996b21e60436 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 27 Mar 2024 18:37:25 +0800 Subject: [PATCH 044/102] null safety --- tests/unit/ViolationUtilsTest.ts | 40 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 354a90802077..4c9a2c344363 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -57,7 +57,7 @@ describe('getViolationsOnyxData', () => { {name: 'receiptRequired', type: 'violation'}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining(transactionViolations)); + expect(result?.value).toEqual(expect.arrayContaining(transactionViolations)); }); describe('policyRequiresCategories', () => { @@ -70,18 +70,18 @@ describe('getViolationsOnyxData', () => { it('should add missingCategory violation if no category is included', () => { transaction.category = undefined; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); + expect(result?.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); it('should add categoryOutOfPolicy violation when category is not in policy', () => { transaction.category = 'Bananas'; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); + expect(result?.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); }); it('should not include a categoryOutOfPolicy violation when category is in policy', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); + expect(result?.value).not.toContainEqual(categoryOutOfPolicyViolation); }); it('should add categoryOutOfPolicy violation to existing violations if they exist', () => { @@ -93,7 +93,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); + expect(result?.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); }); it('should add missingCategory violation to existing violations if they exist', () => { @@ -105,7 +105,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); + expect(result?.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); }); @@ -117,8 +117,8 @@ describe('getViolationsOnyxData', () => { it('should not add any violations when categories are not required', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).not.toContainEqual([categoryOutOfPolicyViolation]); - expect(result.value).not.toContainEqual([missingCategoryViolation]); + expect(result?.value).not.toContainEqual([categoryOutOfPolicyViolation]); + expect(result?.value).not.toContainEqual([missingCategoryViolation]); }); }); @@ -142,7 +142,7 @@ describe('getViolationsOnyxData', () => { it("shouldn't update the transactionViolations if the policy requires tags and the transaction has a tag from the policy", () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(transactionViolations); + expect(result?.value).toEqual(transactionViolations); }); it('should add a missingTag violation if none is provided and policy requires tags', () => { @@ -150,7 +150,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([{...missingTagViolation}])); + expect(result?.value).toEqual(expect.arrayContaining([{...missingTagViolation}])); }); it('should add a tagOutOfPolicy violation when policy requires tags and tag is not in the policy', () => { @@ -158,7 +158,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual([]); + expect(result?.value).toEqual([]); }); it('should add tagOutOfPolicy violation to existing violations if transaction has tag that is not in the policy', () => { @@ -170,7 +170,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([{...tagOutOfPolicyViolation}, ...transactionViolations])); + expect(result?.value).toEqual(expect.arrayContaining([{...tagOutOfPolicyViolation}, ...transactionViolations])); }); it('should add missingTag violation to existing violations if transaction does not have a tag', () => { @@ -182,7 +182,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(expect.arrayContaining([{...missingTagViolation}, ...transactionViolations])); + expect(result?.value).toEqual(expect.arrayContaining([{...missingTagViolation}, ...transactionViolations])); }); }); @@ -194,8 +194,8 @@ describe('getViolationsOnyxData', () => { it('should not add any violations when tags are not required', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).not.toContainEqual([tagOutOfPolicyViolation]); - expect(result.value).not.toContainEqual([missingTagViolation]); + expect(result?.value).not.toContainEqual([tagOutOfPolicyViolation]); + expect(result?.value).not.toContainEqual([missingTagViolation]); }); }); describe('policy has multi level tags', () => { @@ -248,31 +248,31 @@ describe('getViolationsOnyxData', () => { // Test case where transaction has no tags let result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual([someTagLevelsRequiredViolation]); + expect(result?.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has 1 tag transaction.tag = 'Accounting'; someTagLevelsRequiredViolation.data = {errorIndexes: [1, 2]}; result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual([someTagLevelsRequiredViolation]); + expect(result?.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has 2 tags transaction.tag = 'Accounting::Project1'; someTagLevelsRequiredViolation.data = {errorIndexes: [1]}; result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual([someTagLevelsRequiredViolation]); + expect(result?.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has all tags transaction.tag = 'Accounting:Africa:Project1'; result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual([]); + expect(result?.value).toEqual([]); }); it('should return tagOutOfPolicy when a tag is not enabled in the policy but is set in the transaction', () => { policyTags.Department.tags.Accounting.enabled = false; transaction.tag = 'Accounting:Africa:Project1'; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); const violation = {...tagOutOfPolicyViolation, data: {tagName: 'Department'}}; - expect(result.value).toEqual([violation]); + expect(result?.value).toEqual([violation]); }); }); }); From 39b8c46885695e70983ea14d0e4177835d0c9f80 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 27 Mar 2024 18:39:36 +0800 Subject: [PATCH 045/102] add test --- tests/unit/ViolationUtilsTest.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 4c9a2c344363..7da8352cdb53 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -60,6 +60,16 @@ describe('getViolationsOnyxData', () => { expect(result?.value).toEqual(expect.arrayContaining(transactionViolations)); }); + it('should not add violation when the transaction is partial', () => { + const partialTransaction = {...transaction, amount: 0, merchant: ''}; + transactionViolations = [ + {name: 'duplicatedTransaction', type: 'violation'}, + {name: 'receiptRequired', type: 'violation'}, + ]; + const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); + expect(result).toBeNull(); + }); + describe('policyRequiresCategories', () => { beforeEach(() => { policyRequiresCategories = true; From 421f10855c3de0f7e596d0f77ffcffde624a18c3 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 27 Mar 2024 17:50:59 +0700 Subject: [PATCH 046/102] use type utils and useMemo --- src/components/BlockingViews/BlockingView.tsx | 65 +++++++++---------- .../LHNOptionsList/LHNOptionsList.tsx | 4 +- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index 3733075c2025..57c8b9c16eb6 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,7 +1,8 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import type {ImageSourcePropType, StyleProp, ViewStyle, WebStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; +import type {MergeExclusive} from 'type-fest'; import AutoEmailLink from '@components/AutoEmailLink'; import Icon from '@components/Icon'; import Lottie from '@components/Lottie'; @@ -14,27 +15,19 @@ import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; import type {TranslationPaths} from '@src/languages/types'; -type RequiredIllustrationProps = - | { - /** Expensicon for the page */ - icon: React.FC | ImageSourcePropType; - - /** - * Animation for the page - * If icon is provided, animation is not required - */ - animation?: DotLottieAnimation; - } - | { - /** Animation for the page */ - animation: DotLottieAnimation; - - /** - * Expensicon for the page - * If animation is provided, icon is not required - */ - icon?: React.FC | ImageSourcePropType; - }; +/** + * This page requires either an icon or an animation, but not both + */ +type RequiredIllustrationProps = MergeExclusive< + { + /** Expensicon for the page */ + icon: React.FC | ImageSourcePropType; + }, + { + /** Animation for the page */ + animation: DotLottieAnimation; + } +>; type BlockingViewProps = RequiredIllustrationProps & { /** Color for the icon (should be from theme) */ @@ -71,7 +64,7 @@ type BlockingViewProps = RequiredIllustrationProps & { animationWebStyle?: WebStyle; /** Render custom subtitle */ - renderCustomSubtitle?: () => React.ReactElement; + CustomSubtitle?: React.ReactElement; }; function BlockingView({ @@ -88,12 +81,13 @@ function BlockingView({ shouldEmbedLinkWithSubtitle = false, animationStyles = [], animationWebStyle = {}, - renderCustomSubtitle, + CustomSubtitle, }: BlockingViewProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - function renderContent() { - return ( + + const subtitleText: React.ReactElement = useMemo( + () => ( <> ) : null} - ); - } + ), + [styles, subtitle, shouldShowLink, linkKey, onLinkPress, translate], + ); - function renderSubtitle() { - if (renderCustomSubtitle) { - return renderCustomSubtitle(); + const subtitleContent: React.ReactElement = useMemo(() => { + if (CustomSubtitle) { + return CustomSubtitle; } return shouldEmbedLinkWithSubtitle ? ( - {renderContent()} + {subtitleText} ) : ( - {renderContent()} + {subtitleText} ); - } + }, [styles, subtitleText, shouldEmbedLinkWithSubtitle, CustomSubtitle]); return ( @@ -144,7 +139,7 @@ function BlockingView({ {title} - {renderSubtitle()} + {subtitleContent} ); diff --git a/src/components/LHNOptionsList/LHNOptionsList.tsx b/src/components/LHNOptionsList/LHNOptionsList.tsx index c8cb12680c28..e241f65bc646 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.tsx +++ b/src/components/LHNOptionsList/LHNOptionsList.tsx @@ -66,7 +66,7 @@ function LHNOptionsList({ onFirstItemRendered(); }, [onFirstItemRendered]); - const renderEmptyLHNSubtitle = useCallback( + const emptyLHNSubtitle = useMemo( () => ( ) : ( Date: Wed, 27 Mar 2024 21:27:04 +0200 Subject: [PATCH 047/102] nested quote for editing message --- package-lock.json | 25 +++++++++++++------------ package.json | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61d6a27821cd..2c6f56889ac4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#615f4a8662cd1abea9fdeee4d04847197c5e36ae", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#1247a822328011083a13abc769ba1911c3586338", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", @@ -23087,9 +23087,9 @@ } }, "node_modules/classnames": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.4.0.tgz", - "integrity": "sha512-lWxiIlphgAhTLN657pwU/ofFxsUTOWc2CRIFeoV5st0MGRJHStUnWIUJgDHxjUO/F0mXzGufXIM4Lfu/8h+MpA==" + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.0.tgz", + "integrity": "sha512-FQuRlyKinxrb5gwJlfVASbSrDlikDJ07426TrfPsdGLvtochowmkbnSFdQGJ2aoXrSetq5KqGV9emvWpy+91xA==" }, "node_modules/clean-css": { "version": "5.3.2", @@ -27370,20 +27370,20 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#615f4a8662cd1abea9fdeee4d04847197c5e36ae", - "integrity": "sha512-k/SmW3EBR+gxFkJP/59LJsmBKjnKR07XS30yk/GkQ0lIfyYkNmFJ0dWm/S/54ezFweezR7MDaQ3zGc45Mb/U5A==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#1247a822328011083a13abc769ba1911c3586338", + "integrity": "sha512-YqFwbL3B5XzdQ+4wmZqWcdAbRerGvP0ZvcJV2YTHETxlZdjc39AZ2gviaJhqmz8E4kTQIfgO6ii3n4bWSYKt5A==", "license": "MIT", "dependencies": { - "classnames": "2.4.0", + "classnames": "2.5.0", "clipboard": "2.0.11", - "html-entities": "^2.4.0", + "html-entities": "^2.5.2", "jquery": "3.6.0", "localforage": "^1.10.0", "lodash": "4.17.21", "prop-types": "15.8.1", "react": "16.12.0", "react-dom": "16.12.0", - "semver": "^7.5.2", + "semver": "^7.6.0", "simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5", "ua-parser-js": "^1.0.37", "underscore": "1.13.6" @@ -29528,7 +29528,9 @@ } }, "node_modules/html-entities": { - "version": "2.4.0", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "funding": [ { "type": "github", @@ -29538,8 +29540,7 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ], - "license": "MIT" + ] }, "node_modules/html-escaper": { "version": "2.0.2", diff --git a/package.json b/package.json index 92a6b9cde5e1..68268f737c7d 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "date-fns-tz": "^2.0.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#615f4a8662cd1abea9fdeee4d04847197c5e36ae", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#1247a822328011083a13abc769ba1911c3586338", "expo": "^50.0.3", "expo-av": "~13.10.4", "expo-image": "1.10.1", From cdecb00c71b616277d3cb1562d4bb57c0b4b7207 Mon Sep 17 00:00:00 2001 From: Matt Allen Date: Wed, 27 Mar 2024 17:20:28 -0700 Subject: [PATCH 048/102] Update HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md Added at the end Please include your GitHub username and a link to the PRs you've authored that have been merged. ie. https://github.com/Expensify/App/pulls?q=is%3Apr+author%3Aparasharrajat+is%3Amerged --- contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md b/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md index 1e950bbf1a63..932dcc8d5e20 100644 --- a/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md +++ b/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md @@ -24,4 +24,4 @@ C+ are contributors who are experienced at working with Expensify and have gaine ## How to join? -Email contributors@expensify.com and include "C+ Team Application" in the subject line if you’re interested in joining. +Email contributors@expensify.com and include "C+ Team Application" in the subject line if you’re interested in joining. Please include your GitHub username and a link to the PRs you've authored that have been merged. ie. https://github.com/Expensify/App/pulls?q=is%3Apr+author%3Aparasharrajat+is%3Amerged From 8be26fc4de122876da04d41ab30d84ec0695f2c4 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 28 Mar 2024 10:17:02 +0700 Subject: [PATCH 049/102] add param and using CONST --- src/libs/Navigation/types.ts | 1 + src/libs/actions/IOU.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index de1ed96579ce..dd41bec40d6e 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -334,6 +334,7 @@ type MoneyRequestNavigatorParamList = { reportID: string; }; [SCREENS.MONEY_REQUEST.CURRENCY]: { + action: ValueOf; iouType: string; reportID: string; currency: string; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5b009cfe8a7f..8db9dc698bfa 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5006,7 +5006,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, '1', report?.reportID ?? '1')); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report?.reportID ?? '1')); return; } @@ -5022,7 +5022,7 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); setMoneyRequestParticipants(participants); } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, '1', report.reportID)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID)); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); From 2c9efa0dca63e63600452a45891bc3f01ec0e74f Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 28 Mar 2024 11:22:01 +0800 Subject: [PATCH 050/102] update partial merchant condition --- src/libs/Violations/ViolationsUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index be8fe79445dc..c707b9d45451 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -121,7 +121,7 @@ const ViolationsUtils = { policyRequiresCategories: boolean, policyCategories: PolicyCategories, ): OnyxUpdate | null { - const isPartialTransaction = TransactionUtils.isMerchantMissing(updatedTransaction) && TransactionUtils.isAmountMissing(updatedTransaction); + const isPartialTransaction = TransactionUtils.isPartialMerchant(TransactionUtils.getMerchant(updatedTransaction)) && TransactionUtils.isAmountMissing(updatedTransaction); if (isPartialTransaction) { return null; } From 3a5827ff56cd0622f093e5195019e8ca6cc5c88d Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 28 Mar 2024 11:26:20 +0800 Subject: [PATCH 051/102] fix test case --- tests/unit/ViolationUtilsTest.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 7da8352cdb53..10c08266a1e2 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -1,6 +1,7 @@ import {beforeEach} from '@jest/globals'; import Onyx from 'react-native-onyx'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PolicyCategories, PolicyTagList, Transaction, TransactionViolation} from '@src/types/onyx'; @@ -61,7 +62,7 @@ describe('getViolationsOnyxData', () => { }); it('should not add violation when the transaction is partial', () => { - const partialTransaction = {...transaction, amount: 0, merchant: ''}; + const partialTransaction = {...transaction, amount: 0, merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT}; transactionViolations = [ {name: 'duplicatedTransaction', type: 'violation'}, {name: 'receiptRequired', type: 'violation'}, From 13770a7117c5297b63f1ab12c2e675fb790634ea Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 28 Mar 2024 10:35:40 +0700 Subject: [PATCH 052/102] lint fix --- src/libs/actions/IOU.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f5220e758ff3..446c0ce30b43 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4999,7 +4999,9 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report?.reportID ?? '1')); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report?.reportID ?? '1'), + ); return; } @@ -5015,7 +5017,9 @@ function navigateToNextPage(iou: OnyxEntry, iouType: string, repo : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); setMoneyRequestParticipants(participants); } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID)); + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID), + ); return; } Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); From 030593a8e34c4bd9385ee8e7e86e84d8868ee170 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 28 Mar 2024 11:31:54 +0700 Subject: [PATCH 053/102] type inference --- src/components/BlockingViews/BlockingView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index 57c8b9c16eb6..ba660c9a9ecd 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -86,7 +86,7 @@ function BlockingView({ const styles = useThemeStyles(); const {translate} = useLocalize(); - const subtitleText: React.ReactElement = useMemo( + const subtitleText = useMemo( () => ( <> { + const subtitleContent = useMemo(() => { if (CustomSubtitle) { return CustomSubtitle; } From 0ef11c2c606b7c9fb74eb8136c93f5313d65c4cc Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 28 Mar 2024 14:40:02 +0700 Subject: [PATCH 054/102] fix type --- src/libs/Navigation/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c6a3e04b0eb2..fc82b2f0dea5 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -342,12 +342,12 @@ type MoneyRequestNavigatorParamList = { reportID: string; }; [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: { + action: ValueOf; iouType: string; transactionID: string; reportID: string; }; [SCREENS.MONEY_REQUEST.CURRENCY]: { - action: ValueOf; iouType: string; reportID: string; currency: string; From 313524685bde1b8916b33e63ef385932f9d99dbd Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 28 Mar 2024 17:38:10 +0700 Subject: [PATCH 055/102] fix lint --- src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index ef1fc3c2dfb0..de3552199626 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -86,7 +86,6 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../../pages/iou/request/step/IOURequestStepScan').default as React.ComponentType, [SCREENS.MONEY_REQUEST.STEP_TAG]: () => require('../../../../pages/iou/request/step/IOURequestStepTag').default as React.ComponentType, [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: () => require('../../../../pages/iou/request/step/IOURequestStepWaypoint').default as React.ComponentType, - [SCREENS.MONEY_REQUEST.AMOUNT]: () => require('../../../../pages/iou/steps/NewRequestAmountPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.PARTICIPANTS]: () => require('../../../../pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CONFIRMATION]: () => require('../../../../pages/iou/steps/MoneyRequestConfirmPage').default as React.ComponentType, [SCREENS.MONEY_REQUEST.CURRENCY]: () => require('../../../../pages/iou/IOUCurrencySelection').default as React.ComponentType, From a32c7ee49b9fe7f524f552a4b8d3dd3e35d01097 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 28 Mar 2024 18:50:52 +0800 Subject: [PATCH 056/102] create withTransitionEnd hook --- src/components/withTransitionEnd.tsx | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/components/withTransitionEnd.tsx diff --git a/src/components/withTransitionEnd.tsx b/src/components/withTransitionEnd.tsx new file mode 100644 index 000000000000..0047b60efcc5 --- /dev/null +++ b/src/components/withTransitionEnd.tsx @@ -0,0 +1,39 @@ +import {useNavigation} from '@react-navigation/native'; +import type {StackNavigationProp} from '@react-navigation/stack'; +import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; +import React, {useEffect, useState} from 'react'; +import getComponentDisplayName from '@libs/getComponentDisplayName'; +import type {RootStackParamList} from '@libs/Navigation/types'; + +type WithTransitionEndProps = {didScreenTransitionEnd: boolean}; + +export default function (WrappedComponent: ComponentType>): React.ComponentType> { + function WithTransitionEnd(props: TProps, ref: ForwardedRef) { + const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); + const navigation = useNavigation>(); + + useEffect(() => { + const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => { + setDidScreenTransitionEnd(true); + }); + + return unsubscribeTransitionEnd; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + ); + } + + WithTransitionEnd.displayName = `WithTransitionEnd(${getComponentDisplayName(WrappedComponent)})`; + + return WithTransitionEnd; +} + +export type {WithTransitionEndProps}; From bb40f856185258c5fc16561754d28ae6ebcef8aa Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 28 Mar 2024 18:51:09 +0800 Subject: [PATCH 057/102] use didScreenTransitionEnd from withTransitionEnd HOC --- src/pages/RoomInvitePage.tsx | 37 +++++--------- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 44 ++++++++-------- src/pages/workspace/WorkspaceInvitePage.tsx | 51 ++++++++----------- 3 files changed, 56 insertions(+), 76 deletions(-) diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index d0ea55a923e7..35c4759cdaad 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -1,5 +1,3 @@ -import {useNavigation} from '@react-navigation/native'; -import type {StackNavigationProp} from '@react-navigation/stack'; import Str from 'expensify-common/lib/str'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {SectionListData} from 'react-native'; @@ -13,12 +11,13 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import type {Section} from '@components/SelectionList/types'; import UserListItem from '@components/SelectionList/UserListItem'; +import withTransitionEnd from '@components/withTransitionEnd'; +import type {WithTransitionEndProps} from '@components/withTransitionEnd'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as LoginUtils from '@libs/LoginUtils'; import Navigation from '@libs/Navigation/Navigation'; -import type {RootStackParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; @@ -39,19 +38,17 @@ type RoomInvitePageOnyxProps = { personalDetails: OnyxEntry; }; -type RoomInvitePageProps = RoomInvitePageOnyxProps & WithReportOrNotFoundProps; +type RoomInvitePageProps = RoomInvitePageOnyxProps & WithReportOrNotFoundProps & WithTransitionEndProps; type Sections = Array>>; -function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePageProps) { +function RoomInvitePage({betas, personalDetails, report, policies, didScreenTransitionEnd}: RoomInvitePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [searchTerm, setSearchTerm] = useState(''); const [selectedOptions, setSelectedOptions] = useState([]); const [invitePersonalDetails, setInvitePersonalDetails] = useState([]); const [userToInvite, setUserToInvite] = useState(null); - const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); - const navigation: StackNavigationProp = useNavigation(); useEffect(() => { setSearchTerm(SearchInputManager.searchInput); @@ -88,18 +85,6 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to recalculate when selectedOptions change }, [personalDetails, betas, searchTerm, excludedUsers]); - useEffect(() => { - const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => { - setDidScreenTransitionEnd(true); - }); - - return () => { - unsubscribeTransitionEnd(); - }; - // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const sections = useMemo(() => { const sectionsArr: Sections = []; let indexOffset = 0; @@ -266,10 +251,12 @@ function RoomInvitePage({betas, personalDetails, report, policies}: RoomInvitePa RoomInvitePage.displayName = 'RoomInvitePage'; -export default withReportOrNotFound()( - withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - })(RoomInvitePage), +export default withTransitionEnd( + withReportOrNotFound()( + withOnyx({ + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + })(RoomInvitePage), + ), ); diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 0ffb33b7590b..a8ae93dd53c9 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -14,6 +14,8 @@ import type {ListItem} from '@components/SelectionList/types'; import UserListItem from '@components/SelectionList/UserListItem'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; +import withTransitionEnd from '@components/withTransitionEnd'; +import type {WithTransitionEndProps} from '@components/withTransitionEnd'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; @@ -41,7 +43,7 @@ type UseOptions = { reports: OnyxCollection; }; -type TaskAssigneeSelectorModalProps = TaskAssigneeSelectorModalOnyxProps & WithCurrentUserPersonalDetailsProps; +type TaskAssigneeSelectorModalProps = TaskAssigneeSelectorModalOnyxProps & WithCurrentUserPersonalDetailsProps & WithTransitionEndProps; function useOptions({reports}: UseOptions) { const allPersonalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; @@ -90,7 +92,7 @@ function useOptions({reports}: UseOptions) { return {...options, isLoading, searchValue, debouncedSearchValue, setSearchValue}; } -function TaskAssigneeSelectorModal({reports, task}: TaskAssigneeSelectorModalProps) { +function TaskAssigneeSelectorModal({reports, task, didScreenTransitionEnd}: TaskAssigneeSelectorModalProps) { const styles = useThemeStyles(); const route = useRoute>(); const {translate} = useLocalize(); @@ -212,26 +214,24 @@ function TaskAssigneeSelectorModal({reports, task}: TaskAssigneeSelectorModalPro includeSafeAreaPaddingBottom={false} testID={TaskAssigneeSelectorModal.displayName} > - {({didScreenTransitionEnd}) => ( - - + + + - - - - - )} + + ); } @@ -247,4 +247,4 @@ const TaskAssigneeSelectorModalWithOnyx = withOnyx; }; -type WorkspaceInvitePageProps = WithPolicyAndFullscreenLoadingProps & WorkspaceInvitePageOnyxProps & StackScreenProps; +type WorkspaceInvitePageProps = WithPolicyAndFullscreenLoadingProps & + WithTransitionEndProps & + WorkspaceInvitePageOnyxProps & + StackScreenProps; function WorkspaceInvitePage({ route, @@ -59,6 +63,7 @@ function WorkspaceInvitePage({ invitedEmailsToAccountIDsDraft, policy, isLoadingReportData = true, + didScreenTransitionEnd, }: WorkspaceInvitePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -66,8 +71,6 @@ function WorkspaceInvitePage({ const [selectedOptions, setSelectedOptions] = useState([]); const [personalDetails, setPersonalDetails] = useState([]); const [usersToInvite, setUsersToInvite] = useState([]); - const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); - const navigation = useNavigation>(); const openWorkspaceInvitePage = () => { const policyMemberEmailsToAccountIDs = PolicyUtils.getMemberAccountIDsForWorkspace(policyMembers, personalDetailsProp); Policy.openWorkspaceInvitePage(route.params.policyID, Object.keys(policyMemberEmailsToAccountIDs)); @@ -86,18 +89,6 @@ function WorkspaceInvitePage({ // eslint-disable-next-line react-hooks/exhaustive-deps -- policyID changes remount the component }, []); - useEffect(() => { - const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => { - setDidScreenTransitionEnd(true); - }); - - return () => { - unsubscribeTransitionEnd(); - }; - // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - useNetwork({onReconnect: openWorkspaceInvitePage}); const excludedUsers = useMemo(() => PolicyUtils.getIneligibleInvitees(policyMembers, personalDetailsProp), [policyMembers, personalDetailsProp]); @@ -342,16 +333,18 @@ function WorkspaceInvitePage({ WorkspaceInvitePage.displayName = 'WorkspaceInvitePage'; -export default withPolicyAndFullscreenLoading( - withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - betas: { - key: ONYXKEYS.BETAS, - }, - invitedEmailsToAccountIDsDraft: { - key: ({route}) => `${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${route.params.policyID.toString()}`, - }, - })(WorkspaceInvitePage), +export default withTransitionEnd( + withPolicyAndFullscreenLoading( + withOnyx({ + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + invitedEmailsToAccountIDsDraft: { + key: ({route}) => `${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${route.params.policyID.toString()}`, + }, + })(WorkspaceInvitePage), + ), ); From 77c05c9b02ebbda60f78786afab7b9ffb9832b29 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 28 Mar 2024 19:01:07 +0800 Subject: [PATCH 058/102] add missing forwardRef --- src/components/withTransitionEnd.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/withTransitionEnd.tsx b/src/components/withTransitionEnd.tsx index 0047b60efcc5..b00e0a9f4f34 100644 --- a/src/components/withTransitionEnd.tsx +++ b/src/components/withTransitionEnd.tsx @@ -33,7 +33,7 @@ export default function (WrappedComponent: ComponentType Date: Fri, 29 Mar 2024 02:36:44 +0700 Subject: [PATCH 059/102] Add conditional required type for BlockingView --- src/components/BlockingViews/BlockingView.tsx | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index ba660c9a9ecd..363342778fc0 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -15,24 +15,7 @@ import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; import type {TranslationPaths} from '@src/languages/types'; -/** - * This page requires either an icon or an animation, but not both - */ -type RequiredIllustrationProps = MergeExclusive< - { - /** Expensicon for the page */ - icon: React.FC | ImageSourcePropType; - }, - { - /** Animation for the page */ - animation: DotLottieAnimation; - } ->; - -type BlockingViewProps = RequiredIllustrationProps & { - /** Color for the icon (should be from theme) */ - iconColor?: string; - +type BaseBlockingViewProps = { /** Title message below the icon */ title: string; @@ -45,28 +28,44 @@ type BlockingViewProps = RequiredIllustrationProps & { /** Whether we should show a link to navigate elsewhere */ shouldShowLink?: boolean; + /** Function to call when pressing the navigation link */ + onLinkPress?: () => void; + + /** Whether we should embed the link with subtitle */ + shouldEmbedLinkWithSubtitle?: boolean; + + /** Render custom subtitle */ + CustomSubtitle?: React.ReactElement; +}; + +type BlockingViewIconProps = { + /** Expensicon for the page */ + icon: React.FC | ImageSourcePropType; + /** The custom icon width */ iconWidth?: number; /** The custom icon height */ iconHeight?: number; - /** Function to call when pressing the navigation link */ - onLinkPress?: () => void; + /** Color for the icon (should be from theme) */ + iconColor?: string; +}; - /** Whether we should embed the link with subtitle */ - shouldEmbedLinkWithSubtitle?: boolean; +type BlockingViewAnimationProps = { + /** Animation for the page */ + animation: DotLottieAnimation; /** Style for the animation */ animationStyles?: StyleProp; /** Style for the animation on web */ animationWebStyle?: WebStyle; - - /** Render custom subtitle */ - CustomSubtitle?: React.ReactElement; }; +// This page requires either an icon or an animation, but not both +type BlockingViewProps = BaseBlockingViewProps & MergeExclusive; + function BlockingView({ animation, icon, From fe4736ef3b2c9ca4a47f1a47680940d9886ac305 Mon Sep 17 00:00:00 2001 From: gaber Date: Thu, 28 Mar 2024 21:46:25 +0200 Subject: [PATCH 060/102] clean MentionUserRenderer.tsx mentionDisplayText --- .../HTMLRenderers/MentionUserRenderer.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx index d3376a798a8b..0c7c82534bbb 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.tsx @@ -35,12 +35,12 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona const htmlAttributeAccountID = tnode.attributes.accountid; let accountID: number; - let displayNameOrLogin: string; + let mentionDisplayText: string; let navigationRoute: Route; const tnodeClone = cloneDeep(tnode); - const getMentionDisplayText = (displayText: string, userAccountID: string, userLogin = '') => { + const getShortMentionIfFound = (displayText: string, userAccountID: string, userLogin = '') => { // If the userAccountID does not exist, this is an email-based mention so the displayText must be an email. // If the userAccountID exists but userLogin is different from displayText, this means the displayText is either user display name, Hidden, or phone number, in which case we should return it as is. if (userAccountID && userLogin !== displayText) { @@ -59,18 +59,18 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona if (!isEmpty(htmlAttribAccountID)) { const user = personalDetails[htmlAttribAccountID]; accountID = parseInt(htmlAttribAccountID, 10); - displayNameOrLogin = LocalePhoneNumber.formatPhoneNumber(user?.login ?? '') || PersonalDetailsUtils.getDisplayNameOrDefault(user); - displayNameOrLogin = Str.removeSMSDomain(getMentionDisplayText(displayNameOrLogin, htmlAttributeAccountID, user?.login ?? '')); + mentionDisplayText = LocalePhoneNumber.formatPhoneNumber(user?.login ?? '') || PersonalDetailsUtils.getDisplayNameOrDefault(user); + mentionDisplayText = getShortMentionIfFound(mentionDisplayText, htmlAttributeAccountID, user?.login ?? ''); navigationRoute = ROUTES.PROFILE.getRoute(htmlAttribAccountID); } else if ('data' in tnodeClone && !isEmptyObject(tnodeClone.data)) { // We need to remove the LTR unicode and leading @ from data as it is not part of the login - displayNameOrLogin = tnodeClone.data.replace(CONST.UNICODE.LTR, '').slice(1); + mentionDisplayText = tnodeClone.data.replace(CONST.UNICODE.LTR, '').slice(1); // We need to replace tnode.data here because we will pass it to TNodeChildrenRenderer below - asMutable(tnodeClone).data = tnodeClone.data.replace(displayNameOrLogin, Str.removeSMSDomain(getMentionDisplayText(displayNameOrLogin, htmlAttributeAccountID))); + asMutable(tnodeClone).data = tnodeClone.data.replace(mentionDisplayText, Str.removeSMSDomain(getShortMentionIfFound(mentionDisplayText, htmlAttributeAccountID))); - accountID = PersonalDetailsUtils.getAccountIDsByLogins([displayNameOrLogin])?.[0]; - navigationRoute = ROUTES.DETAILS.getRoute(displayNameOrLogin); - displayNameOrLogin = Str.removeSMSDomain(displayNameOrLogin); + accountID = PersonalDetailsUtils.getAccountIDsByLogins([mentionDisplayText])?.[0]; + navigationRoute = ROUTES.DETAILS.getRoute(mentionDisplayText); + mentionDisplayText = Str.removeSMSDomain(mentionDisplayText); } else { // If neither an account ID or email is provided, don't render anything return null; @@ -97,7 +97,7 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona - {htmlAttribAccountID ? `@${displayNameOrLogin}` : } + {htmlAttribAccountID ? `@${mentionDisplayText}` : } From 7e3e4f99134b6c6152acbca83b85c287bbc47e35 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 29 Mar 2024 04:01:06 +0700 Subject: [PATCH 061/102] Fix storybook test --- .storybook/webpack.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.storybook/webpack.config.ts b/.storybook/webpack.config.ts index 2fdae76c1268..c427513d534e 100644 --- a/.storybook/webpack.config.ts +++ b/.storybook/webpack.config.ts @@ -45,6 +45,10 @@ const webpackConfig = ({config}: {config: Configuration}) => { ...custom.resolve.alias, }; + // We can ignore the "module not installed" warning from lottie-react-native + // because we are not using the library for JSON format of Lottie animations. + config.ignoreWarnings = [{module: new RegExp('node_modules/lottie-react-native/lib/module/LottieView/index.web.js')}]; + // Necessary to overwrite the values in the existing DefinePlugin hardcoded to the Config staging values const definePluginIndex = config.plugins.findIndex((plugin) => plugin instanceof DefinePlugin); if (definePluginIndex !== -1 && config.plugins[definePluginIndex] instanceof DefinePlugin) { From a574a3915e87b3b21658327042fcc27201ddc44a Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Fri, 29 Mar 2024 05:51:59 +0530 Subject: [PATCH 062/102] introduce new translations --- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index c3ad6d82d6b2..8fd1f89443b1 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -516,7 +516,7 @@ export default { asCopilot: 'as copilot for', }, mentionSuggestions: { - hereAlternateText: 'Notify everyone online in this room', + hereAlternateText: 'Notify everyone in this conversation', }, newMessages: 'New messages', reportTypingIndicator: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 78b80adb16d4..18b5958fabe6 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -512,7 +512,7 @@ export default { asCopilot: 'como copiloto de', }, mentionSuggestions: { - hereAlternateText: 'Notificar a todos los que estén en linea de esta sala', + hereAlternateText: 'Notificar a todos en esta conversación', }, newMessages: 'Mensajes nuevos', reportTypingIndicator: { From 349c11d21f996a4dd61a4964d4fa6873906e541a Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Fri, 29 Mar 2024 06:08:58 +0530 Subject: [PATCH 063/102] fix screens --- .../Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 4ec955784d92..95233bfed079 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -19,9 +19,6 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.PROFILE.ADDRESS, SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, SCREENS.SETTINGS.SHARE_CODE, - SCREENS.SETTINGS.EXIT_SURVEY.REASON, - SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, - SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, ], [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], [SCREENS.SETTINGS.WALLET.ROOT]: [ From 0612ffd05ba26b5d6c346cd9a99ecf556090f69c Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Fri, 29 Mar 2024 15:09:51 +0800 Subject: [PATCH 064/102] return current violation if it's a partial transaction --- src/libs/Violations/ViolationsUtils.ts | 8 +++-- src/libs/actions/IOU.ts | 43 ++++++++++++-------------- tests/unit/ViolationUtilsTest.ts | 42 ++++++++++++------------- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index c707b9d45451..0d24c3bd2757 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -120,10 +120,14 @@ const ViolationsUtils = { policyTagList: PolicyTagList, policyRequiresCategories: boolean, policyCategories: PolicyCategories, - ): OnyxUpdate | null { + ): OnyxUpdate { const isPartialTransaction = TransactionUtils.isPartialMerchant(TransactionUtils.getMerchant(updatedTransaction)) && TransactionUtils.isAmountMissing(updatedTransaction); if (isPartialTransaction) { - return null; + return { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${updatedTransaction.transactionID}`, + value: transactionViolations, + }; } let newTransactionViolations = [...transactionViolations]; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f6bd73afd082..b67e44fcf5ad 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -1700,22 +1700,21 @@ function getUpdateMoneyRequestParams( if (policy && PolicyUtils.isPaidGroupPolicy(policy) && updatedTransaction) { const currentTransactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? []; - const updatedViolationsOnyxData = ViolationsUtils.getViolationsOnyxData( - updatedTransaction, - currentTransactionViolations, - !!policy.requiresTag, - policyTagList ?? {}, - !!policy.requiresCategory, - policyCategories ?? {}, + optimisticData.push( + ViolationsUtils.getViolationsOnyxData( + updatedTransaction, + currentTransactionViolations, + !!policy.requiresTag, + policyTagList ?? {}, + !!policy.requiresCategory, + policyCategories ?? {}, + ), ); - if (updatedViolationsOnyxData) { - optimisticData.push(updatedViolationsOnyxData); - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: currentTransactionViolations, - }); - } + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: currentTransactionViolations, + }); } // Reset the transaction thread to its original state @@ -3506,14 +3505,12 @@ function editRegularMoneyRequest( !!policy.requiresCategory, policyCategories, ); - if (updatedViolationsOnyxData) { - optimisticData.push(updatedViolationsOnyxData); - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: currentTransactionViolations, - }); - } + optimisticData.push(updatedViolationsOnyxData); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: currentTransactionViolations, + }); } // STEP 6: Call the API endpoint diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 10c08266a1e2..08d7e8cd3d08 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -58,7 +58,7 @@ describe('getViolationsOnyxData', () => { {name: 'receiptRequired', type: 'violation'}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining(transactionViolations)); + expect(result.value).toEqual(expect.arrayContaining(transactionViolations)); }); it('should not add violation when the transaction is partial', () => { @@ -68,7 +68,7 @@ describe('getViolationsOnyxData', () => { {name: 'receiptRequired', type: 'violation'}, ]; const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result).toBeNull(); + expect(result.value).toEqual(transactionViolations); }); describe('policyRequiresCategories', () => { @@ -81,18 +81,18 @@ describe('getViolationsOnyxData', () => { it('should add missingCategory violation if no category is included', () => { transaction.category = undefined; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); + expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); it('should add categoryOutOfPolicy violation when category is not in policy', () => { transaction.category = 'Bananas'; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); + expect(result.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); }); it('should not include a categoryOutOfPolicy violation when category is in policy', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).not.toContainEqual(categoryOutOfPolicyViolation); + expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); }); it('should add categoryOutOfPolicy violation to existing violations if they exist', () => { @@ -104,7 +104,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); + expect(result.value).toEqual(expect.arrayContaining([categoryOutOfPolicyViolation, ...transactionViolations])); }); it('should add missingCategory violation to existing violations if they exist', () => { @@ -116,7 +116,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); + expect(result.value).toEqual(expect.arrayContaining([missingCategoryViolation, ...transactionViolations])); }); }); @@ -128,8 +128,8 @@ describe('getViolationsOnyxData', () => { it('should not add any violations when categories are not required', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).not.toContainEqual([categoryOutOfPolicyViolation]); - expect(result?.value).not.toContainEqual([missingCategoryViolation]); + expect(result.value).not.toContainEqual([categoryOutOfPolicyViolation]); + expect(result.value).not.toContainEqual([missingCategoryViolation]); }); }); @@ -153,7 +153,7 @@ describe('getViolationsOnyxData', () => { it("shouldn't update the transactionViolations if the policy requires tags and the transaction has a tag from the policy", () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(transactionViolations); + expect(result.value).toEqual(transactionViolations); }); it('should add a missingTag violation if none is provided and policy requires tags', () => { @@ -161,7 +161,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([{...missingTagViolation}])); + expect(result.value).toEqual(expect.arrayContaining([{...missingTagViolation}])); }); it('should add a tagOutOfPolicy violation when policy requires tags and tag is not in the policy', () => { @@ -169,7 +169,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual([]); + expect(result.value).toEqual([]); }); it('should add tagOutOfPolicy violation to existing violations if transaction has tag that is not in the policy', () => { @@ -181,7 +181,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([{...tagOutOfPolicyViolation}, ...transactionViolations])); + expect(result.value).toEqual(expect.arrayContaining([{...tagOutOfPolicyViolation}, ...transactionViolations])); }); it('should add missingTag violation to existing violations if transaction does not have a tag', () => { @@ -193,7 +193,7 @@ describe('getViolationsOnyxData', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual(expect.arrayContaining([{...missingTagViolation}, ...transactionViolations])); + expect(result.value).toEqual(expect.arrayContaining([{...missingTagViolation}, ...transactionViolations])); }); }); @@ -205,8 +205,8 @@ describe('getViolationsOnyxData', () => { it('should not add any violations when tags are not required', () => { const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).not.toContainEqual([tagOutOfPolicyViolation]); - expect(result?.value).not.toContainEqual([missingTagViolation]); + expect(result.value).not.toContainEqual([tagOutOfPolicyViolation]); + expect(result.value).not.toContainEqual([missingTagViolation]); }); }); describe('policy has multi level tags', () => { @@ -259,31 +259,31 @@ describe('getViolationsOnyxData', () => { // Test case where transaction has no tags let result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual([someTagLevelsRequiredViolation]); + expect(result.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has 1 tag transaction.tag = 'Accounting'; someTagLevelsRequiredViolation.data = {errorIndexes: [1, 2]}; result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual([someTagLevelsRequiredViolation]); + expect(result.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has 2 tags transaction.tag = 'Accounting::Project1'; someTagLevelsRequiredViolation.data = {errorIndexes: [1]}; result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual([someTagLevelsRequiredViolation]); + expect(result.value).toEqual([someTagLevelsRequiredViolation]); // Test case where transaction has all tags transaction.tag = 'Accounting:Africa:Project1'; result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result?.value).toEqual([]); + expect(result.value).toEqual([]); }); it('should return tagOutOfPolicy when a tag is not enabled in the policy but is set in the transaction', () => { policyTags.Department.tags.Accounting.enabled = false; transaction.tag = 'Accounting:Africa:Project1'; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); const violation = {...tagOutOfPolicyViolation, data: {tagName: 'Department'}}; - expect(result?.value).toEqual([violation]); + expect(result.value).toEqual([violation]); }); }); }); From 1416897ee1ef4900c794fa8a39300ad832801933 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Fri, 29 Mar 2024 14:50:32 +0530 Subject: [PATCH 065/102] fix: Description/Merchant does not show in request preview. Signed-off-by: Krishna Gupta --- src/components/ReportActionItem/ReportPreview.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 8b95474bf2fc..33ce01212b2f 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -127,6 +127,7 @@ function ReportPreview({ const isApproved = ReportUtils.isReportApproved(iouReport); const canAllowSettlement = ReportUtils.hasUpdatedTotal(iouReport); + const allTransactions = TransactionUtils.getAllReportTransactions(iouReportID); const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(iouReportID); const numberOfScanningReceipts = transactionsWithReceipts.filter((transaction) => TransactionUtils.isReceiptBeingScanned(transaction)).length; const numberOfPendingRequests = transactionsWithReceipts.filter((transaction) => TransactionUtils.isPending(transaction) && TransactionUtils.isCardTransaction(transaction)).length; @@ -138,14 +139,16 @@ function ReportPreview({ const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction)); - let formattedMerchant = numberOfRequests === 1 && hasReceipts ? TransactionUtils.getMerchant(transactionsWithReceipts[0]) : null; + let formattedMerchant = numberOfRequests === 1 ? TransactionUtils.getMerchant(allTransactions[0]) : null; + const formattedDescription = numberOfRequests === 1 ? TransactionUtils.getDescription(allTransactions[0]) : null; + if (TransactionUtils.isPartialMerchant(formattedMerchant ?? '')) { formattedMerchant = null; } const previewSubtitle = // Formatted merchant can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - formattedMerchant || + (formattedMerchant ?? formattedDescription) || translate('iou.requestCount', { count: numberOfRequests - numberOfScanningReceipts - numberOfPendingRequests, scanningReceipts: numberOfScanningReceipts, @@ -228,7 +231,8 @@ function ReportPreview({ In this case, we don't want to show the merchant because it says: "Pending route...", which is already displayed in the amount field. */ const shouldShowSingleRequestMerchant = numberOfRequests === 1 && !!formattedMerchant && !(hasOnlyTransactionsWithPendingRoutes && !totalDisplaySpend); - const shouldShowSubtitle = !isScanning && (shouldShowSingleRequestMerchant || numberOfRequests > 1); + const shouldShowSingleRequestDescription = numberOfRequests === 1 && !!formattedDescription && !shouldShowSingleRequestMerchant; + const shouldShowSubtitle = !isScanning && (shouldShowSingleRequestMerchant || shouldShowSingleRequestDescription || numberOfRequests > 1); return ( Date: Fri, 29 Mar 2024 18:21:46 +0800 Subject: [PATCH 066/102] get the latest pending action of member --- src/pages/ReportParticipantsPage.tsx | 2 +- src/pages/RoomMembersPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index a2b2f094ac26..fa5f2b0947c5 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -50,7 +50,7 @@ const getAllParticipants = ( !!userPersonalDetail?.login && !CONST.RESTRICTED_ACCOUNT_IDS.includes(accountID) ? LocalePhoneNumber.formatPhoneNumber(userPersonalDetail.login) : translate('common.hidden'); const displayName = PersonalDetailsUtils.getDisplayNameOrDefault(userPersonalDetail); - const pendingChatMember = report?.pendingChatMembers?.find((member) => member.accountID === accountID.toString()); + const pendingChatMember = report?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); return { alternateText: userLogin, pendingAction: pendingChatMember?.pendingAction, diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 6cdcc6e06b95..220323e3ad85 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -198,7 +198,7 @@ function RoomMembersPage({report, session, policies}: RoomMembersPageProps) { return; } } - const pendingChatMember = report?.pendingChatMembers?.find((member) => member.accountID === accountID.toString()); + const pendingChatMember = report?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); result.push({ keyForList: String(accountID), From c096e2b0578fda03b3f48609f6c449b1970653e3 Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:00:16 +0530 Subject: [PATCH 067/102] Video playback speed change should not move to next video --- src/components/VideoPopoverMenu/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/VideoPopoverMenu/index.tsx b/src/components/VideoPopoverMenu/index.tsx index aad6364f91df..23f3447cf495 100644 --- a/src/components/VideoPopoverMenu/index.tsx +++ b/src/components/VideoPopoverMenu/index.tsx @@ -35,7 +35,6 @@ function VideoPopoverMenu({ anchorPosition={anchorPosition} menuItems={menuItems} anchorRef={videoPlayerMenuRef} - withoutOverlay /> ); } From ca12bc8810f87297a0fb650a0cd8d6889e145fac Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 06:58:32 -1000 Subject: [PATCH 068/102] Pass the chatType --- src/libs/API/parameters/StartSplitBillParams.ts | 1 + src/libs/actions/IOU.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libs/API/parameters/StartSplitBillParams.ts b/src/libs/API/parameters/StartSplitBillParams.ts index 30d21697ac67..623f291eb691 100644 --- a/src/libs/API/parameters/StartSplitBillParams.ts +++ b/src/libs/API/parameters/StartSplitBillParams.ts @@ -12,6 +12,7 @@ type StartSplitBillParams = { isFromGroupDM: boolean; createdReportActionID?: string; billable: boolean; + chatType?: string; }; export default StartSplitBillParams; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 33cd660b65f9..2d494c763503 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3047,6 +3047,7 @@ function startSplitBill( isFromGroupDM: !existingSplitChatReport, billable, ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}), + chatType: splitChatReport?.chatType, }; API.write(WRITE_COMMANDS.START_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); From 744a59fc88c183a2b20153fb29004d453a198b05 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 07:52:20 -1000 Subject: [PATCH 069/102] Refactor duplicate logic to get or create split chat report --- src/libs/actions/IOU.ts | 61 +++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 2d494c763503..6ba3500a27ae 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2280,31 +2280,7 @@ function createSplitsAndOnyxData( const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); - const existingChatReportID = existingSplitChatReportID || participants[0].reportID; - let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; - if (!existingSplitChatReport) { - existingSplitChatReport = participants.length < 2 ? ReportUtils.getChatByParticipants(participantAccountIDs) : null; - } - let newChat: ReportUtils.OptimisticChatReport | EmptyObject = {}; - const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; - if (!existingSplitChatReport && participants.length > 1) { - newChat = ReportUtils.buildOptimisticChatReport( - allParticipantsAccountIDs, - '', - CONST.REPORT.CHAT_TYPE.GROUP, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, - ); - } - if (isEmptyObject(newChat)) { - newChat = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); - } - const splitChatReport = existingSplitChatReport ?? newChat; + const {splitChatReport, existingSplitChatReport} = getOrCreateSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; const splitTransaction = TransactionUtils.buildOptimisticTransaction( @@ -2647,6 +2623,35 @@ function createSplitsAndOnyxData( }; } +function getOrCreateSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { + const existingChatReportID = existingSplitChatReportID || participants[0].reportID; + let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; + if (!existingSplitChatReport) { + existingSplitChatReport = participants.length < 2 ? ReportUtils.getChatByParticipants(participantAccountIDs) : null; + } + let newChat: ReportUtils.OptimisticChatReport | EmptyObject = {}; + const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; + if (!existingSplitChatReport && participants.length > 1) { + newChat = ReportUtils.buildOptimisticChatReport( + allParticipantsAccountIDs, + '', + CONST.REPORT.CHAT_TYPE.GROUP, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN + ); + } + if (isEmptyObject(newChat)) { + newChat = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); + } + const splitChatReport = existingSplitChatReport ?? newChat; + return { splitChatReport, existingSplitChatReport }; +} + /** * @param amount - always in smallest currency unit * @param existingSplitChatReportID - Either a group DM or a workspace chat @@ -2785,11 +2790,7 @@ function startSplitBill( ) { const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); - const existingSplitChatReport = - existingSplitChatReportID || participants[0].reportID - ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`] - : ReportUtils.getChatByParticipants(participantAccountIDs); - const splitChatReport = existingSplitChatReport ?? ReportUtils.buildOptimisticChatReport(participantAccountIDs); + const {splitChatReport, existingSplitChatReport} = getOrCreateSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; const {name: filename, source, state = CONST.IOU.RECEIPT_STATE.SCANREADY} = receipt; From 2ff25d1c86cd77008ed384ae76d696b43115f358 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 07:54:24 -1000 Subject: [PATCH 070/102] run prettier --- src/libs/actions/IOU.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 6ba3500a27ae..0f325d001fcc 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2642,14 +2642,14 @@ function getOrCreateSplitChatReport(existingSplitChatReportID: string, participa undefined, undefined, undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN + CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, ); } if (isEmptyObject(newChat)) { newChat = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); } const splitChatReport = existingSplitChatReport ?? newChat; - return { splitChatReport, existingSplitChatReport }; + return {splitChatReport, existingSplitChatReport}; } /** From db186982229cd670360c41ef4e24fde8c42956a6 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 07:56:49 -1000 Subject: [PATCH 071/102] give better name since we dont actually create any report just optimistic one --- src/libs/actions/IOU.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0f325d001fcc..9ee90a5090f0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2280,7 +2280,7 @@ function createSplitsAndOnyxData( const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); - const {splitChatReport, existingSplitChatReport} = getOrCreateSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); + const {splitChatReport, existingSplitChatReport} = getOrCreateOptimisticSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; const splitTransaction = TransactionUtils.buildOptimisticTransaction( @@ -2623,7 +2623,7 @@ function createSplitsAndOnyxData( }; } -function getOrCreateSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { +function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { const existingChatReportID = existingSplitChatReportID || participants[0].reportID; let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; if (!existingSplitChatReport) { @@ -2790,7 +2790,7 @@ function startSplitBill( ) { const currentUserEmailForIOUSplit = PhoneNumber.addSMSDomainIfPhoneNumber(currentUserLogin); const participantAccountIDs = participants.map((participant) => Number(participant.accountID)); - const {splitChatReport, existingSplitChatReport} = getOrCreateSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); + const {splitChatReport, existingSplitChatReport} = getOrCreateOptimisticSplitChatReport(existingSplitChatReportID, participants, participantAccountIDs, currentUserAccountID); const isOwnPolicyExpenseChat = !!splitChatReport.isOwnPolicyExpenseChat; const {name: filename, source, state = CONST.IOU.RECEIPT_STATE.SCANREADY} = receipt; From aec400275cb82f264843eb1cacd0ad111dd4ba3c Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 08:04:17 -1000 Subject: [PATCH 072/102] Fix avatar leading to not found page --- src/components/RoomHeaderAvatars.tsx | 7 ++++++- src/pages/ReportDetailsPage.tsx | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/RoomHeaderAvatars.tsx b/src/components/RoomHeaderAvatars.tsx index 9298062aa6f9..c23108adc0ea 100644 --- a/src/components/RoomHeaderAvatars.tsx +++ b/src/components/RoomHeaderAvatars.tsx @@ -13,10 +13,15 @@ import Text from './Text'; type RoomHeaderAvatarsProps = { icons: Icon[]; reportID: string; + isGroupChat?: boolean; }; -function RoomHeaderAvatars({icons, reportID}: RoomHeaderAvatarsProps) { +function RoomHeaderAvatars({icons, reportID, isGroupChat}: RoomHeaderAvatarsProps) { const navigateToAvatarPage = (icon: Icon) => { + if (isGroupChat) { + return; + } + if (icon.type === CONST.ICON_TYPE_WORKSPACE) { Navigation.navigate(ROUTES.REPORT_AVATAR.getRoute(reportID)); return; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 80563fcf7b1b..ccfe329419e3 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -218,6 +218,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD )} From c3892b1f003fd6a8e14a5cf0274bf0cc078f0363 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 08:27:10 -1000 Subject: [PATCH 073/102] Fix lint --- src/libs/actions/IOU.ts | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 9ee90a5090f0..30892bef5760 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2248,6 +2248,35 @@ function trackExpense( Report.notifyNewAction(activeReportID, payeeAccountID); } +function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { + const existingChatReportID = existingSplitChatReportID || participants[0].reportID; + let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; + if (!existingSplitChatReport) { + existingSplitChatReport = participants.length < 2 ? ReportUtils.getChatByParticipants(participantAccountIDs) : null; + } + let newChat: ReportUtils.OptimisticChatReport | EmptyObject = {}; + const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; + if (!existingSplitChatReport && participants.length > 1) { + newChat = ReportUtils.buildOptimisticChatReport( + allParticipantsAccountIDs, + '', + CONST.REPORT.CHAT_TYPE.GROUP, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + ); + } + if (isEmptyObject(newChat)) { + newChat = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); + } + const splitChatReport = existingSplitChatReport ?? newChat; + return {splitChatReport, existingSplitChatReport}; +} + /** * Build the Onyx data and IOU split necessary for splitting a bill with 3+ users. * 1. Build the optimistic Onyx data for the group chat, i.e. chatReport and iouReportAction creating the former if it doesn't yet exist. @@ -2623,35 +2652,6 @@ function createSplitsAndOnyxData( }; } -function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { - const existingChatReportID = existingSplitChatReportID || participants[0].reportID; - let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; - if (!existingSplitChatReport) { - existingSplitChatReport = participants.length < 2 ? ReportUtils.getChatByParticipants(participantAccountIDs) : null; - } - let newChat: ReportUtils.OptimisticChatReport | EmptyObject = {}; - const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; - if (!existingSplitChatReport && participants.length > 1) { - newChat = ReportUtils.buildOptimisticChatReport( - allParticipantsAccountIDs, - '', - CONST.REPORT.CHAT_TYPE.GROUP, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, - ); - } - if (isEmptyObject(newChat)) { - newChat = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); - } - const splitChatReport = existingSplitChatReport ?? newChat; - return {splitChatReport, existingSplitChatReport}; -} - /** * @param amount - always in smallest currency unit * @param existingSplitChatReportID - Either a group DM or a workspace chat From 57751f121c5cea270c5d543799f5b599f24f7841 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sat, 30 Mar 2024 03:08:22 +0530 Subject: [PATCH 074/102] improvement: Use Const for 'violation' everywhere we check for violation type. Signed-off-by: Krishna Gupta --- src/CONST.ts | 10 +++++- .../MoneyRequestPreviewContent.tsx | 2 +- src/hooks/useViolations.ts | 3 +- src/libs/TransactionUtils.ts | 4 ++- src/libs/Violations/ViolationsUtils.ts | 12 +++---- tests/unit/ViolationUtilsTest.ts | 31 ++++++++++--------- 6 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 0fa1c64be44d..1db67a818b84 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3332,7 +3332,15 @@ const CONST = { }, /** - * Constants for types of violations. + * Constants for types of violation. + */ + VIOLATION_TYPES: { + VIOLATION: 'violation', + NOTICE: 'notice', + }, + + /** + * Constants for types of violation names. * Defined here because they need to be referenced by the type system to generate the * ViolationNames type. */ diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 2e9f9a553b71..2c6f14cec4c2 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -160,7 +160,7 @@ function MoneyRequestPreviewContent({ const violations = TransactionUtils.getTransactionViolations(transaction.transactionID, transactionViolations); if (violations?.[0]) { const violationMessage = ViolationsUtils.getViolationTranslation(violations[0], translate); - const violationsCount = violations.filter((v) => v.type === 'violation').length; + const violationsCount = violations.filter((v) => v.type === CONST.VIOLATION_TYPES.VIOLATION).length; const isTooLong = violationsCount > 1 || violationMessage.length > 15; const hasViolationsAndFieldErrors = violationsCount > 0 && hasFieldErrors; diff --git a/src/hooks/useViolations.ts b/src/hooks/useViolations.ts index 3df457f1205a..7aadb4ce4ca3 100644 --- a/src/hooks/useViolations.ts +++ b/src/hooks/useViolations.ts @@ -1,4 +1,5 @@ import {useCallback, useMemo} from 'react'; +import CONST from '@src/CONST'; import type {TransactionViolation, ViolationName} from '@src/types/onyx'; /** @@ -49,7 +50,7 @@ type ViolationsMap = Map; function useViolations(violations: TransactionViolation[]) { const violationsByField = useMemo((): ViolationsMap => { - const filteredViolations = violations.filter((violation) => violation.type === 'violation'); + const filteredViolations = violations.filter((violation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION); const violationGroups = new Map(); for (const violation of filteredViolations) { const field = violationFields[violation.name]; diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 907edc208570..cdd23aac1596 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -562,7 +562,9 @@ function isOnHold(transaction: OnyxEntry): boolean { * Checks if any violations for the provided transaction are of type 'violation' */ function hasViolation(transactionID: string, transactionViolations: OnyxCollection): boolean { - return Boolean(transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some((violation: TransactionViolation) => violation.type === 'violation')); + return Boolean( + transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some((violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION), + ); } function getTransactionViolations(transactionID: string, transactionViolations: OnyxCollection): TransactionViolation[] | null { diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index fe2e5af537a7..f2aa53e55443 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -26,7 +26,7 @@ function getTagViolationsForSingleLevelTags( // Add 'tagOutOfPolicy' violation if tag is not in policy if (!hasTagOutOfPolicyViolation && updatedTransaction.tag && !isTagInPolicy) { - newTransactionViolations.push({name: CONST.VIOLATIONS.TAG_OUT_OF_POLICY, type: 'violation'}); + newTransactionViolations.push({name: CONST.VIOLATIONS.TAG_OUT_OF_POLICY, type: CONST.VIOLATION_TYPES.VIOLATION}); } // Remove 'tagOutOfPolicy' violation if tag is in policy @@ -41,7 +41,7 @@ function getTagViolationsForSingleLevelTags( // Add 'missingTag violation' if tag is required and not set if (!hasMissingTagViolation && !updatedTransaction.tag && policyRequiresTags) { - newTransactionViolations.push({name: CONST.VIOLATIONS.MISSING_TAG, type: 'violation'}); + newTransactionViolations.push({name: CONST.VIOLATIONS.MISSING_TAG, type: CONST.VIOLATION_TYPES.VIOLATION}); } return newTransactionViolations; } @@ -75,7 +75,7 @@ function getTagViolationsForMultiLevelTags( if (errorIndexes.length !== 0) { newTransactionViolations.push({ name: CONST.VIOLATIONS.SOME_TAG_LEVELS_REQUIRED, - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, data: { errorIndexes, }, @@ -89,7 +89,7 @@ function getTagViolationsForMultiLevelTags( if (!isTagInPolicy) { newTransactionViolations.push({ name: CONST.VIOLATIONS.TAG_OUT_OF_POLICY, - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, data: { tagName: policyTagKeys[i], }, @@ -131,7 +131,7 @@ const ViolationsUtils = { // Add 'categoryOutOfPolicy' violation if category is not in policy if (!hasCategoryOutOfPolicyViolation && categoryKey && !isCategoryInPolicy) { - newTransactionViolations.push({name: 'categoryOutOfPolicy', type: 'violation'}); + newTransactionViolations.push({name: 'categoryOutOfPolicy', type: CONST.VIOLATION_TYPES.VIOLATION}); } // Remove 'categoryOutOfPolicy' violation if category is in policy @@ -146,7 +146,7 @@ const ViolationsUtils = { // Add 'missingCategory' violation if category is required and not set if (!hasMissingCategoryViolation && policyRequiresCategories && !categoryKey) { - newTransactionViolations.push({name: 'missingCategory', type: 'violation'}); + newTransactionViolations.push({name: 'missingCategory', type: CONST.VIOLATION_TYPES.VIOLATION}); } } diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index 354a90802077..6c45fea0058a 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -1,27 +1,28 @@ import {beforeEach} from '@jest/globals'; import Onyx from 'react-native-onyx'; import ViolationsUtils from '@libs/Violations/ViolationsUtils'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PolicyCategories, PolicyTagList, Transaction, TransactionViolation} from '@src/types/onyx'; const categoryOutOfPolicyViolation = { name: 'categoryOutOfPolicy', - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, }; const missingCategoryViolation = { name: 'missingCategory', - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, }; const tagOutOfPolicyViolation = { name: 'tagOutOfPolicy', - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, }; const missingTagViolation = { name: 'missingTag', - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, }; describe('getViolationsOnyxData', () => { @@ -53,8 +54,8 @@ describe('getViolationsOnyxData', () => { it('should handle multiple violations', () => { transactionViolations = [ - {name: 'duplicatedTransaction', type: 'violation'}, - {name: 'receiptRequired', type: 'violation'}, + {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}, + {name: 'receiptRequired', type: CONST.VIOLATION_TYPES.VIOLATION}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); expect(result.value).toEqual(expect.arrayContaining(transactionViolations)); @@ -87,8 +88,8 @@ describe('getViolationsOnyxData', () => { it('should add categoryOutOfPolicy violation to existing violations if they exist', () => { transaction.category = 'Bananas'; transactionViolations = [ - {name: 'duplicatedTransaction', type: 'violation'}, - {name: 'receiptRequired', type: 'violation'}, + {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}, + {name: 'receiptRequired', type: CONST.VIOLATION_TYPES.VIOLATION}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); @@ -99,8 +100,8 @@ describe('getViolationsOnyxData', () => { it('should add missingCategory violation to existing violations if they exist', () => { transaction.category = undefined; transactionViolations = [ - {name: 'duplicatedTransaction', type: 'violation'}, - {name: 'receiptRequired', type: 'violation'}, + {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}, + {name: 'receiptRequired', type: CONST.VIOLATION_TYPES.VIOLATION}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); @@ -164,8 +165,8 @@ describe('getViolationsOnyxData', () => { it('should add tagOutOfPolicy violation to existing violations if transaction has tag that is not in the policy', () => { transaction.tag = 'Bananas'; transactionViolations = [ - {name: 'duplicatedTransaction', type: 'violation'}, - {name: 'receiptRequired', type: 'violation'}, + {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}, + {name: 'receiptRequired', type: CONST.VIOLATION_TYPES.VIOLATION}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); @@ -176,8 +177,8 @@ describe('getViolationsOnyxData', () => { it('should add missingTag violation to existing violations if transaction does not have a tag', () => { transaction.tag = undefined; transactionViolations = [ - {name: 'duplicatedTransaction', type: 'violation'}, - {name: 'receiptRequired', type: 'violation'}, + {name: 'duplicatedTransaction', type: CONST.VIOLATION_TYPES.VIOLATION}, + {name: 'receiptRequired', type: CONST.VIOLATION_TYPES.VIOLATION}, ]; const result = ViolationsUtils.getViolationsOnyxData(transaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); @@ -240,7 +241,7 @@ describe('getViolationsOnyxData', () => { it('should return someTagLevelsRequired when a required tag is missing', () => { const someTagLevelsRequiredViolation = { name: 'someTagLevelsRequired', - type: 'violation', + type: CONST.VIOLATION_TYPES.VIOLATION, data: { errorIndexes: [0, 1, 2], }, From d94613008dec9177cf32679aab88482a4c038a2e Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 12:19:01 -1000 Subject: [PATCH 075/102] Fix workspace avatar issue --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b7c835d692ca..82ece08ef09c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1193,7 +1193,7 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): * If the report is a thread and has a chat type set, it is a workspace chat. */ function isWorkspaceThread(report: OnyxEntry): boolean { - return isThread(report) && isChatReport(report) && !!getChatType(report); + return isThread(report) && isChatReport(report) && !isGroupChat(report) && !!getChatType(report); } /** From 0887c096514b6b13e36ec9ed5e45b71382f199ff Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sat, 30 Mar 2024 04:20:54 +0530 Subject: [PATCH 076/102] add warning violation type. Signed-off-by: Krishna Gupta --- src/CONST.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CONST.ts b/src/CONST.ts index 1db67a818b84..290a9df75621 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3337,6 +3337,7 @@ const CONST = { VIOLATION_TYPES: { VIOLATION: 'violation', NOTICE: 'notice', + WARNING: 'warning', }, /** From 2de1bb225e1dfbe8ddca5af662bad4395aed5a1a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 12:57:42 -1000 Subject: [PATCH 077/102] Fix issue for future threads as well --- src/CONST.ts | 3 +++ src/libs/ReportUtils.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 0fa1c64be44d..f8a15351ee32 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -59,6 +59,9 @@ const cardActiveStates: number[] = [2, 3, 4, 7]; const CONST = { MERGED_ACCOUNT_PREFIX: 'MERGED_', DEFAULT_POLICY_ROOM_CHAT_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL], + + // Note: Group excluded as it is not tied to any Workspace + WORKSPACE_ROOM_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL, chatTypes.POLICY_ROOM, chatTypes.POLICY_EXPENSE_CHAT, chatTypes.SELF_DM], ANDROID_PACKAGE_NAME, ANIMATED_TRANSITION: 300, ANIMATED_TRANSITION_FROM_VALUE: 100, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 82ece08ef09c..72eea831350c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1193,7 +1193,7 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): * If the report is a thread and has a chat type set, it is a workspace chat. */ function isWorkspaceThread(report: OnyxEntry): boolean { - return isThread(report) && isChatReport(report) && !isGroupChat(report) && !!getChatType(report); + return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.includes(getChatType(report)); } /** From a4225b8acd157bdb3548f9ea8afa79177b53011c Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 12:59:28 -1000 Subject: [PATCH 078/102] also self DM --- src/CONST.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index f8a15351ee32..f4c7ecb5215a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -60,8 +60,8 @@ const CONST = { MERGED_ACCOUNT_PREFIX: 'MERGED_', DEFAULT_POLICY_ROOM_CHAT_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL], - // Note: Group excluded as it is not tied to any Workspace - WORKSPACE_ROOM_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL, chatTypes.POLICY_ROOM, chatTypes.POLICY_EXPENSE_CHAT, chatTypes.SELF_DM], + // Note: Group and Self-DM excluded as these are not tied to a Workspace + WORKSPACE_ROOM_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL, chatTypes.POLICY_ROOM, chatTypes.POLICY_EXPENSE_CHAT], ANDROID_PACKAGE_NAME, ANIMATED_TRANSITION: 300, ANIMATED_TRANSITION_FROM_VALUE: 100, From 54ae619460300cad448d1f153deee9daa9308cc2 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 13:05:08 -1000 Subject: [PATCH 079/102] Fix ts --- src/libs/ReportUtils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 72eea831350c..6ff941771f94 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1193,7 +1193,8 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): * If the report is a thread and has a chat type set, it is a workspace chat. */ function isWorkspaceThread(report: OnyxEntry): boolean { - return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.includes(getChatType(report)); + const chatType = getChatType(report) ?? ''; + return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.includes(chatType); } /** From cdc85349708da77bdda048af686cd6b9ebb8ca2a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 13:18:33 -1000 Subject: [PATCH 080/102] typescript. is it smart? sometimes. --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6ff941771f94..479569b35bc8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1194,7 +1194,7 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): */ function isWorkspaceThread(report: OnyxEntry): boolean { const chatType = getChatType(report) ?? ''; - return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.includes(chatType); + return isThread(report) && isChatReport(report) && typeof chatType === 'string' && CONST.WORKSPACE_ROOM_TYPES.includes(chatType); } /** From 8eced8e9f73f89b086b62e26ddd6ad4dff16eaf3 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 13:22:39 -1000 Subject: [PATCH 081/102] Use some instead to fool typescript --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 479569b35bc8..9ca43d67e0d3 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1194,7 +1194,7 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): */ function isWorkspaceThread(report: OnyxEntry): boolean { const chatType = getChatType(report) ?? ''; - return isThread(report) && isChatReport(report) && typeof chatType === 'string' && CONST.WORKSPACE_ROOM_TYPES.includes(chatType); + return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.some(type => chatType === type); } /** From cc757f0c4ce23e9e7b651dea13b456a84619aaee Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sat, 30 Mar 2024 04:56:38 +0530 Subject: [PATCH 082/102] update according to suggestions. Signed-off-by: Krishna Gupta --- src/components/ReportActionItem/ReportPreview.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 33ce01212b2f..2581359b4543 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -225,14 +225,14 @@ function ReportPreview({ /* Show subtitle if at least one of the money requests is not being smart scanned, and either: - There is more than one money request – in this case, the "X requests, Y scanning" subtitle is shown; - - There is only one money request, it has a receipt and is not being smart scanned – in this case, the request merchant is shown; + - There is only one money request, it has a receipt and is not being smart scanned – in this case, the request merchant or description is shown; * There is an edge case when there is only one distance request with a pending route and amount = 0. - In this case, we don't want to show the merchant because it says: "Pending route...", which is already displayed in the amount field. + In this case, we don't want to show the merchant or description because it says: "Pending route...", which is already displayed in the amount field. */ - const shouldShowSingleRequestMerchant = numberOfRequests === 1 && !!formattedMerchant && !(hasOnlyTransactionsWithPendingRoutes && !totalDisplaySpend); - const shouldShowSingleRequestDescription = numberOfRequests === 1 && !!formattedDescription && !shouldShowSingleRequestMerchant; - const shouldShowSubtitle = !isScanning && (shouldShowSingleRequestMerchant || shouldShowSingleRequestDescription || numberOfRequests > 1); + const shouldShowSingleRequestMerchantOrDescription = + numberOfRequests === 1 && (!!formattedMerchant || !!formattedDescription) && !(hasOnlyTransactionsWithPendingRoutes && !totalDisplaySpend); + const shouldShowSubtitle = !isScanning && (shouldShowSingleRequestMerchantOrDescription || numberOfRequests > 1); return ( Date: Fri, 29 Mar 2024 13:32:41 -1000 Subject: [PATCH 083/102] Remove null coalesce since we are using some --- src/libs/ReportUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9ca43d67e0d3..11dd86a32ed3 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1193,8 +1193,8 @@ function hasOnlyTransactionsWithPendingRoutes(iouReportID: string | undefined): * If the report is a thread and has a chat type set, it is a workspace chat. */ function isWorkspaceThread(report: OnyxEntry): boolean { - const chatType = getChatType(report) ?? ''; - return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.some(type => chatType === type); + const chatType = getChatType(report); + return isThread(report) && isChatReport(report) && CONST.WORKSPACE_ROOM_TYPES.some((type) => chatType === type); } /** From 04cfc03ba3e0e7ca59f9e370613a8471bb244910 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Fri, 29 Mar 2024 16:39:21 -1000 Subject: [PATCH 084/102] Clean up logic for creating Group Chats --- src/libs/actions/IOU.ts | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 30892bef5760..4702b7a18958 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2249,15 +2249,30 @@ function trackExpense( } function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, participants: Participant[], participantAccountIDs: number[], currentUserAccountID: number) { + // The existing chat report could be passed as reportID or exist on the sole "participant" (in this case a report option) const existingChatReportID = existingSplitChatReportID || participants[0].reportID; + + // Check if the report is available locally if we do have one let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; - if (!existingSplitChatReport) { - existingSplitChatReport = participants.length < 2 ? ReportUtils.getChatByParticipants(participantAccountIDs) : null; + + // If we do not have one locally then we will search for a chat with the same participants (only for 1:1 chats). + const shouldGetOrCreateOneOneDM = participants.length < 2; + if (!existingSplitChatReport && shouldGetOrCreateOneOneDM) { + existingSplitChatReport = ReportUtils.getChatByParticipants(participantAccountIDs); + } + + // We found an existing chat report we are done... + if (existingSplitChatReport) { + // Yes, these are the same, but give the caller a way to identify if we created a new report or not + return {existingSplitChatReport, splitChatReport: existingSplitChatReport}; } - let newChat: ReportUtils.OptimisticChatReport | EmptyObject = {}; + + // No existing chat by this point we need to create it const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; - if (!existingSplitChatReport && participants.length > 1) { - newChat = ReportUtils.buildOptimisticChatReport( + + // Create a Group Chat if we have multiple participants + if (participants.length > 1) { + const splitChatReport = ReportUtils.buildOptimisticChatReport( allParticipantsAccountIDs, '', CONST.REPORT.CHAT_TYPE.GROUP, @@ -2269,12 +2284,12 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, undefined, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, ); + return {existingSplitChatReport: null, splitChatReport}; } - if (isEmptyObject(newChat)) { - newChat = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); - } - const splitChatReport = existingSplitChatReport ?? newChat; - return {splitChatReport, existingSplitChatReport}; + + // Otherwise, create a new 1:1 chat report + const splitChatReport = ReportUtils.buildOptimisticChatReport(allParticipantsAccountIDs); + return {existingSplitChatReport: null, splitChatReport}; } /** From 21ca2908711377c0f09096c128393b81bada7270 Mon Sep 17 00:00:00 2001 From: Krishna Gupta Date: Sat, 30 Mar 2024 08:57:23 +0530 Subject: [PATCH 085/102] fix: Task - No error of exceeding limit when changing title of existing task & system message posted. Signed-off-by: Krishna Gupta --- src/pages/tasks/TaskTitlePage.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/tasks/TaskTitlePage.tsx b/src/pages/tasks/TaskTitlePage.tsx index 009983beac3e..99558efaeb03 100644 --- a/src/pages/tasks/TaskTitlePage.tsx +++ b/src/pages/tasks/TaskTitlePage.tsx @@ -12,6 +12,7 @@ import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalD import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; @@ -32,7 +33,9 @@ function TaskTitlePage({report, currentUserPersonalDetails}: TaskTitlePageProps) const errors: FormInputErrors = {}; if (!title) { - errors.title = 'newTaskPage.pleaseEnterTaskName'; + ErrorUtils.addErrorMessage(errors, INPUT_IDS.TITLE, 'newTaskPage.pleaseEnterTaskName'); + } else if (title.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, INPUT_IDS.TITLE, ['common.error.characterLimitExceedCounter', {length: title.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } return errors; From 471895feeed895ea0c79ba818ecd43039eead80a Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 30 Mar 2024 13:41:28 +0800 Subject: [PATCH 086/102] renaming --- ...ansitionEnd.tsx => withNavigationTransitionEnd.tsx} | 10 +++++----- src/pages/RoomInvitePage.tsx | 8 ++++---- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 8 ++++---- src/pages/workspace/WorkspaceInvitePage.tsx | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) rename src/components/{withTransitionEnd.tsx => withNavigationTransitionEnd.tsx} (76%) diff --git a/src/components/withTransitionEnd.tsx b/src/components/withNavigationTransitionEnd.tsx similarity index 76% rename from src/components/withTransitionEnd.tsx rename to src/components/withNavigationTransitionEnd.tsx index b00e0a9f4f34..417d8828c1e4 100644 --- a/src/components/withTransitionEnd.tsx +++ b/src/components/withNavigationTransitionEnd.tsx @@ -5,10 +5,10 @@ import React, {useEffect, useState} from 'react'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import type {RootStackParamList} from '@libs/Navigation/types'; -type WithTransitionEndProps = {didScreenTransitionEnd: boolean}; +type WithNavigationTransitionEndProps = {didScreenTransitionEnd: boolean}; export default function (WrappedComponent: ComponentType>): React.ComponentType> { - function WithTransitionEnd(props: TProps, ref: ForwardedRef) { + function WithNavigationTransitionEnd(props: TProps, ref: ForwardedRef) { const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); const navigation = useNavigation>(); @@ -31,9 +31,9 @@ export default function (WrappedComponent: ComponentType; }; -type RoomInvitePageProps = RoomInvitePageOnyxProps & WithReportOrNotFoundProps & WithTransitionEndProps; +type RoomInvitePageProps = RoomInvitePageOnyxProps & WithReportOrNotFoundProps & WithNavigationTransitionEndProps; type Sections = Array>>; @@ -245,7 +245,7 @@ function RoomInvitePage({betas, personalDetails, report, policies, didScreenTran RoomInvitePage.displayName = 'RoomInvitePage'; -export default withTransitionEnd( +export default withNavigationTransitionEnd( withReportOrNotFound()( withOnyx({ personalDetails: { diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index f293c5ff03c4..bb199ddc905f 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -14,8 +14,8 @@ import type {ListItem} from '@components/SelectionList/types'; import UserListItem from '@components/SelectionList/UserListItem'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; -import withTransitionEnd from '@components/withTransitionEnd'; -import type {WithTransitionEndProps} from '@components/withTransitionEnd'; +import withNavigationTransitionEnd from '@components/withNavigationTransitionEnd'; +import type {WithNavigationTransitionEndProps} from '@components/withNavigationTransitionEnd'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; @@ -43,7 +43,7 @@ type UseOptions = { reports: OnyxCollection; }; -type TaskAssigneeSelectorModalProps = TaskAssigneeSelectorModalOnyxProps & WithCurrentUserPersonalDetailsProps & WithTransitionEndProps; +type TaskAssigneeSelectorModalProps = TaskAssigneeSelectorModalOnyxProps & WithCurrentUserPersonalDetailsProps & WithNavigationTransitionEndProps; function useOptions({reports}: UseOptions) { const allPersonalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; @@ -241,4 +241,4 @@ const TaskAssigneeSelectorModalWithOnyx = withOnyx; @@ -327,7 +327,7 @@ function WorkspaceInvitePage({ WorkspaceInvitePage.displayName = 'WorkspaceInvitePage'; -export default withTransitionEnd( +export default withNavigationTransitionEnd( withPolicyAndFullscreenLoading( withOnyx({ personalDetails: { From 9e7f5b790a84b8c359dab6e31c6428690ce6ace7 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 30 Mar 2024 13:56:20 +0800 Subject: [PATCH 087/102] update test --- tests/unit/ViolationUtilsTest.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/unit/ViolationUtilsTest.ts b/tests/unit/ViolationUtilsTest.ts index e112f2908590..8389086f8720 100644 --- a/tests/unit/ViolationUtilsTest.ts +++ b/tests/unit/ViolationUtilsTest.ts @@ -61,16 +61,6 @@ describe('getViolationsOnyxData', () => { expect(result.value).toEqual(expect.arrayContaining(transactionViolations)); }); - it('should not add violation when the transaction is partial', () => { - const partialTransaction = {...transaction, amount: 0, merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT}; - transactionViolations = [ - {name: 'duplicatedTransaction', type: 'violation'}, - {name: 'receiptRequired', type: 'violation'}, - ]; - const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); - expect(result.value).toEqual(transactionViolations); - }); - describe('policyRequiresCategories', () => { beforeEach(() => { policyRequiresCategories = true; @@ -95,6 +85,12 @@ describe('getViolationsOnyxData', () => { expect(result.value).not.toContainEqual(categoryOutOfPolicyViolation); }); + it('should not add a category violation when the transaction is partial', () => { + const partialTransaction = {...transaction, amount: 0, merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT, category: undefined}; + const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); + expect(result.value).not.toContainEqual(missingCategoryViolation); + }); + it('should add categoryOutOfPolicy violation to existing violations if they exist', () => { transaction.category = 'Bananas'; transactionViolations = [ @@ -172,6 +168,12 @@ describe('getViolationsOnyxData', () => { expect(result.value).toEqual([]); }); + it('should not add a tag violation when the transaction is partial', () => { + const partialTransaction = {...transaction, amount: 0, merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT, tag: undefined}; + const result = ViolationsUtils.getViolationsOnyxData(partialTransaction, transactionViolations, policyRequiresTags, policyTags, policyRequiresCategories, policyCategories); + expect(result.value).not.toContainEqual(missingTagViolation); + }); + it('should add tagOutOfPolicy violation to existing violations if transaction has tag that is not in the policy', () => { transaction.tag = 'Bananas'; transactionViolations = [ From 37a9a6a888efae02094d54856d175a26043cf11b Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 30 Mar 2024 14:04:47 +0800 Subject: [PATCH 088/102] prettier --- src/libs/Violations/ViolationsUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index d3c1e6e19cd0..83f3b2fcc154 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -2,8 +2,8 @@ import reject from 'lodash/reject'; import Onyx from 'react-native-onyx'; import type {OnyxUpdate} from 'react-native-onyx'; import type {Phrase, PhraseParameters} from '@libs/Localize'; -import * as TransactionUtils from '@libs/TransactionUtils'; import {getSortedTagKeys} from '@libs/PolicyUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; From 3ca25eeccbfe4cef6c3ab4837ea05b42f96c9955 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Sat, 30 Mar 2024 15:17:52 +0800 Subject: [PATCH 089/102] fix removed user isn't strikethrough-ed --- src/components/OptionRow.tsx | 22 +++++++++++----------- src/libs/actions/Policy.ts | 5 ----- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/components/OptionRow.tsx b/src/components/OptionRow.tsx index c72cdd1fd898..90ccff47b2b9 100644 --- a/src/components/OptionRow.tsx +++ b/src/components/OptionRow.tsx @@ -154,14 +154,14 @@ function OptionRow({ } return ( - - - {(hovered) => ( + + {(hovered) => ( + )} - )} - - + + )} + ); } diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 0c6bd7682add..3c34e823ac9a 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -780,15 +780,12 @@ function removeOptimisticAnnounceRoomMembers(policyID: string, accountIDs: numbe } if (announceReport?.participantAccountIDs) { - const remainUsers = announceReport.participantAccountIDs.filter((e) => !accountIDs.includes(e)); const pendingChatMembers = ReportUtils.getPendingChatMembers(accountIDs, announceReport?.pendingChatMembers ?? [], CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); announceRoomMembers.onyxOptimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, value: { - participantAccountIDs: [...remainUsers], - visibleChatMemberAccountIDs: [...remainUsers], pendingChatMembers, }, }); @@ -797,8 +794,6 @@ function removeOptimisticAnnounceRoomMembers(policyID: string, accountIDs: numbe onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, value: { - participantAccountIDs: announceReport.participantAccountIDs, - visibleChatMemberAccountIDs: announceReport.visibleChatMemberAccountIDs, pendingChatMembers: announceReport?.pendingChatMembers ?? null, }, }); From 990b6d3815af91f2a087af79010b0340398b5a92 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 1 Apr 2024 10:02:10 +0700 Subject: [PATCH 090/102] merge main --- src/pages/iou/steps/NewRequestAmountPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/NewRequestAmountPage.tsx b/src/pages/iou/steps/NewRequestAmountPage.tsx index 685098c47afa..0528af502e99 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.tsx +++ b/src/pages/iou/steps/NewRequestAmountPage.tsx @@ -77,7 +77,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}: NewRequestAmoun if (!iou?.id) { return; } - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID), true); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, '1', reportID), true); return; } const moneyRequestID = `${iouType}${reportID}`; @@ -87,7 +87,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}: NewRequestAmoun } if (!isDistanceRequestTab && (!iou?.participants?.length || iou?.amount === 0 || shouldReset)) { - Navigation.goBack(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID), true); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, '1', reportID), true); } } From 744f3fbf7ee2c88579fd4f95e5fab5699eb44b0f Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 1 Apr 2024 11:51:52 +0700 Subject: [PATCH 091/102] resolve conflict --- src/libs/actions/IOU.ts | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0a57dd15489b..a4f1efeeb8c6 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5051,44 +5051,6 @@ function setShownHoldUseExplanation() { Onyx.set(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, true); } -<<<<<<< HEAD -======= -/** Navigates to the next IOU page based on where the IOU request was started */ -function navigateToNextPage(iou: OnyxEntry, iouType: string, report?: OnyxEntry, path = '') { - const moneyRequestID = `${iouType}${report?.reportID ?? ''}`; - const shouldReset = iou?.id !== moneyRequestID && !!report?.reportID; - - // If the money request ID in Onyx does not match the ID from params, we want to start a new request - // with the ID from params. We need to clear the participants in case the new request is initiated from FAB. - if (shouldReset) { - resetMoneyRequestInfo(moneyRequestID); - } - - // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. - if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report?.reportID)); - return; - } - - // If a request is initiated on a report, skip the participants selection step and navigate to the confirmation page. - if (report?.reportID) { - // If the report is iou or expense report, we should get the chat report to set participant for request money - const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReport(report.chatReportID) : report; - // Reinitialize the participants when the money request ID in Onyx does not match the ID from params - if (!iou?.participants?.length || shouldReset) { - const currentUserAccountID = currentUserPersonalDetails.accountID; - const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) - ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}] - : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); - setMoneyRequestParticipants(participants); - } - Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(iouType, report.reportID)); - return; - } - Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); -} - ->>>>>>> main /** * When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation * parameter. From e183469e0669dac9347cfb0720a0b754132741a8 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Mon, 1 Apr 2024 10:45:27 +0530 Subject: [PATCH 092/102] display link as inline code --- contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md b/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md index 932dcc8d5e20..f2a2efca1f5f 100644 --- a/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md +++ b/contributingGuides/HOW_TO_BECOME_A_CONTRIBUTOR_PLUS.md @@ -24,4 +24,4 @@ C+ are contributors who are experienced at working with Expensify and have gaine ## How to join? -Email contributors@expensify.com and include "C+ Team Application" in the subject line if you’re interested in joining. Please include your GitHub username and a link to the PRs you've authored that have been merged. ie. https://github.com/Expensify/App/pulls?q=is%3Apr+author%3Aparasharrajat+is%3Amerged +Email contributors@expensify.com and include "C+ Team Application" in the subject line if you’re interested in joining. Please include your GitHub username and a link to the PRs you've authored that have been merged. ie. `https://github.com/Expensify/App/pulls?q=is%3Apr+author%3Aparasharrajat+is%3Amerged` From e5e77a8ad63257825a1786e6f7d12e746dc2ded4 Mon Sep 17 00:00:00 2001 From: Scott Deeter Date: Mon, 1 Apr 2024 09:09:58 -0700 Subject: [PATCH 093/102] Revert "feat: Upgrade VisionCamera to V4" --- ios/Podfile.lock | 4 +- package-lock.json | 15 ++----- package.json | 2 +- .../react-native-vision-camera+2.16.8.patch | 22 ++++++++++ .../NavigationAwareCamera/index.native.js | 1 - .../step/IOURequestStepScan/index.native.js | 43 +++++++++---------- 6 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 patches/react-native-vision-camera+2.16.8.patch diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 24ef0704be25..b2995c35c9bc 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1415,7 +1415,7 @@ PODS: - SDWebImage/Core (~> 5.17) - SocketRocket (0.6.1) - Turf (2.7.0) - - VisionCamera (4.0.0-beta.11): + - VisionCamera (2.16.8): - React - React-callinvoker - React-Core @@ -1920,7 +1920,7 @@ SPEC CHECKSUMS: SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 - VisionCamera: b6b6f46949eae83b71429c971162af337ef34fa3 + VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 PODFILE CHECKSUM: a431c146e1501391834a2f299a74093bac53b530 diff --git a/package-lock.json b/package-lock.json index d6c5edbdd981..4c4e6d1d4844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -114,7 +114,7 @@ "react-native-tab-view": "^3.5.2", "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "3.8.0", - "react-native-vision-camera": "^4.0.0-beta.11", + "react-native-vision-camera": "2.16.8", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-web-sound": "^0.1.3", @@ -39769,18 +39769,11 @@ } }, "node_modules/react-native-vision-camera": { - "version": "4.0.0-beta.11", - "resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.0.0-beta.11.tgz", - "integrity": "sha512-cKg/nwT0q0H1ivEVG+PQt/QxhFgf/dd7SiMm7bCzlSCmt0T2tXyIdLsuY312iKBB2qasQZOYtzRsoQjipHQkDw==", + "version": "2.16.8", + "license": "MIT", "peerDependencies": { "react": "*", - "react-native": "*", - "react-native-worklets-core": "*" - }, - "peerDependenciesMeta": { - "react-native-worklets-core": { - "optional": true - } + "react-native": "*" } }, "node_modules/react-native-web": { diff --git a/package.json b/package.json index 507c58763b85..e25f8ea95b02 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "react-native-tab-view": "^3.5.2", "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "3.8.0", - "react-native-vision-camera": "^4.0.0-beta.11", + "react-native-vision-camera": "2.16.8", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-web-sound": "^0.1.3", diff --git a/patches/react-native-vision-camera+2.16.8.patch b/patches/react-native-vision-camera+2.16.8.patch new file mode 100644 index 000000000000..3afc4573985d --- /dev/null +++ b/patches/react-native-vision-camera+2.16.8.patch @@ -0,0 +1,22 @@ +diff --git a/node_modules/react-native-vision-camera/android/build.gradle b/node_modules/react-native-vision-camera/android/build.gradle +index ddfa243..bafffc3 100644 +--- a/node_modules/react-native-vision-camera/android/build.gradle ++++ b/node_modules/react-native-vision-camera/android/build.gradle +@@ -334,7 +334,7 @@ if (ENABLE_FRAME_PROCESSORS) { + def thirdPartyVersions = new Properties() + thirdPartyVersions.load(new FileInputStream(thirdPartyVersionsFile)) + +- def BOOST_VERSION = thirdPartyVersions["BOOST_VERSION"] ++ def BOOST_VERSION = thirdPartyVersions["BOOST_VERSION"] ?: "1.83.0" + def boost_file = new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz") + def DOUBLE_CONVERSION_VERSION = thirdPartyVersions["DOUBLE_CONVERSION_VERSION"] + def double_conversion_file = new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz") +@@ -352,7 +352,7 @@ if (ENABLE_FRAME_PROCESSORS) { + + task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) { + def transformedVersion = BOOST_VERSION.replace("_", ".") +- def srcUrl = "https://boostorg.jfrog.io/artifactory/main/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz" ++ def srcUrl = "https://archives.boost.io/release/${transformedVersion}/source/boost_${BOOST_VERSION}.tar.gz" + if (REACT_NATIVE_VERSION < 69) { + srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/boost_${BOOST_VERSION}.tar.gz" + } diff --git a/src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/index.native.js b/src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/index.native.js index 64fa291b2003..65c17d3cb7ab 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/index.native.js +++ b/src/pages/iou/request/step/IOURequestStepScan/NavigationAwareCamera/index.native.js @@ -15,7 +15,6 @@ const NavigationAwareCamera = React.forwardRef(({cameraTabIndex, ...props}, ref) return ( { // Store the receipt on the transaction object in Onyx @@ -258,7 +257,7 @@ function IOURequestStepScan({ showCameraAlert(); Log.warn('Error taking photo', error); }); - }, [flash, hasFlash, action, translate, transactionID, updateScanAndNavigate, navigateToConfirmationStep, cameraPermissionStatus]); + }, [flash, action, translate, transactionID, updateScanAndNavigate, navigateToConfirmationStep, cameraPermissionStatus]); // Wait for camera permission status to render if (cameraPermissionStatus == null) { @@ -357,22 +356,20 @@ function IOURequestStepScan({ height={CONST.RECEIPT.SHUTTER_SIZE} /> - {hasFlash && ( - setFlash((prevFlash) => !prevFlash)} - > - - - )} + setFlash((prevFlash) => !prevFlash)} + > + + ); From 4649cfa845b81b231d2f4ab42813688c9deffcf3 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Mon, 1 Apr 2024 19:30:17 +0000 Subject: [PATCH 094/102] Update version to 1.4.58-5 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9a00228cd5f5..3185fe5456e7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001045804 - versionName "1.4.58-4" + versionCode 1001045805 + versionName "1.4.58-5" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 8860c0883a12..31521c7e13ca 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.58.4 + 1.4.58.5 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 8fe00fa73a5d..d68eb78fdbac 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.58.4 + 1.4.58.5 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index ec61c4ff9a96..d638780dd903 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.58 CFBundleVersion - 1.4.58.4 + 1.4.58.5 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index d6c5edbdd981..210a192ac902 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.58-4", + "version": "1.4.58-5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.58-4", + "version": "1.4.58-5", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 507c58763b85..2305fa870ff0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.58-4", + "version": "1.4.58-5", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From a5888426fcdd95a1efefbf1a9a41b0caaeb55267 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 2 Apr 2024 02:41:11 +0700 Subject: [PATCH 095/102] complete resolve conflict --- src/libs/actions/IOU.ts | 42 ----------------------------------------- 1 file changed, 42 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 8393982c6b33..f99942a3d7a8 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5064,48 +5064,6 @@ function setShownHoldUseExplanation() { Onyx.set(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, true); } -<<<<<<< HEAD -======= -/** Navigates to the next IOU page based on where the IOU request was started */ -function navigateToNextPage(iou: OnyxEntry, iouType: string, report?: OnyxEntry, path = '') { - const moneyRequestID = `${iouType}${report?.reportID ?? ''}`; - const shouldReset = iou?.id !== moneyRequestID && !!report?.reportID; - - // If the money request ID in Onyx does not match the ID from params, we want to start a new request - // with the ID from params. We need to clear the participants in case the new request is initiated from FAB. - if (shouldReset) { - resetMoneyRequestInfo(moneyRequestID); - } - - // If we're adding a receipt, that means the user came from the confirmation page and we need to navigate back to it. - if (path.slice(1) === ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, report?.reportID)) { - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report?.reportID ?? '1'), - ); - return; - } - - // If a request is initiated on a report, skip the participants selection step and navigate to the confirmation page. - if (report?.reportID) { - // If the report is iou or expense report, we should get the chat report to set participant for request money - const chatReport = ReportUtils.isMoneyRequestReport(report) ? ReportUtils.getReport(report.chatReportID) : report; - // Reinitialize the participants when the money request ID in Onyx does not match the ID from params - if (!iou?.participants?.length || shouldReset) { - const currentUserAccountID = currentUserPersonalDetails.accountID; - const participants: Participant[] = ReportUtils.isPolicyExpenseChat(chatReport) - ? [{reportID: chatReport?.reportID, isPolicyExpenseChat: true, selected: true}] - : (chatReport?.participantAccountIDs ?? []).filter((accountID) => currentUserAccountID !== accountID).map((accountID) => ({accountID, selected: true})); - setMoneyRequestParticipants(participants); - } - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType as ValueOf, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report.reportID), - ); - return; - } - Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType)); -} - ->>>>>>> main /** * Put money request on HOLD */ From 09288120b1b8a0023ee286e011fbf400c7c9c211 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Mon, 1 Apr 2024 20:40:47 +0000 Subject: [PATCH 096/102] Update version to 1.4.58-6 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 3185fe5456e7..f4d6f1679f6b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001045805 - versionName "1.4.58-5" + versionCode 1001045806 + versionName "1.4.58-6" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 31521c7e13ca..3d7ff5fadd93 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.58.5 + 1.4.58.6 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index d68eb78fdbac..93a1e784788f 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.58.5 + 1.4.58.6 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index d638780dd903..23238badb6b9 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.58 CFBundleVersion - 1.4.58.5 + 1.4.58.6 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index aa494e6d8ccc..15f00c3cce29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.58-5", + "version": "1.4.58-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.58-5", + "version": "1.4.58-6", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index f7afb324afda..0e3568ccffd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.58-5", + "version": "1.4.58-6", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From d2ab32de307763d3f21f9f9eb4673b10b4f25fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Mon, 1 Apr 2024 14:51:58 -0600 Subject: [PATCH 097/102] Revert "fixes "Skeleton is displayed when navigating to a transaction thread created offline"" --- src/pages/home/ReportScreen.tsx | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index f1f8eb8047c7..a7f0a9a26f80 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -102,7 +102,7 @@ type ReportScreenProps = OnyxHOCProps & CurrentReportIDContextValue & ReportScre function getReportID(route: ReportScreenNavigationProps['route']): string { // The report ID is used in an onyx key. If it's an empty string, onyx will return // a collection instead of an individual report. - return String(route.params?.reportID || ''); + return String(route.params?.reportID || 0); } /** @@ -337,21 +337,28 @@ function ReportScreen({ return reportIDFromRoute !== '' && !!report.reportID && !isTransitioning; }, [report, reportIDFromRoute]); - const isLoading = !isSidebarLoaded || PersonalDetailsUtils.isPersonalDetailsEmpty(); + const isLoading = !ReportUtils.isValidReportIDFromPath(reportIDFromRoute) || !isSidebarLoaded || PersonalDetailsUtils.isPersonalDetailsEmpty(); const shouldShowSkeleton = isLinkingToMessage || !isCurrentReportLoadedFromOnyx || (reportActions.length === 0 && !!reportMetadata?.isLoadingInitialReportActions) || isLoading || (!!reportActionIDFromRoute && reportMetadata?.isLoadingInitialReportActions); - const shouldShowReportActionList = isCurrentReportLoadedFromOnyx && !isLoading; // eslint-disable-next-line rulesdir/no-negated-variables - const shouldShowNotFoundPage = - !firstRenderRef.current && - ((!wasReportAccessibleRef.current && !report.reportID && !isOptimisticDelete && !reportMetadata?.isLoadingInitialReportActions && !userLeavingStatus) || - shouldHideReport || - (!!reportIDFromRoute && !ReportUtils.isValidReportIDFromPath(reportIDFromRoute))); + const shouldShowNotFoundPage = useMemo( + (): boolean => + !shouldShowSkeleton && + ((!wasReportAccessibleRef.current && + !firstRenderRef.current && + !report.reportID && + !isOptimisticDelete && + !reportMetadata?.isLoadingInitialReportActions && + !userLeavingStatus) || + shouldHideReport || + (!!reportIDFromRoute && !ReportUtils.isValidReportIDFromPath(reportIDFromRoute))), + [shouldShowSkeleton, report.reportID, isOptimisticDelete, reportMetadata?.isLoadingInitialReportActions, userLeavingStatus, shouldHideReport, reportIDFromRoute], + ); const fetchReport = useCallback(() => { Report.openReport(reportIDFromRoute, reportActionIDFromRoute); From 9fa7e69487d235984877e3f7ce5e732dd318725b Mon Sep 17 00:00:00 2001 From: usman-ghani564 Date: Tue, 2 Apr 2024 03:41:25 +0500 Subject: [PATCH 098/102] fix: add iouType to differ with request / split --- .../MoneyTemporaryForRefactorRequestParticipantsSelector.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index e0a570e334d5..31ddda4cf04d 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -188,6 +188,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ { ..._.pick(option, 'accountID', 'login', 'isPolicyExpenseChat', 'reportID', 'searchText'), selected: true, + iouType: iouType, }, ]); onFinish(); @@ -227,6 +228,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ reportID: option.reportID, selected: true, searchText: option.searchText, + iouType: iouType === CONST.IOU.TYPE.REQUEST ? CONST.IOU.TYPE.SPLIT : iouType, }, ]; } From 6b96af5d0682b771368ba8b7fbcfed6f3acf52b6 Mon Sep 17 00:00:00 2001 From: usman-ghani564 Date: Tue, 2 Apr 2024 04:51:36 +0500 Subject: [PATCH 099/102] fix lint --- .../MoneyTemporaryForRefactorRequestParticipantsSelector.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index 31ddda4cf04d..bdd71d28b0e0 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -182,13 +182,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ * * @param {Object} option */ + // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes const addSingleParticipant = useCallback( (option) => { onParticipantsAdded([ { ..._.pick(option, 'accountID', 'login', 'isPolicyExpenseChat', 'reportID', 'searchText'), selected: true, - iouType: iouType, + iouType, }, ]); onFinish(); @@ -200,6 +201,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ * Removes a selected option from list if already selected. If not already selected add this option to the list. * @param {Object} option */ + // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes const addParticipantToSelection = useCallback( (option) => { const isOptionSelected = (selectedOption) => { From 4ac2310471c1961d6ab5846f2c2770e197d62a4e Mon Sep 17 00:00:00 2001 From: usman-ghani564 Date: Tue, 2 Apr 2024 05:00:50 +0500 Subject: [PATCH 100/102] fix lint --- .../MoneyTemporaryForRefactorRequestParticipantsSelector.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index bdd71d28b0e0..4870d39002ac 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -182,7 +182,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ * * @param {Object} option */ - // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes const addSingleParticipant = useCallback( (option) => { onParticipantsAdded([ @@ -194,6 +193,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ ]); onFinish(); }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes [onFinish, onParticipantsAdded], ); @@ -201,7 +201,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ * Removes a selected option from list if already selected. If not already selected add this option to the list. * @param {Object} option */ - // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes const addParticipantToSelection = useCallback( (option) => { const isOptionSelected = (selectedOption) => { @@ -237,6 +236,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ onParticipantsAdded(newSelectedOptions, newSelectedOptions.length !== 0 ? CONST.IOU.TYPE.SPLIT : undefined); }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to trigger this callback when iouType changes [participants, onParticipantsAdded], ); From 0f089ae890448d473d47cc6442384b88d81c9ddd Mon Sep 17 00:00:00 2001 From: OSBotify Date: Tue, 2 Apr 2024 02:44:08 +0000 Subject: [PATCH 101/102] Update version to 1.4.58-7 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index f4d6f1679f6b..13a6a9d3cc38 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001045806 - versionName "1.4.58-6" + versionCode 1001045807 + versionName "1.4.58-7" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 3d7ff5fadd93..059fe63535b7 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.58.6 + 1.4.58.7 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 93a1e784788f..c98b0058973d 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.58.6 + 1.4.58.7 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 23238badb6b9..b8a7167bba64 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.58 CFBundleVersion - 1.4.58.6 + 1.4.58.7 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 15f00c3cce29..eb1d8e0c3aec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.58-6", + "version": "1.4.58-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.58-6", + "version": "1.4.58-7", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0e3568ccffd0..0b464b3801e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.58-6", + "version": "1.4.58-7", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 16525e6d24859c0a396c2693205ad008e3cc999e Mon Sep 17 00:00:00 2001 From: OSBotify Date: Tue, 2 Apr 2024 03:12:25 +0000 Subject: [PATCH 102/102] Update version to 1.4.58-8 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 13a6a9d3cc38..cb7056283750 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001045807 - versionName "1.4.58-7" + versionCode 1001045808 + versionName "1.4.58-8" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 059fe63535b7..7711fe679b3f 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.58.7 + 1.4.58.8 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index c98b0058973d..3e503e2c1a08 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.58.7 + 1.4.58.8 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index b8a7167bba64..6f5a7fa2c754 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.58 CFBundleVersion - 1.4.58.7 + 1.4.58.8 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index eb1d8e0c3aec..809b4bd5c4df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.58-7", + "version": "1.4.58-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.58-7", + "version": "1.4.58-8", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0b464b3801e0..9f1fbc894e1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.58-7", + "version": "1.4.58-8", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",