diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index c801dbdf40b3..ae1b3b363e6c 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -10,7 +10,6 @@ import MenuItem from '@components/MenuItem'; import Modal from '@components/Modal'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; -import openSearchReport from '@components/Search/openSearchReport'; import {useSearchContext} from '@components/Search/SearchContext'; import type {SearchColumnType, SortOrder} from '@components/Search/types'; import Text from '@components/Text'; @@ -50,6 +49,7 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import NAVIGATORS from '@src/NAVIGATORS'; 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 MoneyRequestReportTableHeader from './MoneyRequestReportTableHeader'; @@ -266,7 +266,7 @@ function MoneyRequestReportTransactionList({ if (reportIDToNavigate) { markReportIDAsExpense(reportIDToNavigate); } - openSearchReport(routeParams.reportID, backTo); + Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute(routeParams)); }); }, [report, reportActions, sortedTransactions, markReportIDAsExpense], diff --git a/src/components/Navigation/TopBar.tsx b/src/components/Navigation/TopBar.tsx index fa8118f494f3..84eb0a5a8c6e 100644 --- a/src/components/Navigation/TopBar.tsx +++ b/src/components/Navigation/TopBar.tsx @@ -1,4 +1,4 @@ -import React, {useContext} from 'react'; +import React from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import LoadingBar from '@components/LoadingBar'; @@ -6,7 +6,6 @@ import {PressableWithoutFeedback} from '@components/Pressable'; import SearchButton from '@components/Search/SearchRouter/SearchButton'; import HelpButton from '@components/SidePanel/HelpComponents/HelpButton'; import Text from '@components/Text'; -import {WideRHPContext} from '@components/WideRHPContextProvider'; import useLoadingBarVisibility from '@hooks/useLoadingBarVisibility'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -33,8 +32,6 @@ function TopBar({breadcrumbLabel, shouldDisplaySearch = true, shouldDisplayHelpB const [session] = useOnyx(ONYXKEYS.SESSION, {selector: authTokenTypeSelector, canBeMissing: true}); const shouldShowLoadingBarForReports = useLoadingBarVisibility(); const isAnonymousUser = isAnonymousUserUtil(session); - const {wideRHPRouteKeys} = useContext(WideRHPContext); - const isWideRhpVisible = !!wideRHPRouteKeys.length; const displaySignIn = isAnonymousUser; const displaySearch = !isAnonymousUser && shouldDisplaySearch; @@ -71,7 +68,7 @@ function TopBar({breadcrumbLabel, shouldDisplaySearch = true, shouldDisplayHelpB {shouldDisplayHelpButton && } {displaySearch && } - + ); } diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 26a8eda50c60..838032476bbd 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -72,7 +72,6 @@ import type {SearchTransaction} from '@src/types/onyx/SearchResults'; import type {TransactionViolation} from '@src/types/onyx/TransactionViolation'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import arraysEqual from '@src/utils/arraysEqual'; -import openSearchReport from './openSearchReport'; import {useSearchContext} from './SearchContext'; import SearchList from './SearchList'; import {SearchScopeProvider} from './SearchScopeProvider'; @@ -711,7 +710,7 @@ function Search({ setOptimisticDataForTransactionThreadPreview(item, transactionPreviewData); } - openSearchReport(reportID, backTo); + requestAnimationFrame(() => Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID, backTo}))); }, [isMobileSelectionModeEnabled, type, toggleTransaction, hash, queryJSON, handleSearch, searchKey, markReportIDAsExpense], ); diff --git a/src/components/Search/openSearchReport/index.native.ts b/src/components/Search/openSearchReport/index.native.ts deleted file mode 100644 index 4929d1a49257..000000000000 --- a/src/components/Search/openSearchReport/index.native.ts +++ /dev/null @@ -1,6 +0,0 @@ -import Navigation from '@libs/Navigation/Navigation'; -import ROUTES from '@src/ROUTES'; - -export default function openSearchReport(reportID: string | undefined, backTo: string) { - requestAnimationFrame(() => Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID, backTo}))); -} diff --git a/src/components/Search/openSearchReport/index.ts b/src/components/Search/openSearchReport/index.ts deleted file mode 100644 index 3b6cf0179977..000000000000 --- a/src/components/Search/openSearchReport/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {CommonActions} from '@react-navigation/native'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; - -// The search report screen is preloaded before navigating to avoid lag when opening the page. If the content is rendered in the background and then navigated, the opening experience is smoother. -export default function openSearchReport(reportID: string | undefined, backTo: string) { - navigationRef.dispatch({ - ...CommonActions.preload(NAVIGATORS.RIGHT_MODAL_NAVIGATOR, { - name: SCREENS.RIGHT_MODAL.SEARCH_REPORT, - params: {reportID, backTo}, - }), - target: navigationRef.getRootState().key, - }); - requestAnimationFrame(() => Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID, backTo}))); -} diff --git a/src/components/WideRHPContextProvider/index.tsx b/src/components/WideRHPContextProvider/index.tsx index cde7c8f11c88..07a327d95719 100644 --- a/src/components/WideRHPContextProvider/index.tsx +++ b/src/components/WideRHPContextProvider/index.tsx @@ -61,22 +61,6 @@ function extractNavigationKeys(state: NavigationState | PartialState isFullScreenName(route.name)); - const lastRHPRouteIndex = state.routes.findLastIndex((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); - - // Both routes have to be present and the RHP have to be after last full screen for it to be visible. - if (lastFullScreenRouteIndex === -1 || lastRHPRouteIndex === -1 || lastFullScreenRouteIndex > lastRHPRouteIndex) { - return undefined; - } - - return state?.routes.at(lastRHPRouteIndex)?.key; -} - /** * Calculates the optimal width for the receipt pane RHP based on window width. * Ensures the RHP doesn't exceed maximum width and maintains minimum responsive width. @@ -115,6 +99,23 @@ function WideRHPContextProvider({children}: React.PropsWithChildren) { const [expenseReportIDs, setExpenseReportIDs] = useState>(new Set()); const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {selector: expenseReportSelector, canBeMissing: true}); + // Return undefined if RHP is not the last route + const lastVisibleRHPRouteKey = useRootNavigationState((state) => { + // Safe handling when navigation is not yet initialized + if (!state) { + return undefined; + } + const lastFullScreenRouteIndex = state?.routes.findLastIndex((route) => isFullScreenName(route.name)); + const lastRHPRouteIndex = state?.routes.findLastIndex((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); + + // Both routes have to be present and the RHP have to be after last full screen for it to be visible. + if (lastFullScreenRouteIndex === -1 || lastRHPRouteIndex === -1 || lastFullScreenRouteIndex > lastRHPRouteIndex) { + return undefined; + } + + return state?.routes.at(lastRHPRouteIndex)?.key; + }); + const wideRHPRouteKeys = useMemo(() => { const rootState = navigationRef.getRootState(); @@ -122,7 +123,6 @@ function WideRHPContextProvider({children}: React.PropsWithChildren) { return []; } - const lastVisibleRHPRouteKey = getLastVisibleRHPRouteKey(rootState); const lastRHPRoute = rootState.routes.find((route) => route.key === lastVisibleRHPRouteKey); if (!lastRHPRoute) { @@ -133,7 +133,7 @@ function WideRHPContextProvider({children}: React.PropsWithChildren) { const currentKeys = allWideRHPRouteKeys.filter((key) => lastRHPKeys.has(key)); return currentKeys; - }, [allWideRHPRouteKeys]); + }, [allWideRHPRouteKeys, lastVisibleRHPRouteKey]); /** * Determines whether the secondary overlay should be displayed. diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 3b00ade78aff..99e81ced4463 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -7,7 +7,6 @@ import type DotLottieAnimation from '@components/LottieAnimations/types'; import type {MenuItemWithLink} from '@components/MenuItemList'; import type {MultiSelectItem} from '@components/Search/FilterDropdowns/MultiSelectPopup'; import type {SingleSelectItem} from '@components/Search/FilterDropdowns/SingleSelectPopup'; -import openSearchReport from '@components/Search/openSearchReport'; import type { SearchAction, SearchColumnType, @@ -1313,7 +1312,7 @@ function createAndOpenSearchTransactionThread(item: TransactionListItemType, has } if (shouldNavigate) { - openSearchReport(transactionThreadReport?.reportID, backTo); + Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID: transactionThreadReport?.reportID, backTo})); } } diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index 883276608a40..5027b2d3cac4 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -1,6 +1,5 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import openSearchReport from '@components/Search/openSearchReport'; import ChatListItem from '@components/SelectionListWithSections/ChatListItem'; import TransactionGroupListItem from '@components/SelectionListWithSections/Search/TransactionGroupListItem'; import TransactionListItem from '@components/SelectionListWithSections/Search/TransactionListItem'; @@ -13,6 +12,7 @@ import type { TransactionReportGroupListItemType, TransactionWithdrawalIDGroupListItemType, } from '@components/SelectionListWithSections/types'; +import Navigation from '@navigation/Navigation'; // eslint-disable-next-line no-restricted-syntax import type * as ReportUserActions from '@userActions/Report'; import {createTransactionThreadReport} from '@userActions/Report'; @@ -25,6 +25,7 @@ import IntlStore from '@src/languages/IntlStore'; import type {CardFeedForDisplay} from '@src/libs/CardFeedUtils'; import * as SearchUIUtils from '@src/libs/SearchUIUtils'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Connections} from '@src/types/onyx/Policy'; import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; @@ -44,7 +45,6 @@ jest.mock('@userActions/Search', () => ({ ...jest.requireActual('@userActions/Search'), updateSearchResultsWithTransactionThreadReportID: jest.fn(), })); -jest.mock('@components/Search/openSearchReport', () => jest.fn()); const adminAccountID = 18439984; const adminEmail = 'admin@policy.com'; @@ -2876,12 +2876,12 @@ describe('SearchUIUtils', () => { test('Should not navigate if shouldNavigate = false', () => { SearchUIUtils.createAndOpenSearchTransactionThread(transactionListItem, hash, backTo, undefined, false); - expect(openSearchReport).not.toHaveBeenCalled(); + expect(Navigation.navigate).not.toHaveBeenCalled(); }); test('Should handle navigation if shouldNavigate = true', () => { SearchUIUtils.createAndOpenSearchTransactionThread(transactionListItem, hash, backTo, undefined, true); - expect(openSearchReport).toHaveBeenCalledWith(threadReportID, backTo); + expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.SEARCH_REPORT.getRoute({reportID: threadReportID, backTo})); }); });