-
Notifications
You must be signed in to change notification settings - Fork 3.9k
refactor: Remove shouldHandleNavigation from sendMoney and submitPerDiemExpense #86619
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
Merged
Valforte
merged 20 commits into
Expensify:main
from
TaduJR:refactor-code-to-keep-navigation-handling-in-the-UI-components
Apr 13, 2026
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
a0da86a
refactor: Add navigateAfterExpenseCreate and dismissModalAndOpenRepor…
TaduJR e1cc99a
refactor: Wire up sendMoney callers to use dismissModalAndOpenReportI…
TaduJR 03099eb
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR e66ff45
refactor: Remove shouldHandleNavigation from submitPerDiemExpense and…
TaduJR 8c9bf99
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR d700b5e
refactor: sendMoney to params object and pre-generate optimistic chat…
TaduJR 2b58745
fix: per-diem policy expense chat lookup and guard navigation on earl…
TaduJR c86cc79
fix: Add getChatByParticipants fallback for expense report chat resol…
TaduJR 3a3eda5
fix: Extract resolveOptimisticChatReportID helper and deduplicate dis…
TaduJR 328511c
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR 5dfa313
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR dd99009
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR a275c58
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR 143a765
test: Add unit tests for navigation helpers and resolveOptimisticChat…
TaduJR 80708af
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR f4d4f40
chore: CI restart
TaduJR 2b7d7d3
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR 8a07284
fix: Restore sync-first navigation optimization and replace getReport…
TaduJR f83047e
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR 0d3f409
Merge branch 'main' of https://github.com/TaduJR/App into refactor-co…
TaduJR File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
src/libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| import {InteractionManager} from 'react-native'; | ||
| import getIsNarrowLayout from '@libs/getIsNarrowLayout'; | ||
| import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; | ||
| import {getSpan} from '@libs/telemetry/activeSpans'; | ||
| import {endSubmitFollowUpActionSpan, setPendingSubmitFollowUpAction} from '@libs/telemetry/submitFollowUpAction'; | ||
| import CONST from '@src/CONST'; | ||
| import ROUTES from '@src/ROUTES'; | ||
| import isReportOpenInRHP from './isReportOpenInRHP'; | ||
| import isReportOpenInSuperWideRHP from './isReportOpenInSuperWideRHP'; | ||
| import isSearchTopmostFullScreenRoute from './isSearchTopmostFullScreenRoute'; | ||
| import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; | ||
|
|
||
| /** | ||
| * After finishing the action in RHP from the Inbox tab, besides dismissing the modal, we should open the report. | ||
| * If the action is done from the report RHP, then we just want to dismiss the money request flow screens. | ||
| */ | ||
| function dismissModalAndOpenReportInInboxTab(reportID: string | undefined, isInvoice: boolean | undefined, hasMultipleTransactions: boolean) { | ||
| const rootState = navigationRef.getRootState(); | ||
| const hasSubmitToDestinationVisibleSpan = !!getSpan(CONST.TELEMETRY.SPAN_SUBMIT_TO_DESTINATION_VISIBLE); | ||
|
|
||
| if (!isInvoice && isReportOpenInRHP(rootState)) { | ||
| const rhpKey = rootState.routes.at(-1)?.state?.key; | ||
| if (rhpKey) { | ||
| const isSuperWideRHP = isReportOpenInSuperWideRHP(rootState); | ||
|
|
||
| // submit_follow_up_action: only set when the span was started. | ||
| if (hasSubmitToDestinationVisibleSpan) { | ||
| if (isSuperWideRHP) { | ||
| setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY, reportID); | ||
| } else if (hasMultipleTransactions && reportID) { | ||
| setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_AND_OPEN_REPORT, reportID); | ||
| } else { | ||
| setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY, reportID); | ||
| } | ||
| } | ||
| // When a report is opened in the super wide RHP, we need to dismiss to the first RHP to show the same report with new expense. | ||
| if (isSuperWideRHP) { | ||
| Navigation.dismissToPreviousRHP(); | ||
| return; | ||
| } | ||
| // When a report with one expense is opened in the wide RHP and the user adds another expense, RHP should be dismissed and ROUTES.SEARCH_MONEY_REQUEST_REPORT should be displayed. | ||
| if (hasMultipleTransactions && reportID) { | ||
| // On small screens, dismiss all modals and then navigate to the right report. | ||
| // On large screens, dismiss to the previous RHP first, then replace the current route with the new report. | ||
| const isNarrowLayout = getIsNarrowLayout(); | ||
| if (isNarrowLayout) { | ||
| Navigation.dismissModal(); | ||
| } else { | ||
| Navigation.dismissToPreviousRHP(); | ||
| } | ||
| setNavigationActionToMicrotaskQueue(() => { | ||
| Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID}), {forceReplace: !isNarrowLayout}); | ||
| }); | ||
| return; | ||
| } | ||
| Navigation.pop(rhpKey); | ||
| return; | ||
| } | ||
| } | ||
| if (isSearchTopmostFullScreenRoute() || !reportID) { | ||
| if (hasSubmitToDestinationVisibleSpan) { | ||
| setPendingSubmitFollowUpAction(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY); | ||
| } | ||
| Navigation.dismissModal(); | ||
| if (hasSubmitToDestinationVisibleSpan) { | ||
| // eslint-disable-next-line @typescript-eslint/no-deprecated -- we need to wait for the modal to be dismissed before marking the span | ||
| InteractionManager.runAfterInteractions(() => { | ||
| endSubmitFollowUpActionSpan(CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY); | ||
| }); | ||
| } | ||
| return; | ||
| } | ||
| if (hasSubmitToDestinationVisibleSpan) { | ||
| Navigation.dismissModalWithReport({reportID}, undefined, { | ||
| onBeforeNavigate: (willOpenReport) => { | ||
| setPendingSubmitFollowUpAction( | ||
| willOpenReport ? CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_AND_OPEN_REPORT : CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY, | ||
| reportID, | ||
| ); | ||
| }, | ||
| }); | ||
| } else { | ||
| Navigation.dismissModalWithReport({reportID}); | ||
| } | ||
| } | ||
|
|
||
| export default dismissModalAndOpenReportInInboxTab; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| import getIsNarrowLayout from '@libs/getIsNarrowLayout'; | ||
| import Log from '@libs/Log'; | ||
| import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; | ||
| import {buildCannedSearchQuery, getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils'; | ||
| import {setPendingSubmitFollowUpAction} from '@libs/telemetry/submitFollowUpAction'; | ||
| import CONST from '@src/CONST'; | ||
| import NAVIGATORS from '@src/NAVIGATORS'; | ||
| import ROUTES from '@src/ROUTES'; | ||
| import SCREENS from '@src/SCREENS'; | ||
| import dismissModalAndOpenReportInInboxTab from './dismissModalAndOpenReportInInboxTab'; | ||
| import isReportTopmostSplitNavigator from './isReportTopmostSplitNavigator'; | ||
| import isSearchTopmostFullScreenRoute from './isSearchTopmostFullScreenRoute'; | ||
|
|
||
| type NavigateAfterExpenseCreateParams = { | ||
| activeReportID?: string; | ||
| transactionID?: string; | ||
| isFromGlobalCreate?: boolean; | ||
| isInvoice?: boolean; | ||
| hasMultipleTransactions: boolean; | ||
| }; | ||
|
|
||
| /** | ||
| * Helper to navigate after an expense is created in order to standardize the post‑creation experience | ||
| * when creating an expense from the global create button. | ||
| * If the expense is created from the global create button then: | ||
| * - If it is created on the inbox tab, it will open the chat report containing that expense. | ||
| * - If it is created elsewhere, it will navigate to Reports > Expense and highlight the newly created expense. | ||
| */ | ||
| function navigateAfterExpenseCreate({activeReportID, transactionID, isFromGlobalCreate, isInvoice, hasMultipleTransactions}: NavigateAfterExpenseCreateParams) { | ||
| const isUserOnInbox = isReportTopmostSplitNavigator(); | ||
|
|
||
| // If the expense is not created from global create or is currently on the inbox tab, | ||
| // we just need to dismiss the money request flow screens | ||
| // and open the report chat containing the IOU report | ||
| if (!isFromGlobalCreate || isUserOnInbox || !transactionID) { | ||
| dismissModalAndOpenReportInInboxTab(activeReportID, isInvoice, hasMultipleTransactions); | ||
| return; | ||
| } | ||
|
|
||
| const type = isInvoice ? CONST.SEARCH.DATA_TYPES.INVOICE : CONST.SEARCH.DATA_TYPES.EXPENSE; | ||
|
|
||
| // When already on Search ROOT with the same type (expense vs invoice), we navigate to the same screen (no-op or refresh); record as dismiss_modal_only. | ||
| // When on another Search sub-tab (e.g. Chats), or on Search with a different type (e.g. on Invoice, submitting expense), record as navigate_to_search. | ||
| const rootState = navigationRef.getRootState(); | ||
| const searchNavigatorRoute = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR); | ||
| const lastSearchRoute = searchNavigatorRoute?.state?.routes?.at(-1); | ||
| const alreadyOnSearchRoot = isSearchTopmostFullScreenRoute() && lastSearchRoute?.name === SCREENS.SEARCH.ROOT; | ||
| const currentSearchQueryJSON = alreadyOnSearchRoot ? getCurrentSearchQueryJSON() : undefined; | ||
| const isSameSearchType = currentSearchQueryJSON?.type === type; | ||
| setPendingSubmitFollowUpAction( | ||
| alreadyOnSearchRoot && isSameSearchType ? CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.DISMISS_MODAL_ONLY : CONST.TELEMETRY.SUBMIT_FOLLOW_UP_ACTION.NAVIGATE_TO_SEARCH, | ||
| ); | ||
|
|
||
| const queryString = buildCannedSearchQuery({type}); | ||
| const navigateToSearch = () => { | ||
| // On the fast path, onConfirm already cleared the flag and dismissed the modal, | ||
| // so this branch is only reached on the slow path (user submitted before the | ||
| // 300ms pre-insert timer fired). | ||
| if (getIsNarrowLayout() && Navigation.getIsFullscreenPreInsertedUnderRHP()) { | ||
| Navigation.clearFullscreenPreInsertedFlag(); | ||
| Navigation.dismissModal(); | ||
| } else if (getIsNarrowLayout()) { | ||
| const isRHPStillOnTop = navigationRef.getRootState()?.routes?.at(-1)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; | ||
| if (!alreadyOnSearchRoot || !isSameSearchType || isRHPStillOnTop) { | ||
| Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: queryString}), {forceReplace: true}); | ||
| } else { | ||
| Log.info('[IOU] navigateToSearch: already on matching Search root with RHP dismissed — no-op'); | ||
| } | ||
| } else { | ||
| Navigation.revealRouteBeforeDismissingModal(ROUTES.SEARCH_ROOT.getRoute({query: queryString})); | ||
| } | ||
| }; | ||
|
|
||
| if (navigationRef.isReady()) { | ||
| navigateToSearch(); | ||
| } else { | ||
| Navigation.isNavigationReady().then(navigateToSearch); | ||
| } | ||
| } | ||
|
|
||
| export default navigateAfterExpenseCreate; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.