-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Update create transaction Manual flow to ask for merchant after asking for amount v3 #82214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,14 +5,15 @@ import CONST from '@src/CONST'; | |
| import ROUTES from '@src/ROUTES'; | ||
| import type {OnyxInputOrEntry, PersonalDetails, Policy, Report} from '@src/types/onyx'; | ||
| import type {Attendee, Participant} from '@src/types/onyx/IOU'; | ||
| import type Transaction from '@src/types/onyx/Transaction'; | ||
| import SafeString from '@src/utils/SafeString'; | ||
| import type {IOURequestType} from './actions/IOU'; | ||
| import {getCurrencyUnit} from './CurrencyUtils'; | ||
| import Navigation from './Navigation/Navigation'; | ||
| import Performance from './Performance'; | ||
| import {isPaidGroupPolicy} from './PolicyUtils'; | ||
| import {getReportTransactions} from './ReportUtils'; | ||
| import {getCurrency, getTagArrayFromName} from './TransactionUtils'; | ||
| import {getReportTransactions, isExpenseReport, isPolicyExpenseChat as isPolicyExpenseChatUtils} from './ReportUtils'; | ||
| import {getCurrency, getTagArrayFromName, isMerchantMissing, isScanRequest} from './TransactionUtils'; | ||
|
|
||
| function navigateToStartMoneyRequestStep(requestType: IOURequestType, iouType: IOUType, transactionID: string, reportID: string, iouAction?: IOUAction): void { | ||
| if (iouAction === CONST.IOU.ACTION.CATEGORIZE || iouAction === CONST.IOU.ACTION.SUBMIT || iouAction === CONST.IOU.ACTION.SHARE) { | ||
|
|
@@ -324,6 +325,34 @@ function formatCurrentUserToAttendee(currentUser?: PersonalDetails, reportID?: s | |
| return [initialAttendee]; | ||
| } | ||
|
|
||
| /** | ||
| * Checks if merchant is required and missing for a transaction. | ||
| * Merchant is required for policy expense chats, expense requests, or when any participant is a policy expense chat. | ||
| * For scan requests, merchant is not required unless it's a split bill being edited. | ||
| * | ||
| * @param transaction - The transaction to check | ||
| * @param report - The report associated with the transaction | ||
| * @param isEditingSplitBill - Whether this is editing a split bill | ||
| * @returns true if merchant is required and missing, false otherwise | ||
| */ | ||
| function shouldRequireMerchant(transaction: OnyxInputOrEntry<Transaction> | undefined, report: OnyxInputOrEntry<Report> | undefined, isEditingSplitBill = false): boolean { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ CONSISTENCY-6 (docs)The Suggested fix: function shouldRequireMerchant(transaction: OnyxInputOrEntry<Transaction> | undefined, report: OnyxInputOrEntry<Report> | undefined, isEditingSplitBill = false): boolean {
if (\!transaction) {
return false;
}
if (\!isMerchantMissing(transaction)) {
return false;
}
// For scan requests, merchant is not required unless it's a split bill being edited
if (isScanRequest(transaction) && \!isEditingSplitBill) {
return false;
}
// Add defensive check for participants array
const hasParticipantsWithPolicyExpenseChat = Array.isArray(transaction?.participants) &&
transaction.participants.some((participant) => \!\!participant?.isPolicyExpenseChat);
// Check if merchant is required based on report type and participants
return \!\!(isPolicyExpenseChatUtils(report) || isExpenseReport(report) || hasParticipantsWithPolicyExpenseChat);
}Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| if (!transaction) { | ||
| return false; | ||
| } | ||
|
|
||
| if (!isMerchantMissing(transaction)) { | ||
| return false; | ||
| } | ||
|
|
||
| // For scan requests, merchant is not required unless it's a split bill being edited | ||
| if (isScanRequest(transaction) && !isEditingSplitBill) { | ||
| return false; | ||
| } | ||
|
|
||
| // Check if merchant is required based on report type and participants | ||
| return !!(isPolicyExpenseChatUtils(report) || isExpenseReport(report) || transaction?.participants?.some((participant) => !!participant.isPolicyExpenseChat)); | ||
| } | ||
|
|
||
| function navigateToConfirmationPage( | ||
| iouType: IOUType, | ||
| transactionID: string, | ||
|
|
@@ -392,6 +421,7 @@ export { | |
| formatCurrentUserToAttendee, | ||
| navigateToParticipantPage, | ||
| shouldShowReceiptEmptyState, | ||
| shouldRequireMerchant, | ||
| navigateToConfirmationPage, | ||
| calculateDefaultReimbursable, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,7 @@ import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep'; | |
| import {setTransactionReport} from '@libs/actions/Transaction'; | ||
| import {convertToBackendAmount} from '@libs/CurrencyUtils'; | ||
| import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; | ||
| import {calculateDefaultReimbursable, isMovingTransactionFromTrackExpense, navigateToConfirmationPage, navigateToParticipantPage} from '@libs/IOUUtils'; | ||
| import {calculateDefaultReimbursable, isMovingTransactionFromTrackExpense, navigateToConfirmationPage, navigateToParticipantPage, shouldRequireMerchant} from '@libs/IOUUtils'; | ||
| import Navigation from '@libs/Navigation/Navigation'; | ||
| import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; | ||
| import {getPolicyExpenseChat, getReportOrDraftReport, getTransactionDetails, isMoneyRequestReport, isPolicyExpenseChat, isSelfDM, shouldEnableNegative} from '@libs/ReportUtils'; | ||
|
|
@@ -307,8 +307,14 @@ function IOURequestStepAmount({ | |
| setSplitShares(transaction, amountInSmallestCurrencyUnits, selectedCurrency || CONST.CURRENCY.USD, participantAccountIDs); | ||
| } | ||
| setMoneyRequestParticipantsFromReport(transactionID, report, currentUserPersonalDetails.accountID).then(() => { | ||
| // If merchant is required and missing, navigate to merchant step first | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ PERF-2 (docs)The merchant requirement check at line 310 is performed AFTER calling Suggested fix: // Check merchant requirement first to avoid unnecessary async work
if (shouldRequireMerchant(transaction, report, isEditingSplitBill)) {
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID, undefined, reportActionID, backToReport));
return;
}
setMoneyRequestParticipantsFromReport(transactionID, report, currentUserPersonalDetails.accountID).then(() => {
navigateToConfirmationPage(iouType, transactionID, reportID, backToReport);
});This avoids the async participant setup when it's not needed for the next screen. Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| if (shouldRequireMerchant(transaction, report, isEditingSplitBill)) { | ||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID, undefined, reportActionID, backToReport)); | ||
| return; | ||
| } | ||
| navigateToConfirmationPage(iouType, transactionID, reportID, backToReport); | ||
| }); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
|
|
@@ -324,7 +330,11 @@ function IOURequestStepAmount({ | |
| const resetToDefaultWorkspace = () => { | ||
| setTransactionReport(transactionID, {reportID: transactionReportID}, true); | ||
| setMoneyRequestParticipantsFromReport(transactionID, targetReport, currentUserPersonalDetails.accountID).then(() => { | ||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouTypeTrackOrSubmit, transactionID, targetReport?.reportID)); | ||
| if (transactionReportID === CONST.REPORT.UNREPORTED_REPORT_ID) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ PERF-2 (docs)The merchant requirement check at line 333 could be performed BEFORE calling Suggested fix: const resetToDefaultWorkspace = () => {
setTransactionReport(transactionID, {reportID: transactionReportID}, true);
// Check if we need merchant step before expensive participant setup
if (transactionReportID !== CONST.REPORT.UNREPORTED_REPORT_ID) {
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, targetReport?.reportID, undefined, reportActionID));
return;
}
setMoneyRequestParticipantsFromReport(transactionID, targetReport, currentUserPersonalDetails.accountID).then(() => {
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouTypeTrackOrSubmit, transactionID, targetReport?.reportID));
});
};This avoids the async participant operation when immediately navigating to the merchant step. Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouTypeTrackOrSubmit, transactionID, targetReport?.reportID)); | ||
| return; | ||
| } | ||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, targetReport?.reportID, undefined, reportActionID)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This branch now always sends users to the merchant step whenever Useful? React with 👍 / 👎. |
||
| }); | ||
| }; | ||
|
|
||
|
|
@@ -346,6 +356,10 @@ function IOURequestStepAmount({ | |
| const chatReportID = selectedReport?.chatReportID ?? selectedReport?.reportID; | ||
|
|
||
| Navigation.setNavigationActionToMicrotaskQueue(() => { | ||
| if (shouldRequireMerchant(transaction, selectedReport, isEditingSplitBill)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ PERF-2 (docs)The merchant requirement check at line 359 is performed AFTER calling Suggested fix: if (shouldRequireMerchant(transaction, selectedReport, isEditingSplitBill)) {
Navigation.setNavigationActionToMicrotaskQueue(() => {
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.CREATE, navigationIOUType, transactionID, chatReportID, undefined, reportActionID));
});
return;
}
Navigation.setNavigationActionToMicrotaskQueue(() => {
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, navigationIOUType, transactionID, chatReportID));
});This avoids setting up navigation to the confirmation page when the merchant page is the actual target. Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.CREATE, navigationIOUType, transactionID, chatReportID, undefined, reportActionID)); | ||
| return; | ||
| } | ||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, navigationIOUType, transactionID, chatReportID)); | ||
| }); | ||
| } else { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import React, {useCallback, useEffect, useRef, useState} from 'react'; | ||
| import {useFocusEffect} from '@react-navigation/native'; | ||
| import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; | ||
| import {InteractionManager, View} from 'react-native'; | ||
| import FormProvider from '@components/Form/FormProvider'; | ||
| import InputWrapper from '@components/Form/InputWrapper'; | ||
|
|
@@ -21,6 +22,7 @@ import {setMoneyRequestMerchant, updateMoneyRequestMerchant} from '@userActions/ | |
| import {setDraftSplitTransaction} from '@userActions/IOU/Split'; | ||
| import CONST from '@src/CONST'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import ROUTES from '@src/ROUTES'; | ||
| import type SCREENS from '@src/SCREENS'; | ||
| import INPUT_IDS from '@src/types/form/MoneyRequestMerchantForm'; | ||
| import {isEmptyObject} from '@src/types/utils/EmptyObject'; | ||
|
|
@@ -36,7 +38,7 @@ type IOURequestStepMerchantProps = WithWritableReportOrNotFoundProps<typeof SCRE | |
|
|
||
| function IOURequestStepMerchant({ | ||
| route: { | ||
| params: {transactionID, reportID, backTo, action, iouType, reportActionID}, | ||
| params: {transactionID, reportID, backTo, action, iouType, reportActionID, backToReport}, | ||
| }, | ||
| transaction, | ||
| report, | ||
|
|
@@ -69,19 +71,35 @@ function IOURequestStepMerchant({ | |
| const {isBetaEnabled} = usePermissions(); | ||
| const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); | ||
|
|
||
| const isMerchantRequired = isPolicyExpenseChat(report) || isExpenseRequest(report) || transaction?.participants?.some((participant) => !!participant.isPolicyExpenseChat); | ||
| const isMerchantRequired = useMemo(() => { | ||
| if (isEditing) { | ||
| return isPolicyExpenseChat(report) || isExpenseRequest(report); | ||
| } | ||
| return transaction?.participants?.some((participant) => !!participant.isPolicyExpenseChat); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ PERF-6 (docs)The Suggested fix: // Remove useFocusEffect - state will naturally reset when component remounts
// The currentMerchant state is already initialized from initialMerchant
const [currentMerchant, setCurrentMerchant] = useState(initialMerchant);If you need to respond to prop changes, consider using the Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| }, [isEditing, report, transaction?.participants]); | ||
|
|
||
| const navigateBack = useCallback(() => { | ||
| Navigation.goBack(backTo); | ||
| }, [backTo]); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ PERF-6 (docs)The navigation logic inside Suggested fix: const updateMerchant = (value: FormOnyxValues<typeof ONYXKEYS.FORMS.MONEY_REQUEST_MERCHANT_FORM>) => {
const newMerchant = value.moneyRequestMerchant?.trim();
// ... existing validation logic ...
// Compute navigation target directly
const shouldNavigateToConfirmation = !isEditing && !backTo;
if (shouldNavigateToConfirmation) {
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, iouType, transactionID, reportID, backToReport, undefined, Navigation.getActiveRoute()));
} else {
Navigation.goBack(backTo);
}
};This eliminates the need for the Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
|
|
||
| useFocusEffect( | ||
| useCallback(() => { | ||
| setIsSaved(false); | ||
| setCurrentMerchant(initialMerchant); | ||
| }, [initialMerchant]), | ||
| ); | ||
|
|
||
| useEffect(() => { | ||
| if (!isSaved || !shouldNavigateAfterSaveRef.current) { | ||
| return; | ||
| } | ||
| shouldNavigateAfterSaveRef.current = false; | ||
| if (!isEditing && !backTo) { | ||
| Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, iouType, transactionID, reportID, backToReport, undefined, Navigation.getActiveRoute())); | ||
| return; | ||
| } | ||
| navigateBack(); | ||
| }, [isSaved, navigateBack]); | ||
| }, [isSaved, navigateBack, action, iouType, transactionID, reportID, backTo, isEditing, backToReport]); | ||
|
|
||
| const validate = useCallback( | ||
| (value: FormOnyxValues<typeof ONYXKEYS.FORMS.MONEY_REQUEST_MERCHANT_FORM>) => { | ||
|
|
@@ -165,6 +183,7 @@ function IOURequestStepMerchant({ | |
| inputID={INPUT_IDS.MONEY_REQUEST_MERCHANT} | ||
| name={INPUT_IDS.MONEY_REQUEST_MERCHANT} | ||
| defaultValue={initialMerchant} | ||
| value={currentMerchant} | ||
| onValueChange={updateMerchantRef} | ||
| label={translate('common.merchant')} | ||
| accessibilityLabel={translate('common.merchant')} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,7 +22,7 @@ import {isPaidGroupPolicy} from '@libs/PolicyUtils'; | |
| import {findSelfDMReportID, generateReportID, isInvoiceRoomWithID} from '@libs/ReportUtils'; | ||
| import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; | ||
| import {endSpan} from '@libs/telemetry/activeSpans'; | ||
| import {getRequestType, hasRoute, isCorporateCardTransaction, isDistanceRequest, isPerDiemRequest} from '@libs/TransactionUtils'; | ||
| import {getRequestType, hasRoute, isCorporateCardTransaction, isDistanceRequest, isMerchantMissing, isPerDiemRequest} from '@libs/TransactionUtils'; | ||
| import MoneyRequestParticipantsSelector from '@pages/iou/request/MoneyRequestParticipantsSelector'; | ||
| import { | ||
| navigateToStartStepIfScanFileCannotBeRead, | ||
|
|
@@ -38,6 +38,7 @@ import {createDraftWorkspace} from '@userActions/Policy/Policy'; | |
| import CONST from '@src/CONST'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import ROUTES from '@src/ROUTES'; | ||
| import type {Route} from '@src/ROUTES'; | ||
| import type SCREENS from '@src/SCREENS'; | ||
| import type {Policy} from '@src/types/onyx'; | ||
| import type {Participant} from '@src/types/onyx/IOU'; | ||
|
|
@@ -88,6 +89,7 @@ function IOURequestStepParticipants({ | |
|
|
||
| // We need to set selectedReportID if user has navigated back from confirmation page and navigates to confirmation page with already selected participant | ||
| const selectedReportID = useRef<string>(participants?.length === 1 ? (participants.at(0)?.reportID ?? reportID) : reportID); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ CONSISTENCY-4 (docs)The Suggested fix: // Remove line 91:
// const selectedParticipants = useRef<Participant[]>(participants);
// Remove line 226:
// selectedParticipants.current = val;
// At line 341, use val or participants directly:
const firstParticipant = participants?.at(0); // or use _participants parameter if availablePlease rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| const selectedParticipants = useRef<Participant[]>(participants); | ||
| const numberOfParticipants = useRef(participants?.length ?? 0); | ||
| const iouRequestType = getRequestType(initialTransaction); | ||
| const isSplitRequest = iouType === CONST.IOU.TYPE.SPLIT; | ||
|
|
@@ -221,6 +223,7 @@ function IOURequestStepParticipants({ | |
| (val: Participant[]) => { | ||
| HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); | ||
|
|
||
| selectedParticipants.current = val; | ||
| const firstParticipant = val.at(0); | ||
|
|
||
| if (firstParticipant?.isSelfDM && !isSplitRequest) { | ||
|
|
@@ -335,6 +338,12 @@ function IOURequestStepParticipants({ | |
| return; | ||
| } | ||
|
|
||
| const firstParticipant = selectedParticipants.current?.at(0); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ PERF-2 (docs)The merchant requirement check is performed after several expensive operations including setting transaction report, split shares, and other transaction manipulations. This check could be moved earlier to avoid unnecessary work. Suggested fix: const goToNextStep = useCallback(
(_value?: string, _participants?: Participant[]) => {
const isCategorizing = action === CONST.IOU.ACTION.CATEGORIZE;
const isShareAction = action === CONST.IOU.ACTION.SHARE;
// Check merchant requirement early
const firstParticipant = _participants?.at(0) || participants?.at(0);
const isMerchantRequired =
\!\!firstParticipant?.isPolicyExpenseChat &&
isMerchantMissing(initialTransaction) &&
(iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL || (isMovingTransactionFromTrackExpense && iouRequestType === CONST.IOU.REQUEST_TYPE.TIME));
// ... rest of the logic
},
// ...
);This avoids performing split share calculations and other operations when the user will immediately navigate to the merchant page. Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| const isMerchantRequired = | ||
| !!firstParticipant?.isPolicyExpenseChat && | ||
| isMerchantMissing(initialTransaction) && | ||
| (iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL || (isMovingTransactionFromTrackExpense && iouRequestType === CONST.IOU.REQUEST_TYPE.TIME)); | ||
|
|
||
| const iouConfirmationPageRoute = ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute( | ||
| action, | ||
| iouType === CONST.IOU.TYPE.CREATE || iouType === CONST.IOU.TYPE.TRACK ? CONST.IOU.TYPE.SUBMIT : iouType, | ||
|
|
@@ -345,21 +354,34 @@ function IOURequestStepParticipants({ | |
| action === CONST.IOU.ACTION.SHARE ? Navigation.getActiveRoute() : undefined, | ||
| ); | ||
|
|
||
| const route = isCategorizing | ||
| ? ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, iouType, initialTransactionID, selectedReportID.current || reportID, iouConfirmationPageRoute) | ||
| : iouConfirmationPageRoute; | ||
| let route: Route = iouConfirmationPageRoute; | ||
|
|
||
| if (isCategorizing) { | ||
| route = ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, iouType, initialTransactionID, selectedReportID.current || reportID, iouConfirmationPageRoute); | ||
| } else if (isMerchantRequired) { | ||
| route = ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute( | ||
| action, | ||
| iouType === CONST.IOU.TYPE.CREATE || iouType === CONST.IOU.TYPE.TRACK ? CONST.IOU.TYPE.SUBMIT : iouType, | ||
| initialTransactionID, | ||
| newReportID, | ||
| ); | ||
| } | ||
|
|
||
| Performance.markStart(CONST.TIMING.OPEN_CREATE_EXPENSE_APPROVE); | ||
| waitForKeyboardDismiss(() => { | ||
| // If the backTo parameter is set, we should navigate back to the confirmation screen that is already on the stack. | ||
| // We wrap navigation in setNavigationActionToMicrotaskQueue so that data loading in Onyx and navigation do not occur simultaneously, which resets the amount to 0. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ CONSISTENCY-6 (docs)The navigation logic has complex conditional branching with multiple paths ( Suggested fix: // Navigation logic:
// 1. If merchant is required and backTo is set: go back first, then replace with merchant page
// 2. If merchant is required without backTo: navigate to merchant page with forceReplace
// 3. If merchant not required and backTo is set: go back to confirmation
// 4. Otherwise: navigate normally to confirmation or category page
if (backTo && !isMerchantRequired) {
// We don't want to compare params because we just changed the participants.
Navigation.goBack(route, {compareParams: false});
} else {
// If the merchant step is required and the backTo parameter is set, we need to go back to the confirmation screen first
if (isMerchantRequired && backTo) {
Navigation.goBack();
}
Navigation.navigate(route, {forceReplace: isMerchantRequired && !!backTo});
}Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency. |
||
| // More information can be found here: https://github.com/Expensify/App/issues/73728 | ||
| Navigation.setNavigationActionToMicrotaskQueue(() => { | ||
| if (backTo) { | ||
| if (backTo && !isMerchantRequired) { | ||
| // We don't want to compare params because we just changed the participants. | ||
| Navigation.goBack(route, {compareParams: false}); | ||
| } else { | ||
| Navigation.navigate(route); | ||
| // If the merchant step is required and the backTo parameter is set, we need to go back the the confirmation screen first and then navigate to the merchant page with forceReplace to remove this screen from the stack | ||
| if (isMerchantRequired && backTo) { | ||
| Navigation.goBack(); | ||
| } | ||
| Navigation.navigate(route, {forceReplace: isMerchantRequired && !!backTo}); | ||
| } | ||
| }); | ||
| }); | ||
|
|
@@ -369,14 +391,15 @@ function IOURequestStepParticipants({ | |
| participants, | ||
| iouType, | ||
| initialTransaction, | ||
| iouRequestType, | ||
| initialTransactionID, | ||
| reportID, | ||
| waitForKeyboardDismiss, | ||
| transactions, | ||
| isMovingTransactionFromTrackExpense, | ||
| allPolicies, | ||
| policyForMovingExpenses, | ||
| introSelected, | ||
| reportID, | ||
| backTo, | ||
| selfDMReportID, | ||
| ], | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ CONSISTENCY-2 (docs)
The route generation logic constructs query parameters and paths manually using string concatenation. While functional, this approach is error-prone and makes it harder to understand the relationship between
reportActionIDandbackToReportparameters.Suggested fix:
Add comments to clarify the parameter precedence and construction logic:
Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.