From ce177bbfcc72fe03785772e382d1840ed4f8e41a Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Mon, 25 Aug 2025 11:45:16 +0200 Subject: [PATCH 01/21] fix create new report while cycling via reports --- src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx | 5 +++++ src/types/onyx/ReportNavigation.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 08c8505a3e9ff..d3a73b77314ae 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -48,6 +48,7 @@ import {generateReportID, getDisplayNameForParticipant, getIcons, getReportName, import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import variables from '@styles/variables'; import closeReactNativeApp from '@userActions/HybridApp'; +import saveLastSearchParams from '@userActions/ReportNavigation'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -102,6 +103,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true}); + const [lastSearchResults] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true}); const policyChatForActivePolicy = useMemo(() => { if (isEmptyObject(activePolicy) || !activePolicy?.isPolicyExpenseChatEnabled) { return {} as OnyxTypes.Report; @@ -439,6 +441,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT : []), ...(shouldShowCreateReportOption ? [ + // tu robimy report duuuuupa { icon: Expensicons.Document, text: translate('report.newReport.createReport'), @@ -460,6 +463,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT workspaceIDForReportCreation = groupPoliciesWithChatEnabled.at(0)?.id; } + saveLastSearchParams({}); + if (!workspaceIDForReportCreation || (shouldRestrictUserBillableActions(workspaceIDForReportCreation) && groupPoliciesWithChatEnabled.length > 1)) { // If we couldn't guess the workspace to create the report, or a guessed workspace is past it's grace period and we have other workspaces to choose from Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION); diff --git a/src/types/onyx/ReportNavigation.ts b/src/types/onyx/ReportNavigation.ts index 07c6ef04a7eb5..a7af1edf38ba2 100644 --- a/src/types/onyx/ReportNavigation.ts +++ b/src/types/onyx/ReportNavigation.ts @@ -23,7 +23,7 @@ type LastSearchParams = { /** * The full query JSON object that was used in the last search. */ - queryJSON: SearchQueryJSON; + queryJSON?: SearchQueryJSON; /** * The current offset used in pagination for fetching the previous set of results. */ From ec0c2950deb151711db7c351333736bc1a8c68de Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Mon, 25 Aug 2025 14:03:59 +0200 Subject: [PATCH 02/21] working fix --- .../MoneyRequestReportNavigation.tsx | 4 ++-- .../helpers/isReportInSearchContext.ts | 18 ++++++++++++++++++ .../sidebar/FloatingActionButtonAndPopover.tsx | 15 +++++++++------ 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/libs/Navigation/helpers/isReportInSearchContext.ts diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 4dc2e2878550a..07f188ffa124b 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -61,7 +61,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion, bac const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; const hidePrevButton = currentIndex === 0; const styles = useThemeStyles(); - const shouldDisplayNavigationArrows = allReports && allReports.length > 1; + const shouldDisplayNavigationArrows = allReports && allReports.length > 1 && !(currentIndex === -1 || !lastSearchQuery?.queryJSON); useEffect(() => { if (!lastSearchQuery?.queryJSON) { @@ -98,7 +98,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion, bac }; const goToNextReport = () => { - if (currentIndex === -1 || allReports.length === 0) { + if (currentIndex === -1 || allReports.length === 0 || !lastSearchQuery?.queryJSON) { return ''; } if (currentIndex > allReports.length * 0.75 && lastSearchQuery?.hasMoreResults) { diff --git a/src/libs/Navigation/helpers/isReportInSearchContext.ts b/src/libs/Navigation/helpers/isReportInSearchContext.ts new file mode 100644 index 0000000000000..bd758c4dcc825 --- /dev/null +++ b/src/libs/Navigation/helpers/isReportInSearchContext.ts @@ -0,0 +1,18 @@ +import {navigationRef} from '@libs/Navigation/Navigation'; +import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; +import SCREENS from '@src/SCREENS'; + +const isReportInSearchContext = (): boolean => { + const rootState = navigationRef.getRootState() as State | undefined; + + if (!rootState) { + return false; + } + + const lastRootRoute = rootState.routes.at(-1); + const lastNestedRoute = lastRootRoute?.state?.routes?.at(-1); + + return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; +}; + +export default isReportInSearchContext; diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index d3a73b77314ae..2a750026c3618 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -46,6 +46,7 @@ import { import {getQuickActionIcon, getQuickActionTitle, isQuickActionAllowed} from '@libs/QuickActionUtils'; import {generateReportID, getDisplayNameForParticipant, getIcons, getReportName, getWorkspaceChats, isPolicyExpenseChat} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; +import isReportInSearchContext from '@navigation/helpers/isReportInSearchContext'; import variables from '@styles/variables'; import closeReactNativeApp from '@userActions/HybridApp'; import saveLastSearchParams from '@userActions/ReportNavigation'; @@ -103,7 +104,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true}); - const [lastSearchResults] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true}); const policyChatForActivePolicy = useMemo(() => { if (isEmptyObject(activePolicy) || !activePolicy?.isPolicyExpenseChatEnabled) { return {} as OnyxTypes.Report; @@ -144,6 +144,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT selector: (policies) => Object.values(policies ?? {}).some((policy) => isPaidGroupPolicy(policy) && isPolicyMember(policy, currentUserPersonalDetails.login)), }); + const isReportInSearch = isReportInSearchContext(); + const groupPoliciesWithChatEnabled = getGroupPaidPoliciesWithExpenseChatEnabled(); /** @@ -441,7 +443,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT : []), ...(shouldShowCreateReportOption ? [ - // tu robimy report duuuuupa { icon: Expensicons.Document, text: translate('report.newReport.createReport'), @@ -462,12 +463,13 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT // If the user has only one paid group workspace with chat enabled, we create a report with it workspaceIDForReportCreation = groupPoliciesWithChatEnabled.at(0)?.id; } - - saveLastSearchParams({}); + if (isReportInSearch) { + saveLastSearchParams({}); + } if (!workspaceIDForReportCreation || (shouldRestrictUserBillableActions(workspaceIDForReportCreation) && groupPoliciesWithChatEnabled.length > 1)) { // If we couldn't guess the workspace to create the report, or a guessed workspace is past it's grace period and we have other workspaces to choose from - Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION); + Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION, {forceReplace: isReportInSearch}); return; } @@ -478,10 +480,11 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT isSearchTopmostFullScreenRoute() ? ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID}) : ROUTES.REPORT_WITH_ID.getRoute(createdReportID, undefined, undefined, undefined, undefined, Navigation.getActiveRoute()), + {forceReplace: isReportInSearch}, ); }); } else { - Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(workspaceIDForReportCreation)); + Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(workspaceIDForReportCreation), {forceReplace: isReportInSearch}); } }); }, From 242cc994999081bd0a5c21dfc2b4bac07141e87c Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Mon, 25 Aug 2025 16:07:02 +0200 Subject: [PATCH 03/21] working fix --- src/libs/Navigation/helpers/isReportInSearchContext.ts | 1 - src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/Navigation/helpers/isReportInSearchContext.ts b/src/libs/Navigation/helpers/isReportInSearchContext.ts index bd758c4dcc825..8db9d54823c1d 100644 --- a/src/libs/Navigation/helpers/isReportInSearchContext.ts +++ b/src/libs/Navigation/helpers/isReportInSearchContext.ts @@ -4,7 +4,6 @@ import SCREENS from '@src/SCREENS'; const isReportInSearchContext = (): boolean => { const rootState = navigationRef.getRootState() as State | undefined; - if (!rootState) { return false; } diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 2a750026c3618..44392b8e97b06 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -469,7 +469,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT if (!workspaceIDForReportCreation || (shouldRestrictUserBillableActions(workspaceIDForReportCreation) && groupPoliciesWithChatEnabled.length > 1)) { // If we couldn't guess the workspace to create the report, or a guessed workspace is past it's grace period and we have other workspaces to choose from - Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION, {forceReplace: isReportInSearch}); + Navigation.navigate(ROUTES.NEW_REPORT_WORKSPACE_SELECTION); return; } From 6b9a22d446a1541320858d981d7d73f6e3c8ed0d Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Tue, 26 Aug 2025 11:01:08 +0200 Subject: [PATCH 04/21] revert revert PR --- src/CONST/index.ts | 1 + src/ONYXKEYS.ts | 3 + src/components/MoneyReportHeader.tsx | 82 +++++----- .../MoneyRequestReportNavigation.tsx | 145 ++++++++++++++++++ src/components/PrevNextButtons.tsx | 8 +- src/components/Search/index.tsx | 37 ++--- src/components/Search/types.ts | 1 + src/libs/API/types.ts | 1 + src/libs/ReportUtils.ts | 36 +++++ src/libs/actions/ReportNavigation.ts | 9 ++ src/libs/actions/Search.ts | 47 +++++- src/styles/utils/flex.ts | 4 + src/styles/utils/sizing.ts | 4 + src/types/onyx/ReportNavigation.ts | 38 +++++ src/types/onyx/index.ts | 2 + 15 files changed, 345 insertions(+), 73 deletions(-) create mode 100644 src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx create mode 100644 src/libs/actions/ReportNavigation.ts create mode 100644 src/types/onyx/ReportNavigation.ts diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 67b9855413d6e..b83636afff38e 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1073,6 +1073,7 @@ const CONST = { MAX_COUNT_BEFORE_FOCUS_UPDATE: 30, MIN_INITIAL_REPORT_ACTION_COUNT: 15, UNREPORTED_REPORT_ID: '0', + DEFAULT_REPORT_ID: '1', SPLIT_REPORT_ID: '-2', SECONDARY_ACTIONS: { SUBMIT: 'submit', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8443812a2a065..392256a885f6c 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -561,6 +561,8 @@ const ONYXKEYS = { /** List of transaction thread IDs used when navigating to prev/next transaction when viewing it in RHP */ TRANSACTION_THREAD_NAVIGATION_REPORT_IDS: 'transactionThreadNavigationReportIDs', + REPORT_NAVIGATION_LAST_SEARCH_QUERY: 'ReportNavigationLastSearchQuery', + /** Timestamp of the last login on iOS */ NVP_LAST_ECASH_IOS_LOGIN: 'nvp_lastECashIOSLogin', NVP_LAST_IPHONE_LOGIN: 'nvp_lastiPhoneLogin', @@ -1230,6 +1232,7 @@ type OnyxValuesMapping = { [ONYXKEYS.NVP_LAST_ECASH_IOS_LOGIN]: string; [ONYXKEYS.NVP_LAST_ECASH_ANDROID_LOGIN]: string; [ONYXKEYS.NVP_LAST_IPHONE_LOGIN]: string; + [ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY]: OnyxTypes.LastSearchParams; [ONYXKEYS.NVP_LAST_ANDROID_LOGIN]: string; [ONYXKEYS.TRANSACTION_THREAD_NAVIGATION_REPORT_IDS]: string[]; [ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES]: OnyxTypes.ExportTemplate[]; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index a3f34af8e5eef..b2688da7ae7cb 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -114,6 +114,7 @@ import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar'; import MoneyReportHeaderStatusBarSkeleton from './MoneyReportHeaderStatusBarSkeleton'; import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar'; import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar'; +import MoneyRequestReportNavigation from './MoneyRequestReportView/MoneyRequestReportNavigation'; import type {PopoverMenuItem} from './PopoverMenu'; import type {ActionHandledType} from './ProcessMoneyReportHoldMenu'; import ProcessMoneyReportHoldMenu from './ProcessMoneyReportHoldMenu'; @@ -365,6 +366,7 @@ function MoneyReportHeader({ const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP; const shouldDisplaySearchRouter = !isReportInRHP || isSmallScreenWidth; + const isReportInSearch = route.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; const confirmPayment = useCallback( (type?: PaymentMethodType | undefined, payAsBusiness?: boolean, methodID?: number, paymentMethod?: PaymentMethod) => { @@ -1122,40 +1124,13 @@ function MoneyReportHeader({ ); - const moreContentUnfiltered = [ - shouldShowSelectedTransactionsButton && shouldDisplayNarrowVersion && ( - - null} - options={selectedTransactionsOptions} - customText={translate('workspace.common.selected', {count: selectedTransactionIDs.length})} - isSplitButton={false} - shouldAlwaysShowDropdownMenu - wrapperStyle={styles.w100} - /> - - ), - shouldShowNextStep && !!optimisticNextStep?.message?.length && ( - - ), - shouldShowNextStep && !optimisticNextStep && !!isLoadingInitialReportActions && !isOffline && , - !!statusBarProps && ( - - ), - ]; - const moreContent = moreContentUnfiltered.filter(Boolean); - const isMoreContentShown = moreContent.length > 0; - const shouldAddGapToContents = moreContent.length > 1; + const headerNavigation = isReportInSearch ? ( + + ) : undefined; return ( @@ -1187,14 +1162,39 @@ function MoneyReportHeader({ )} - {shouldDisplayNarrowVersion && !shouldShowSelectedTransactionsButton && ( - - {!!primaryAction && {primaryActionsImplementation[primaryAction]}} - {!!applicableSecondaryActions.length && KYCMoreDropdown} - - )} - {isMoreContentShown && {moreContent}} + {shouldDisplayNarrowVersion && + (shouldShowSelectedTransactionsButton ? ( + + null} + options={selectedTransactionsOptions} + customText={translate('workspace.common.selected', {count: selectedTransactionIDs.length})} + isSplitButton={false} + shouldAlwaysShowDropdownMenu + wrapperStyle={styles.w100} + /> + + ) : ( + + {!!primaryAction && {primaryActionsImplementation[primaryAction]}} + {!!applicableSecondaryActions.length && KYCMoreDropdown} + + ))} + + + + {shouldShowNextStep && !!optimisticNextStep?.message?.length && } + {shouldShowNextStep && !optimisticNextStep && !!isLoadingInitialReportActions && !isOffline && } + {!!statusBarProps && ( + + )} + + {headerNavigation} + {isHoldMenuVisible && requestType !== undefined && ( diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx new file mode 100644 index 0000000000000..4dc2e2878550a --- /dev/null +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -0,0 +1,145 @@ +import React, {useEffect} from 'react'; +import {View} from 'react-native'; +import PrevNextButtons from '@components/PrevNextButtons'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import useThemeStyles from '@hooks/useThemeStyles'; +import {selectArchivedReportsIdSet, selectFilteredReportActions} from '@libs/ReportUtils'; +import {getSections, getSortedSections} from '@libs/SearchUIUtils'; +import Navigation from '@navigation/Navigation'; +import saveLastSearchParams from '@userActions/ReportNavigation'; +import {search} from '@userActions/Search'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; + +type MoneyRequestReportNavigationProps = { + reportID?: string; + shouldDisplayNarrowVersion: boolean; + backTo?: string; +}; + +function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion, backTo}: MoneyRequestReportNavigationProps) { + const [lastSearchQuery] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true}); + const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${lastSearchQuery?.queryJSON?.hash}`, {canBeMissing: true}); + const [accountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false, selector: (s) => s?.accountID}); + + const {localeCompare, formatPhoneNumber} = useLocalize(); + + const [exportReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, { + canEvict: false, + canBeMissing: true, + selector: selectFilteredReportActions, + }); + + const [archivedReportsIdSet = new Set()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { + canBeMissing: true, + selector: selectArchivedReportsIdSet, + }); + + const {type, status, sortBy, sortOrder, groupBy} = lastSearchQuery?.queryJSON ?? {}; + let results: Array = []; + if (!!type && !!groupBy && !!currentSearchResults?.data && !!currentSearchResults?.search) { + const temp = getSections( + type, + currentSearchResults.data, + currentSearchResults.search, + accountID, + formatPhoneNumber, + groupBy, + exportReportActions, + lastSearchQuery?.searchKey, + archivedReportsIdSet, + ); + results = getSortedSections(type, status ?? '', temp, localeCompare, sortBy, sortOrder, groupBy).map((value) => value.reportID); + } + const allReports = results; + + const currentIndex = allReports.indexOf(reportID ?? CONST.REPORT.DEFAULT_REPORT_ID); + const allReportsCount = lastSearchQuery?.previousLengthOfResults ?? 0; + + const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; + const hidePrevButton = currentIndex === 0; + const styles = useThemeStyles(); + const shouldDisplayNavigationArrows = allReports && allReports.length > 1; + + useEffect(() => { + if (!lastSearchQuery?.queryJSON) { + return; + } + + if (lastSearchQuery.allowPostSearchRecount) { + saveLastSearchParams({ + ...lastSearchQuery, + allowPostSearchRecount: false, + previousLengthOfResults: allReports.length, + }); + return; + } + + if (currentIndex < allReportsCount - 1) { + return; + } + + saveLastSearchParams({ + ...lastSearchQuery, + previousLengthOfResults: allReports.length, + }); + }, [currentIndex, allReportsCount, allReports.length, lastSearchQuery?.queryJSON, lastSearchQuery]); + + const goToReportId = (reportId?: string) => { + if (!reportId) { + return; + } + Navigation.setParams({ + reportID: reportId, + backTo: backTo ?? '', + }); + }; + + const goToNextReport = () => { + if (currentIndex === -1 || allReports.length === 0) { + return ''; + } + if (currentIndex > allReports.length * 0.75 && lastSearchQuery?.hasMoreResults) { + const newOffset = (lastSearchQuery.offset ?? 0) + CONST.SEARCH.RESULTS_PAGE_SIZE; + search({ + queryJSON: lastSearchQuery.queryJSON, + offset: newOffset, + prevReports: allReports, + shouldCalculateTotals: false, + searchKey: lastSearchQuery.searchKey, + }); + } + + const nextIndex = (currentIndex + 1) % allReports.length; + goToReportId(allReports.at(nextIndex)); + }; + + const goToPrevReport = () => { + if (currentIndex === -1 || allReports.length === 0) { + return ''; + } + + const prevIndex = (currentIndex - 1) % allReports.length; + goToReportId(allReports.at(prevIndex)); + }; + + return ( + shouldDisplayNavigationArrows && ( + + {!shouldDisplayNarrowVersion && {`${currentIndex + 1} of ${allReportsCount}`}} + + + ) + ); +} + +MoneyRequestReportNavigation.displayName = 'MoneyRequestReportNavigation'; + +export default MoneyRequestReportNavigation; diff --git a/src/components/PrevNextButtons.tsx b/src/components/PrevNextButtons.tsx index 23f950d30f524..401a4d39fdb20 100644 --- a/src/components/PrevNextButtons.tsx +++ b/src/components/PrevNextButtons.tsx @@ -16,10 +16,10 @@ type PrevNextButtonsProps = { isNextButtonDisabled?: boolean; /** Moves a user to the next item */ - onNext: (event?: GestureResponderEvent | KeyboardEvent) => void; + onNext?: (event?: GestureResponderEvent | KeyboardEvent) => void; /** Moves a user to the previous item */ - onPrevious: (event?: GestureResponderEvent | KeyboardEvent) => void; + onPrevious?: (event?: GestureResponderEvent | KeyboardEvent) => void; }; function PrevNextButtons({isPrevButtonDisabled, isNextButtonDisabled, onNext, onPrevious}: PrevNextButtonsProps) { @@ -33,7 +33,7 @@ function PrevNextButtons({isPrevButtonDisabled, isNextButtonDisabled, onNext, on accessibilityRole={CONST.ROLE.BUTTON} accessibilityLabel={CONST.ROLE.BUTTON} disabled={isPrevButtonDisabled} - style={[styles.h10, styles.mr1, styles.alignItemsCenter, styles.justifyContentCenter]} + style={[styles.h7, styles.mr1, styles.alignItemsCenter, styles.justifyContentCenter]} onPress={onPrevious} > @@ -50,7 +50,7 @@ function PrevNextButtons({isPrevButtonDisabled, isNextButtonDisabled, onNext, on accessibilityRole={CONST.ROLE.BUTTON} accessibilityLabel={CONST.ROLE.BUTTON} disabled={isNextButtonDisabled} - style={[styles.h10, styles.alignItemsCenter, styles.justifyContentCenter]} + style={[styles.h7, styles.alignItemsCenter, styles.justifyContentCenter]} onPress={onNext} > diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index a3bc0c6fa8759..9141788688bde 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -24,9 +24,10 @@ import Log from '@libs/Log'; import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; import Performance from '@libs/Performance'; -import {getIOUActionForTransactionID, isExportIntegrationAction, isIntegrationMessageAction} from '@libs/ReportActionsUtils'; -import {canEditFieldOfMoneyRequest, generateReportID, isArchivedReport} from '@libs/ReportUtils'; +import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils'; +import {canEditFieldOfMoneyRequest, generateReportID, selectArchivedReportsIdSet, selectFilteredReportActions} from '@libs/ReportUtils'; import {buildCannedSearchQuery, buildSearchQueryString} from '@libs/SearchQueryUtils'; +import type {SearchKey} from '@libs/SearchUIUtils'; import { getListItem, getSections, @@ -45,7 +46,6 @@ import { shouldShowEmptyState, shouldShowYear as shouldShowYearUtil, } from '@libs/SearchUIUtils'; -import type {ArchivedReportsIDSet, SearchKey} from '@libs/SearchUIUtils'; import {isOnHold, isTransactionPendingDelete} from '@libs/TransactionUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; import type {SearchFullscreenNavigatorParamList} from '@navigation/types'; @@ -198,35 +198,14 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const [archivedReportsIdSet = new Set()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { canBeMissing: true, - selector: (all): ArchivedReportsIDSet => { - const ids = new Set(); - if (!all) { - return ids; - } - - const prefixLength = ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS.length; - for (const [key, value] of Object.entries(all)) { - if (isArchivedReport(value)) { - const reportID = key.slice(prefixLength); - ids.add(reportID); - } - } - return ids; - }, + selector: selectArchivedReportsIdSet, }); // Create a selector for only the reportActions needed to determine if a report has been exported or not, grouped by report const [exportReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, { canEvict: false, canBeMissing: true, - selector: (allReportActions) => { - return Object.fromEntries( - Object.entries(allReportActions ?? {}).map(([reportID, reportActionsGroup]) => { - const filteredReportActions = Object.values(reportActionsGroup ?? {}).filter((action) => isExportIntegrationAction(action) || isIntegrationMessageAction(action)); - return [reportID, filteredReportActions]; - }), - ); - }, + selector: selectFilteredReportActions, }); const {defaultCardFeed} = useCardFeedsForDisplay(); const [accountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false, selector: (s) => s?.accountID}); @@ -321,7 +300,11 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS return; } - handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals}); + const results = searchResults + ? getSections(type, searchResults.data, searchResults.search, accountID, formatPhoneNumber, groupBy).map((element) => element?.reportID ?? CONST.REPORT.DEFAULT_REPORT_ID) + : []; + handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals, prevReports: results}); + // We don't need to run the effect on change of isFocused. // eslint-disable-next-line react-compiler/react-compiler // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 370897cc9bc49..273a62d4dd90f 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -179,6 +179,7 @@ type SearchParams = { queryJSON: SearchQueryJSON; searchKey: SearchKey | undefined; offset: number; + prevReports?: string[]; shouldCalculateTotals: boolean; }; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index accd91e64516d..c786f71c660c3 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -1188,6 +1188,7 @@ const SIDE_EFFECT_REQUEST_COMMANDS = { COMPLETE_HYBRID_APP_ONBOARDING: 'CompleteHybridAppOnboarding', CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP: 'ConnectPolicyToQuickbooksDesktop', MERGE_INTO_ACCOUNT_AND_LOGIN: 'MergeIntoAccountAndLogIn', + SEARCH: 'Search', // PayMoneyRequestOnSearch only works online (pattern C) and we need to play the success sound only when the request is successful PAY_MONEY_REQUEST_ON_SEARCH: 'PayMoneyRequestOnSearch', diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 1695b92847f94..72743c98dda1d 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -220,6 +220,7 @@ import { wasActionTakenByCurrentUser, } from './ReportActionsUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; +import type {ArchivedReportsIDSet} from './SearchUIUtils'; import {shouldRestrictUserBillableActions} from './SubscriptionUtils'; import { getAttendees, @@ -11419,6 +11420,39 @@ function getMoneyReportPreviewName(action: ReportAction, iouReport: OnyxEntry> | null | undefined): ArchivedReportsIDSet { + const archivedIDs = new Set(); + if (!all) { + return archivedIDs; + } + + const prefixLen = ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS.length; + + for (const [key, value] of Object.entries(all)) { + if (isArchivedReport(value)) { + archivedIDs.add(key.slice(prefixLen)); + } + } + + return archivedIDs; +} + +function selectFilteredReportActions( + reportActions: Record> | undefined> | null | undefined, +): Record | undefined { + if (!reportActions) { + return {}; + } + + return Object.fromEntries( + Object.entries(reportActions).map(([reportId, actionsGroup]) => { + const actions = Object.values(actionsGroup ?? {}); + const filteredActions = actions.filter((action): action is ReportAction => isExportIntegrationAction(action) || isIntegrationMessageAction(action)); + return [reportId, filteredActions]; + }), + ); +} + /** * Returns the translated, human-readable status of the report based on its state and status values. * The status is determined by the stateNum and statusNum of the report. @@ -11745,6 +11779,8 @@ export { parseReportRouteParams, parseReportActionHtmlToText, requiresAttentionFromCurrentUser, + selectArchivedReportsIdSet, + selectFilteredReportActions, shouldAutoFocusOnKeyPress, shouldCreateNewMoneyRequestReport, shouldDisableDetailPage, diff --git a/src/libs/actions/ReportNavigation.ts b/src/libs/actions/ReportNavigation.ts new file mode 100644 index 0000000000000..b95ef1906455c --- /dev/null +++ b/src/libs/actions/ReportNavigation.ts @@ -0,0 +1,9 @@ +import Onyx from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type LastSearchParams from '@src/types/onyx/ReportNavigation'; + +function saveLastSearchParams(value: LastSearchParams) { + Onyx.set(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, value); +} + +export default saveLastSearchParams; diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 19a704c825375..2a7cc4aab583f 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -28,6 +28,15 @@ import type {PaymentInformation} from '@src/types/onyx/LastPaymentMethod'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type Nullable from '@src/types/utils/Nullable'; +import saveLastSearchParams from './ReportNavigation'; + +type OnyxSearchResponse = { + data: []; + search: { + offset: number; + hasMoreResults: boolean; + }; +}; function handleActionButtonPress( hash: number, @@ -307,11 +316,13 @@ function search({ searchKey, offset, shouldCalculateTotals = false, + prevReports, }: { queryJSON: SearchQueryJSON; searchKey: SearchKey | undefined; offset?: number; shouldCalculateTotals?: boolean; + prevReports?: Array; }) { const {optimisticData, finallyData, failureData} = getOnyxLoadingData(queryJSON.hash, queryJSON); const {flatFilters, ...queryJSONWithoutFlatFilters} = queryJSON; @@ -319,11 +330,45 @@ function search({ ...queryJSONWithoutFlatFilters, searchKey, offset, + filters: queryJSONWithoutFlatFilters.filters ?? null, shouldCalculateTotals, }; const jsonQuery = JSON.stringify(query); + saveLastSearchParams({ + queryJSON, + offset, + allowPostSearchRecount: false, + }); - API.read(READ_COMMANDS.SEARCH, {hash: queryJSON.hash, jsonQuery}, {optimisticData, finallyData, failureData}); + // eslint-disable-next-line rulesdir/no-api-side-effects-method + API.makeRequestWithSideEffects(READ_COMMANDS.SEARCH, {hash: queryJSON.hash, jsonQuery}, {optimisticData, finallyData, failureData}).then((result) => { + const response = result?.onyxData?.[0]?.value as OnyxSearchResponse; + const reports = Object.keys(response?.data ?? {}) + .filter((key) => key.startsWith(ONYXKEYS.COLLECTION.REPORT)) + .map((key) => key.replace(ONYXKEYS.COLLECTION.REPORT, '')); + if (response?.search?.offset) { + // Indicates that search results are extended from the Report view (with navigation between reports), + // using previous results to enable correct counter behavior. + if (prevReports) { + saveLastSearchParams({ + queryJSON, + offset, + hasMoreResults: !!response?.search?.hasMoreResults, + previousLengthOfResults: prevReports.length, + allowPostSearchRecount: false, + }); + } + } else { + // Applies to all searches from the Search View + saveLastSearchParams({ + queryJSON, + offset, + hasMoreResults: !!response?.search?.hasMoreResults, + previousLengthOfResults: reports.length, + allowPostSearchRecount: true, + }); + } + }); } /** diff --git a/src/styles/utils/flex.ts b/src/styles/utils/flex.ts index aafda26f3acdd..82e41e7d37e14 100644 --- a/src/styles/utils/flex.ts +++ b/src/styles/utils/flex.ts @@ -113,6 +113,10 @@ export default { flexWrap: 'wrap', }, + flexNoWrap: { + flexWrap: 'nowrap', + }, + flexGrow0: { flexGrow: 0, }, diff --git a/src/styles/utils/sizing.ts b/src/styles/utils/sizing.ts index dab8e474abb60..d9aa4df8ec5eb 100644 --- a/src/styles/utils/sizing.ts +++ b/src/styles/utils/sizing.ts @@ -13,6 +13,10 @@ export default { height: '100%', }, + h7: { + height: 28, + }, + h10: { height: 40, }, diff --git a/src/types/onyx/ReportNavigation.ts b/src/types/onyx/ReportNavigation.ts new file mode 100644 index 0000000000000..07c6ef04a7eb5 --- /dev/null +++ b/src/types/onyx/ReportNavigation.ts @@ -0,0 +1,38 @@ +import type {SearchQueryJSON} from '@components/Search/types'; +import type {SearchKey} from '@libs/SearchUIUtils'; + +/** + * Represents the parameters from the previous search invocation. + * This is used to persist search arguments between navigations within reports, + * and allows loading more search results as the user continues navigating. + */ +type LastSearchParams = { + /** + * The number of results returned in the previous search. + */ + previousLengthOfResults?: number; + /** + * Enables post-search recount based on extra criteria unknown during the initial search. + */ + allowPostSearchRecount?: boolean; + /** + * Indicates whether there are more results available beyond the last search. + */ + hasMoreResults?: boolean; + + /** + * The full query JSON object that was used in the last search. + */ + queryJSON: SearchQueryJSON; + /** + * The current offset used in pagination for fetching the previous set of results. + */ + offset?: number; + + /** + *Optional witch field contain search key for last search performed + */ + searchKey?: SearchKey; +}; + +export default LastSearchParams; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index d169a77304623..0dcc6290f5b7d 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -87,6 +87,7 @@ import type ReportActionsDraft from './ReportActionsDraft'; import type ReportActionsDrafts from './ReportActionsDrafts'; import type ReportMetadata from './ReportMetadata'; import type ReportNameValuePairs from './ReportNameValuePairs'; +import type LastSearchParams from './ReportNavigation'; import type ReportNextStep from './ReportNextStep'; import type ReportUserIsTyping from './ReportUserIsTyping'; import type {ReportFieldsViolations, ReportViolationName} from './ReportViolation'; @@ -265,6 +266,7 @@ export type { SidePanel, LastPaymentMethodType, ReportAttributesDerivedValue, + LastSearchParams, ReportTransactionsAndViolationsDerivedValue, OutstandingReportsByPolicyIDDerivedValue, ScheduleCallDraft, From 58bb1b87150143531b048fab63bd2d89898869be Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Wed, 27 Aug 2025 10:20:10 +0200 Subject: [PATCH 05/21] work in progress --- .../MoneyRequestReportView/MoneyRequestReportView.tsx | 7 +++++-- src/pages/Search/SearchMoneyRequestReportPage.tsx | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx index ec5710093bb3a..f5dedc0272595 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx @@ -49,6 +49,8 @@ type MoneyRequestReportViewProps = { /** The `backTo` route that should be used when clicking back button */ backToRoute: Route | undefined; + + shouldWaitForReportSync: boolean; }; function goBackFromSearchMoneyRequest() { @@ -86,7 +88,8 @@ function getParentReportAction(parentReportActions: OnyxEntry; } diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx index c01b9b7614842..48d7a694df9cb 100644 --- a/src/pages/Search/SearchMoneyRequestReportPage.tsx +++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx @@ -43,6 +43,8 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { const reportIDFromRoute = getNonEmptyStringOnyxID(route.params?.reportID); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`, {allowStaleData: true, canBeMissing: true}); + const shuldWaitForReportSync = report?.reportID !== reportIDFromRoute; + const [reportMetadata = defaultReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {canBeMissing: true, allowStaleData: true}); const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {allowStaleData: true, canBeMissing: false}); const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; @@ -105,6 +107,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { policy={policy} shouldDisplayReportFooter={isCurrentReportLoadedFromOnyx} backToRoute={route.params.backTo} + shouldWaitForReportSync={shuldWaitForReportSync} /> @@ -140,6 +143,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { policy={policy} shouldDisplayReportFooter={isCurrentReportLoadedFromOnyx} backToRoute={route.params.backTo} + shouldWaitForReportSync={shuldWaitForReportSync} /> From 832b0f3bf0473569b4a19fbf94bdcfa3f0db9aed Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Wed, 27 Aug 2025 13:55:14 +0200 Subject: [PATCH 06/21] fix pagination after report creation --- .../MoneyRequestReportView.tsx | 2 -- ...chContext.ts => isInSearchReportContext.ts} | 6 +++--- .../helpers/isRHPOnSearchReportContext.ts | 17 +++++++++++++++++ src/pages/NewReportWorkspaceSelectionPage.tsx | 18 ++++++++---------- .../sidebar/FloatingActionButtonAndPopover.tsx | 7 ++++--- 5 files changed, 32 insertions(+), 18 deletions(-) rename src/libs/Navigation/helpers/{isReportInSearchContext.ts => isInSearchReportContext.ts} (83%) create mode 100644 src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx index f5dedc0272595..717fb8f12ab30 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx @@ -89,7 +89,6 @@ function getParentReportAction(parentReportActions: OnyxEntry { +const isInSearchReportContext = (): boolean => { const rootState = navigationRef.getRootState() as State | undefined; if (!rootState) { return false; @@ -10,8 +10,8 @@ const isReportInSearchContext = (): boolean => { const lastRootRoute = rootState.routes.at(-1); const lastNestedRoute = lastRootRoute?.state?.routes?.at(-1); - + debugger; return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; }; -export default isReportInSearchContext; +export default isInSearchReportContext; diff --git a/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts b/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts new file mode 100644 index 0000000000000..2685a399c326e --- /dev/null +++ b/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts @@ -0,0 +1,17 @@ +import {navigationRef} from '@libs/Navigation/Navigation'; +import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; +import SCREENS from '@src/SCREENS'; + +const isRHPOnSearchReportContext = (): boolean => { + const rootState = navigationRef.getRootState() as State | undefined; + if (!rootState) { + return false; + } + + const lastRootRoute = rootState.routes.at(-2); + const lastNestedRoute = lastRootRoute?.state?.routes?.at(-1); + debugger; + return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; +}; + +export default isRHPOnSearchReportContext; diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index 2a116f0625795..a04d9a6812aff 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -20,6 +20,7 @@ import {getHeaderMessageForNonUserList} from '@libs/OptionsListUtils'; import {isPolicyAdmin, shouldShowPolicy} from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; +import isRHPOnSearchReportContext from '@navigation/helpers/isRHPOnSearchReportContext'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -37,29 +38,26 @@ function NewReportWorkspaceSelectionPage() { const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const {translate, localeCompare} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); + const isRHPOnReportInSearch = isRHPOnSearchReportContext(); const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: true}); const shouldShowLoadingIndicator = isLoadingApp && !isOffline; - const navigateToNewReport = useCallback( (optimisticReportID: string) => { - if (shouldUseNarrowLayout) { + // On wide screens we use dismissModal instead of forceReplace to avoid performance issues + if (isRHPOnReportInSearch) { Navigation.setNavigationActionToMicrotaskQueue(() => { - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID}), {forceReplace: true}); + Navigation.dismissModal(); }); - return; } - // On wide screens we use dismissModal instead of forceReplace to avoid performance issues - Navigation.setNavigationActionToMicrotaskQueue(() => { - Navigation.dismissModal(); - }); + Navigation.setNavigationActionToMicrotaskQueue(() => { - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID})); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID}), {forceReplace: isRHPOnReportInSearch || shouldUseNarrowLayout}); }); }, - [shouldUseNarrowLayout], + [isRHPOnReportInSearch, shouldUseNarrowLayout], ); const selectPolicy = useCallback( diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 0888e17a7d2d0..b4eb0c4de4f3d 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -46,7 +46,7 @@ import { import {getQuickActionIcon, getQuickActionTitle, isQuickActionAllowed} from '@libs/QuickActionUtils'; import {generateReportID, getDisplayNameForParticipant, getIcons, getReportName, getWorkspaceChats, isPolicyExpenseChat} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; -import isReportInSearchContext from '@navigation/helpers/isReportInSearchContext'; +import isInSearchReportContext from '@navigation/helpers/isInSearchReportContext'; import variables from '@styles/variables'; import {closeReactNativeApp} from '@userActions/HybridApp'; import saveLastSearchParams from '@userActions/ReportNavigation'; @@ -147,7 +147,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT selector: (policies) => Object.values(policies ?? {}).some((policy) => isPaidGroupPolicy(policy) && isPolicyMember(policy, currentUserPersonalDetails.login)), }); - const isReportInSearch = isReportInSearchContext(); + const isReportInSearch = isInSearchReportContext(); const groupPoliciesWithChatEnabled = getGroupPaidPoliciesWithExpenseChatEnabled(); @@ -472,6 +472,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT // If the user has only one paid group workspace with chat enabled, we create a report with it workspaceIDForReportCreation = groupPoliciesWithChatEnabled.at(0)?.id; } + if (isReportInSearch) { saveLastSearchParams({}); } @@ -493,7 +494,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT ); }); } else { - Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(workspaceIDForReportCreation), {forceReplace: isReportInSearch}); + Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(workspaceIDForReportCreation)); } }); }, From 29d7b808bae57874f87fa26f49aae7653ba2cf7c Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Wed, 27 Aug 2025 16:36:35 +0200 Subject: [PATCH 07/21] fix highlight and distance --- .../MoneyRequestReportView.tsx | 2 +- src/libs/API/index.ts | 2 +- src/libs/actions/Search.ts | 47 ++++++++++--------- .../Search/SearchMoneyRequestReportPage.tsx | 6 +-- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx index 717fb8f12ab30..fe86659e8b302 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx @@ -108,7 +108,7 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe const reportTransactionIDs = visibleTransactions?.map((transaction) => transaction.transactionID); const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, reportActions ?? [], isOffline, reportTransactionIDs); - const newTransactions = useNewTransactions(reportMetadata?.hasOnceLoadedReportActions, transactions); + const newTransactions = useNewTransactions(reportMetadata?.hasOnceLoadedReportActions, shouldWaitForReportSync ? [] : transactions); const [parentReportAction] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(report?.parentReportID)}`, { canEvict: false, canBeMissing: true, diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index 50225e8c232ec..8caf7387add04 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -285,4 +285,4 @@ function paginate { - const response = result?.onyxData?.[0]?.value as OnyxSearchResponse; - const reports = Object.keys(response?.data ?? {}) - .filter((key) => key.startsWith(ONYXKEYS.COLLECTION.REPORT)) - .map((key) => key.replace(ONYXKEYS.COLLECTION.REPORT, '')); - if (response?.search?.offset) { - // Indicates that search results are extended from the Report view (with navigation between reports), - // using previous results to enable correct counter behavior. - if (prevReports) { + waitForWrites(READ_COMMANDS.SEARCH).then(() => { + // eslint-disable-next-line rulesdir/no-api-side-effects-method + API.makeRequestWithSideEffects(READ_COMMANDS.SEARCH, {hash: queryJSON.hash, jsonQuery}, {optimisticData, finallyData, failureData}).then((result) => { + const response = result?.onyxData?.[0]?.value as OnyxSearchResponse; + const reports = Object.keys(response?.data ?? {}) + .filter((key) => key.startsWith(ONYXKEYS.COLLECTION.REPORT)) + .map((key) => key.replace(ONYXKEYS.COLLECTION.REPORT, '')); + if (response?.search?.offset) { + // Indicates that search results are extended from the Report view (with navigation between reports), + // using previous results to enable correct counter behavior. + if (prevReports) { + saveLastSearchParams({ + queryJSON, + offset, + hasMoreResults: !!response?.search?.hasMoreResults, + previousLengthOfResults: prevReports.length, + allowPostSearchRecount: false, + }); + } + } else { + // Applies to all searches from the Search View saveLastSearchParams({ queryJSON, offset, hasMoreResults: !!response?.search?.hasMoreResults, - previousLengthOfResults: prevReports.length, - allowPostSearchRecount: false, + previousLengthOfResults: reports.length, + allowPostSearchRecount: true, }); } - } else { - // Applies to all searches from the Search View - saveLastSearchParams({ - queryJSON, - offset, - hasMoreResults: !!response?.search?.hasMoreResults, - previousLengthOfResults: reports.length, - allowPostSearchRecount: true, - }); - } + }); }); } diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx index 48d7a694df9cb..252c274fec8e6 100644 --- a/src/pages/Search/SearchMoneyRequestReportPage.tsx +++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx @@ -43,7 +43,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { const reportIDFromRoute = getNonEmptyStringOnyxID(route.params?.reportID); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`, {allowStaleData: true, canBeMissing: true}); - const shuldWaitForReportSync = report?.reportID !== reportIDFromRoute; + const shouldWaitForReportSync = report?.reportID !== reportIDFromRoute; const [reportMetadata = defaultReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {canBeMissing: true, allowStaleData: true}); const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {allowStaleData: true, canBeMissing: false}); @@ -107,7 +107,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { policy={policy} shouldDisplayReportFooter={isCurrentReportLoadedFromOnyx} backToRoute={route.params.backTo} - shouldWaitForReportSync={shuldWaitForReportSync} + shouldWaitForReportSync={shouldWaitForReportSync} /> @@ -143,7 +143,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { policy={policy} shouldDisplayReportFooter={isCurrentReportLoadedFromOnyx} backToRoute={route.params.backTo} - shouldWaitForReportSync={shuldWaitForReportSync} + shouldWaitForReportSync={shouldWaitForReportSync} /> From bd609168e87747fb6a0360af83aeba4a9bcac4e7 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Wed, 27 Aug 2025 17:09:46 +0200 Subject: [PATCH 08/21] fix highlight --- src/pages/Search/SearchMoneyRequestReportPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx index 252c274fec8e6..868474849f679 100644 --- a/src/pages/Search/SearchMoneyRequestReportPage.tsx +++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx @@ -108,6 +108,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { shouldDisplayReportFooter={isCurrentReportLoadedFromOnyx} backToRoute={route.params.backTo} shouldWaitForReportSync={shouldWaitForReportSync} + key={report?.reportID} /> @@ -144,6 +145,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { shouldDisplayReportFooter={isCurrentReportLoadedFromOnyx} backToRoute={route.params.backTo} shouldWaitForReportSync={shouldWaitForReportSync} + key={report?.reportID} /> From ada820a7e62b3f45bd476d9e7b220a3d5f3f156b Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Thu, 28 Aug 2025 14:27:15 +0200 Subject: [PATCH 09/21] remove debuggeer --- src/libs/Navigation/helpers/isInSearchReportContext.ts | 1 - src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libs/Navigation/helpers/isInSearchReportContext.ts b/src/libs/Navigation/helpers/isInSearchReportContext.ts index c7f1e613060d5..c4cee424df899 100644 --- a/src/libs/Navigation/helpers/isInSearchReportContext.ts +++ b/src/libs/Navigation/helpers/isInSearchReportContext.ts @@ -10,7 +10,6 @@ const isInSearchReportContext = (): boolean => { const lastRootRoute = rootState.routes.at(-1); const lastNestedRoute = lastRootRoute?.state?.routes?.at(-1); - debugger; return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; }; diff --git a/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts b/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts index 2685a399c326e..977080cc4cc9b 100644 --- a/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts +++ b/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts @@ -10,7 +10,6 @@ const isRHPOnSearchReportContext = (): boolean => { const lastRootRoute = rootState.routes.at(-2); const lastNestedRoute = lastRootRoute?.state?.routes?.at(-1); - debugger; return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; }; From e27ca61800e77fa5065097c7ca52159ba1678ef6 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Thu, 28 Aug 2025 16:01:28 +0200 Subject: [PATCH 10/21] fix ts --- .../MoneyRequestReportNavigation.tsx | 12 +----------- src/components/Search/index.tsx | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 07f188ffa124b..9627ab6f50265 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -40,17 +40,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion, bac const {type, status, sortBy, sortOrder, groupBy} = lastSearchQuery?.queryJSON ?? {}; let results: Array = []; if (!!type && !!groupBy && !!currentSearchResults?.data && !!currentSearchResults?.search) { - const temp = getSections( - type, - currentSearchResults.data, - currentSearchResults.search, - accountID, - formatPhoneNumber, - groupBy, - exportReportActions, - lastSearchQuery?.searchKey, - archivedReportsIdSet, - ); + const temp = getSections(type, currentSearchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, lastSearchQuery?.searchKey, archivedReportsIdSet); results = getSortedSections(type, status ?? '', temp, localeCompare, sortBy, sortOrder, groupBy).map((value) => value.reportID); } const allReports = results; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 6d645d36ae9e5..c993303c6a7eb 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -304,7 +304,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS } const results = searchResults - ? getSections(type, searchResults.data, searchResults.search, accountID, formatPhoneNumber, groupBy).map((element) => element?.reportID ?? CONST.REPORT.DEFAULT_REPORT_ID) + ? getSections(type, searchResults.data, accountID, formatPhoneNumber, groupBy).map((element) => element?.reportID ?? CONST.REPORT.DEFAULT_REPORT_ID) : []; handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals, prevReports: results}); From 78aec843076254cd097a07724887df4769ddaeee Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Thu, 28 Aug 2025 16:04:29 +0200 Subject: [PATCH 11/21] remove unnecessary comment --- src/pages/NewReportWorkspaceSelectionPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index a04d9a6812aff..8c979e38f7706 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -46,7 +46,6 @@ function NewReportWorkspaceSelectionPage() { const shouldShowLoadingIndicator = isLoadingApp && !isOffline; const navigateToNewReport = useCallback( (optimisticReportID: string) => { - // On wide screens we use dismissModal instead of forceReplace to avoid performance issues if (isRHPOnReportInSearch) { Navigation.setNavigationActionToMicrotaskQueue(() => { Navigation.dismissModal(); From faaa7352eea61c7e564d11e4d18300ed0287bf63 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Fri, 29 Aug 2025 09:47:02 +0200 Subject: [PATCH 12/21] remove backTo --- src/components/MoneyReportHeader.tsx | 1 - .../MoneyRequestReportView/MoneyRequestReportNavigation.tsx | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 01755cfaf8538..1f49b51cece87 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -1175,7 +1175,6 @@ function MoneyReportHeader({ ) : undefined; diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 9627ab6f50265..1a629b285b378 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -16,10 +16,9 @@ import ONYXKEYS from '@src/ONYXKEYS'; type MoneyRequestReportNavigationProps = { reportID?: string; shouldDisplayNarrowVersion: boolean; - backTo?: string; }; -function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion, backTo}: MoneyRequestReportNavigationProps) { +function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: MoneyRequestReportNavigationProps) { const [lastSearchQuery] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true}); const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${lastSearchQuery?.queryJSON?.hash}`, {canBeMissing: true}); const [accountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false, selector: (s) => s?.accountID}); @@ -83,7 +82,6 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion, bac } Navigation.setParams({ reportID: reportId, - backTo: backTo ?? '', }); }; From ecefd4349b004a6c4c174c2916bef039696d2530 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Fri, 29 Aug 2025 11:35:47 +0200 Subject: [PATCH 13/21] fixes after review --- src/components/MoneyReportHeader.tsx | 14 ++++++-------- .../MoneyRequestReportNavigation.tsx | 12 ++++++------ src/components/Search/index.tsx | 2 +- src/components/Search/types.ts | 2 +- ...text.ts => isOnSearchMoneyRequestReportPage.ts} | 4 ++-- ...t.ts => isRHPOnSearchMoneyRequestReportPage.ts} | 4 ++-- src/libs/actions/ReportNavigation.ts | 6 +++++- src/libs/actions/Search.ts | 10 +++++----- src/pages/NewReportWorkspaceSelectionPage.tsx | 4 ++-- .../sidebar/FloatingActionButtonAndPopover.tsx | 8 ++++---- 10 files changed, 34 insertions(+), 32 deletions(-) rename src/libs/Navigation/helpers/{isInSearchReportContext.ts => isOnSearchMoneyRequestReportPage.ts} (82%) rename src/libs/Navigation/helpers/{isRHPOnSearchReportContext.ts => isRHPOnSearchMoneyRequestReportPage.ts} (81%) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 1f49b51cece87..35b3af2aff56e 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -1171,13 +1171,6 @@ function MoneyReportHeader({ ); - const headerNavigation = isReportInSearch ? ( - - ) : undefined; - return ( )} - {headerNavigation} + {isReportInSearch && ( + + )} diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 1a629b285b378..ea10de68fddec 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -8,7 +8,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {selectArchivedReportsIdSet, selectFilteredReportActions} from '@libs/ReportUtils'; import {getSections, getSortedSections} from '@libs/SearchUIUtils'; import Navigation from '@navigation/Navigation'; -import saveLastSearchParams from '@userActions/ReportNavigation'; +import {saveLastSearchParams} from '@userActions/ReportNavigation'; import {search} from '@userActions/Search'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -39,8 +39,8 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const {type, status, sortBy, sortOrder, groupBy} = lastSearchQuery?.queryJSON ?? {}; let results: Array = []; if (!!type && !!groupBy && !!currentSearchResults?.data && !!currentSearchResults?.search) { - const temp = getSections(type, currentSearchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, lastSearchQuery?.searchKey, archivedReportsIdSet); - results = getSortedSections(type, status ?? '', temp, localeCompare, sortBy, sortOrder, groupBy).map((value) => value.reportID); + const searchData = getSections(type, currentSearchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, lastSearchQuery?.searchKey, archivedReportsIdSet); + results = getSortedSections(type, status ?? '', searchData, localeCompare, sortBy, sortOrder, groupBy).map((value) => value.reportID); } const allReports = results; @@ -87,14 +87,14 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const goToNextReport = () => { if (currentIndex === -1 || allReports.length === 0 || !lastSearchQuery?.queryJSON) { - return ''; + return; } if (currentIndex > allReports.length * 0.75 && lastSearchQuery?.hasMoreResults) { const newOffset = (lastSearchQuery.offset ?? 0) + CONST.SEARCH.RESULTS_PAGE_SIZE; search({ queryJSON: lastSearchQuery.queryJSON, offset: newOffset, - prevReports: allReports, + prevReportsLength: allReports.length, shouldCalculateTotals: false, searchKey: lastSearchQuery.searchKey, }); @@ -106,7 +106,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const goToPrevReport = () => { if (currentIndex === -1 || allReports.length === 0) { - return ''; + return; } const prevIndex = (currentIndex - 1) % allReports.length; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9cb30b6e57be6..065183512a793 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -309,7 +309,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const results = searchResults ? getSections(type, searchResults.data, accountID, formatPhoneNumber, groupBy).map((element) => element?.reportID ?? CONST.REPORT.DEFAULT_REPORT_ID) : []; - handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals, prevReports: results}); + handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals, prevReportsLength: results.length}); // We don't need to run the effect on change of isFocused. // eslint-disable-next-line react-compiler/react-compiler diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 28754aa439216..77ac48f243b88 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -183,7 +183,7 @@ type SearchParams = { queryJSON: SearchQueryJSON; searchKey: SearchKey | undefined; offset: number; - prevReports?: string[]; + prevReportsLength?: number; shouldCalculateTotals: boolean; }; diff --git a/src/libs/Navigation/helpers/isInSearchReportContext.ts b/src/libs/Navigation/helpers/isOnSearchMoneyRequestReportPage.ts similarity index 82% rename from src/libs/Navigation/helpers/isInSearchReportContext.ts rename to src/libs/Navigation/helpers/isOnSearchMoneyRequestReportPage.ts index c4cee424df899..addda284b5da1 100644 --- a/src/libs/Navigation/helpers/isInSearchReportContext.ts +++ b/src/libs/Navigation/helpers/isOnSearchMoneyRequestReportPage.ts @@ -2,7 +2,7 @@ import {navigationRef} from '@libs/Navigation/Navigation'; import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; -const isInSearchReportContext = (): boolean => { +const isOnSearchMoneyRequestReportPage = (): boolean => { const rootState = navigationRef.getRootState() as State | undefined; if (!rootState) { return false; @@ -13,4 +13,4 @@ const isInSearchReportContext = (): boolean => { return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; }; -export default isInSearchReportContext; +export default isOnSearchMoneyRequestReportPage; diff --git a/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts b/src/libs/Navigation/helpers/isRHPOnSearchMoneyRequestReportPage.ts similarity index 81% rename from src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts rename to src/libs/Navigation/helpers/isRHPOnSearchMoneyRequestReportPage.ts index 977080cc4cc9b..d91a3201c5c6d 100644 --- a/src/libs/Navigation/helpers/isRHPOnSearchReportContext.ts +++ b/src/libs/Navigation/helpers/isRHPOnSearchMoneyRequestReportPage.ts @@ -2,7 +2,7 @@ import {navigationRef} from '@libs/Navigation/Navigation'; import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; -const isRHPOnSearchReportContext = (): boolean => { +const isRHPOnSearchMoneyRequestReportPage = (): boolean => { const rootState = navigationRef.getRootState() as State | undefined; if (!rootState) { return false; @@ -13,4 +13,4 @@ const isRHPOnSearchReportContext = (): boolean => { return lastNestedRoute?.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; }; -export default isRHPOnSearchReportContext; +export default isRHPOnSearchMoneyRequestReportPage; diff --git a/src/libs/actions/ReportNavigation.ts b/src/libs/actions/ReportNavigation.ts index b95ef1906455c..682ff68f55dfe 100644 --- a/src/libs/actions/ReportNavigation.ts +++ b/src/libs/actions/ReportNavigation.ts @@ -6,4 +6,8 @@ function saveLastSearchParams(value: LastSearchParams) { Onyx.set(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, value); } -export default saveLastSearchParams; +function clearLastSearchParams() { + Onyx.set(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {}); +} + +export {clearLastSearchParams, saveLastSearchParams}; diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 67502b19d895f..4f987e65153bb 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -29,7 +29,7 @@ import type {PaymentInformation} from '@src/types/onyx/LastPaymentMethod'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type Nullable from '@src/types/utils/Nullable'; -import saveLastSearchParams from './ReportNavigation'; +import {saveLastSearchParams} from './ReportNavigation'; type OnyxSearchResponse = { data: []; @@ -308,13 +308,13 @@ function search({ searchKey, offset, shouldCalculateTotals = false, - prevReports, + prevReportsLength, }: { queryJSON: SearchQueryJSON; searchKey: SearchKey | undefined; offset?: number; shouldCalculateTotals?: boolean; - prevReports?: Array; + prevReportsLength?: number; }) { const {optimisticData, finallyData, failureData} = getOnyxLoadingData(queryJSON.hash, queryJSON); const {flatFilters, ...queryJSONWithoutFlatFilters} = queryJSON; @@ -342,12 +342,12 @@ function search({ if (response?.search?.offset) { // Indicates that search results are extended from the Report view (with navigation between reports), // using previous results to enable correct counter behavior. - if (prevReports) { + if (prevReportsLength) { saveLastSearchParams({ queryJSON, offset, hasMoreResults: !!response?.search?.hasMoreResults, - previousLengthOfResults: prevReports.length, + previousLengthOfResults: prevReportsLength, allowPostSearchRecount: false, }); } diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index 8c979e38f7706..f31fc07b4304d 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -20,7 +20,7 @@ import {getHeaderMessageForNonUserList} from '@libs/OptionsListUtils'; import {isPolicyAdmin, shouldShowPolicy} from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; -import isRHPOnSearchReportContext from '@navigation/helpers/isRHPOnSearchReportContext'; +import isRHPOnSearchMoneyRequestReportPage from '@navigation/helpers/isRHPOnSearchMoneyRequestReportPage'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -38,7 +38,7 @@ function NewReportWorkspaceSelectionPage() { const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const {translate, localeCompare} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const isRHPOnReportInSearch = isRHPOnSearchReportContext(); + const isRHPOnReportInSearch = isRHPOnSearchMoneyRequestReportPage(); const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 74294576b2a39..925104bf98409 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -46,10 +46,10 @@ import { import {getQuickActionIcon, getQuickActionTitle, isQuickActionAllowed} from '@libs/QuickActionUtils'; import {generateReportID, getDisplayNameForParticipant, getIcons, getReportName, getWorkspaceChats, isPolicyExpenseChat} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; -import isInSearchReportContext from '@navigation/helpers/isInSearchReportContext'; +import isOnSearchMoneyRequestReportPage from '@navigation/helpers/isOnSearchMoneyRequestReportPage'; import variables from '@styles/variables'; import {closeReactNativeApp} from '@userActions/HybridApp'; -import saveLastSearchParams from '@userActions/ReportNavigation'; +import {clearLastSearchParams, saveLastSearchParams} from '@userActions/ReportNavigation'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -148,7 +148,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT selector: (policies) => Object.values(policies ?? {}).some((policy) => isPaidGroupPolicy(policy) && isPolicyMember(policy, currentUserPersonalDetails.login)), }); - const isReportInSearch = isInSearchReportContext(); + const isReportInSearch = isOnSearchMoneyRequestReportPage(); const groupPoliciesWithChatEnabled = getGroupPaidPoliciesWithExpenseChatEnabled(); @@ -476,7 +476,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT } if (isReportInSearch) { - saveLastSearchParams({}); + clearLastSearchParams(); } if (!workspaceIDForReportCreation || (shouldRestrictUserBillableActions(workspaceIDForReportCreation) && groupPoliciesWithChatEnabled.length > 1)) { From fafe89bcef0504f17e4272acb47329fb674b8d07 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Fri, 29 Aug 2025 11:43:06 +0200 Subject: [PATCH 14/21] fixes eslint --- src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 925104bf98409..43777d85c5465 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -49,7 +49,7 @@ import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import isOnSearchMoneyRequestReportPage from '@navigation/helpers/isOnSearchMoneyRequestReportPage'; import variables from '@styles/variables'; import {closeReactNativeApp} from '@userActions/HybridApp'; -import {clearLastSearchParams, saveLastSearchParams} from '@userActions/ReportNavigation'; +import {clearLastSearchParams} from '@userActions/ReportNavigation'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; From 3ef0482e30ea429115196e53569d21eb8fa9c76f Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Fri, 29 Aug 2025 14:09:42 +0200 Subject: [PATCH 15/21] disabled next button --- .../MoneyRequestReportView/MoneyRequestReportNavigation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index ea10de68fddec..99a37336444ff 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -47,7 +47,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const currentIndex = allReports.indexOf(reportID ?? CONST.REPORT.DEFAULT_REPORT_ID); const allReportsCount = lastSearchQuery?.previousLengthOfResults ?? 0; - const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; + const hideNextButton = !lastSearchQuery?.hasMoreResults || currentIndex === allReports.length - 1; const hidePrevButton = currentIndex === 0; const styles = useThemeStyles(); const shouldDisplayNavigationArrows = allReports && allReports.length > 1 && !(currentIndex === -1 || !lastSearchQuery?.queryJSON); From d3d7beb0531d8572a0403563735097055e1c6dfc Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Fri, 29 Aug 2025 14:16:03 +0200 Subject: [PATCH 16/21] disabled next button --- .../MoneyRequestReportView/MoneyRequestReportNavigation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 99a37336444ff..ea10de68fddec 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -47,7 +47,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const currentIndex = allReports.indexOf(reportID ?? CONST.REPORT.DEFAULT_REPORT_ID); const allReportsCount = lastSearchQuery?.previousLengthOfResults ?? 0; - const hideNextButton = !lastSearchQuery?.hasMoreResults || currentIndex === allReports.length - 1; + const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; const hidePrevButton = currentIndex === 0; const styles = useThemeStyles(); const shouldDisplayNavigationArrows = allReports && allReports.length > 1 && !(currentIndex === -1 || !lastSearchQuery?.queryJSON); From 16a8cd3e4d74373d18aa9ccca9c40d2a3a7ec2b3 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Mon, 1 Sep 2025 12:07:44 +0200 Subject: [PATCH 17/21] fix next button disabled --- .../MoneyRequestReportView/MoneyRequestReportNavigation.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index ea10de68fddec..722cd67a0579d 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -89,7 +89,9 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo if (currentIndex === -1 || allReports.length === 0 || !lastSearchQuery?.queryJSON) { return; } - if (currentIndex > allReports.length * 0.75 && lastSearchQuery?.hasMoreResults) { + const threshold = Math.min(allReports.length * 0.75, allReports.length - 2); + + if (currentIndex + 1 >= threshold && lastSearchQuery?.hasMoreResults) { const newOffset = (lastSearchQuery.offset ?? 0) + CONST.SEARCH.RESULTS_PAGE_SIZE; search({ queryJSON: lastSearchQuery.queryJSON, From de51bb90167778c05ad395c70135582006c6d0e3 Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Thu, 4 Sep 2025 14:30:58 +0200 Subject: [PATCH 18/21] fix behavior on approved page --- src/components/MoneyReportHeader.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index aa780eda590e7..a8a99594bb16d 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -434,14 +434,6 @@ function MoneyReportHeader({ } else { startApprovedAnimation(); approveMoneyRequest(moneyRequestReport, true); - if (currentSearchQueryJSON) { - search({ - searchKey: currentSearchKey, - shouldCalculateTotals: true, - offset: 0, - queryJSON: currentSearchQueryJSON, - }); - } } }; From 25c31d695b77741822b83a26ed8e1950272508ab Mon Sep 17 00:00:00 2001 From: sumo_slonik Date: Thu, 4 Sep 2025 14:57:28 +0200 Subject: [PATCH 19/21] prettier --- .../MoneyRequestReportView/MoneyRequestReportView.tsx | 2 +- src/components/Search/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx index c3a462648328b..48083d64f8e19 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx @@ -88,7 +88,7 @@ function getParentReportAction(parentReportActions: OnyxEntry Date: Thu, 11 Sep 2025 11:49:53 +0200 Subject: [PATCH 20/21] First adjustments --- .../MoneyRequestReportView/MoneyRequestReportNavigation.tsx | 2 +- .../MoneyRequestReportView/MoneyRequestReportView.tsx | 1 + src/components/PrevNextButtons.tsx | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 722cd67a0579d..beb7f71babb6c 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -50,7 +50,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; const hidePrevButton = currentIndex === 0; const styles = useThemeStyles(); - const shouldDisplayNavigationArrows = allReports && allReports.length > 1 && !(currentIndex === -1 || !lastSearchQuery?.queryJSON); + const shouldDisplayNavigationArrows = allReports && allReports.length > 1 && currentIndex !== -1 && !!lastSearchQuery?.queryJSON; useEffect(() => { if (!lastSearchQuery?.queryJSON) { diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx index e00be379c5ba6..3f1aa36080656 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportView.tsx @@ -47,6 +47,7 @@ type MoneyRequestReportViewProps = { /** Whether Report footer (that includes Composer) should be displayed */ shouldDisplayReportFooter: boolean; + /** Whether we should wait for the report to sync */ shouldWaitForReportSync: boolean; /** The `backTo` route that should be used when clicking back button */ diff --git a/src/components/PrevNextButtons.tsx b/src/components/PrevNextButtons.tsx index 401a4d39fdb20..cd92b59f14ede 100644 --- a/src/components/PrevNextButtons.tsx +++ b/src/components/PrevNextButtons.tsx @@ -16,10 +16,10 @@ type PrevNextButtonsProps = { isNextButtonDisabled?: boolean; /** Moves a user to the next item */ - onNext?: (event?: GestureResponderEvent | KeyboardEvent) => void; + onNext: (event?: GestureResponderEvent | KeyboardEvent) => void; /** Moves a user to the previous item */ - onPrevious?: (event?: GestureResponderEvent | KeyboardEvent) => void; + onPrevious: (event?: GestureResponderEvent | KeyboardEvent) => void; }; function PrevNextButtons({isPrevButtonDisabled, isNextButtonDisabled, onNext, onPrevious}: PrevNextButtonsProps) { From 56b69764c3c564414ed468148161731b9afe5374 Mon Sep 17 00:00:00 2001 From: Zuzanna Furtak Date: Thu, 11 Sep 2025 14:16:44 +0200 Subject: [PATCH 21/21] Second round of adjustments --- src/CONST/index.ts | 1 - .../MoneyRequestReportNavigation.tsx | 2 +- src/components/Search/index.tsx | 42 +++++++++---------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index ea336c85a441f..6583c394e0ada 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1097,7 +1097,6 @@ const CONST = { MAX_COUNT_BEFORE_FOCUS_UPDATE: 30, MIN_INITIAL_REPORT_ACTION_COUNT: 15, UNREPORTED_REPORT_ID: '0', - DEFAULT_REPORT_ID: '1', SPLIT_REPORT_ID: '-2', SECONDARY_ACTIONS: { SUBMIT: 'submit', diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index beb7f71babb6c..06bb6b6911e97 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -44,7 +44,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo } const allReports = results; - const currentIndex = allReports.indexOf(reportID ?? CONST.REPORT.DEFAULT_REPORT_ID); + const currentIndex = allReports.indexOf(reportID); const allReportsCount = lastSearchQuery?.previousLengthOfResults ?? 0; const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 58b0cb07432b9..3047d8ae24ccd 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -336,24 +336,6 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS // eslint-disable-next-line react-hooks/exhaustive-deps }, [isSmallScreenWidth, selectedTransactions, isMobileSelectionModeEnabled]); - useEffect(() => { - const focusedRoute = findFocusedRoute(navigationRef.getRootState()); - const isMigratedModalDisplayed = focusedRoute?.name === NAVIGATORS.MIGRATED_USER_MODAL_NAVIGATOR || focusedRoute?.name === SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT; - - if ((!isFocused && !isMigratedModalDisplayed) || isOffline) { - return; - } - - const results = searchResults - ? getSections(type, searchResults.data, accountID, formatPhoneNumber, groupBy).map((element) => element?.reportID ?? CONST.REPORT.DEFAULT_REPORT_ID) - : []; - handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals, prevReportsLength: results.length}); - - // We don't need to run the effect on change of isFocused. - // eslint-disable-next-line react-compiler/react-compiler - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [handleSearch, isOffline, offset, queryJSON, searchKey, shouldCalculateTotals]); - useEffect(() => { openSearch(); }, []); @@ -378,19 +360,20 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const shouldShowLoadingMoreItems = !shouldShowLoadingState && searchResults?.search?.isLoading && searchResults?.search?.offset > 0; const prevIsSearchResultEmpty = usePrevious(isSearchResultsEmpty); - const data = useMemo(() => { + const [data, dataLength] = useMemo(() => { if (searchResults === undefined || !isDataLoaded) { - return []; + return [[], 0]; } // Group-by option cannot be used for chats or tasks const isChat = type === CONST.SEARCH.DATA_TYPES.CHAT; const isTask = type === CONST.SEARCH.DATA_TYPES.TASK; if (groupBy && (isChat || isTask)) { - return []; + return [[], 0]; } - return getSections(type, searchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, searchKey, archivedReportsIdSet, queryJSON); + const data1 = getSections(type, searchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, searchKey, archivedReportsIdSet, queryJSON); + return [data1, data1.length]; }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, archivedReportsIdSet, formatPhoneNumber, accountID, queryJSON]); useEffect(() => { @@ -398,6 +381,21 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS setShouldShowFiltersBarLoading(shouldShowLoadingState && lastSearchType !== type); }, [lastSearchType, setShouldShowFiltersBarLoading, shouldShowLoadingState, type]); + useEffect(() => { + const focusedRoute = findFocusedRoute(navigationRef.getRootState()); + const isMigratedModalDisplayed = focusedRoute?.name === NAVIGATORS.MIGRATED_USER_MODAL_NAVIGATOR || focusedRoute?.name === SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT; + + if ((!isFocused && !isMigratedModalDisplayed) || isOffline) { + return; + } + + handleSearch({queryJSON, searchKey, offset, shouldCalculateTotals, prevReportsLength: dataLength}); + + // We don't need to run the effect on change of isFocused. + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [handleSearch, isOffline, offset, queryJSON, searchKey, shouldCalculateTotals]); + // When new data load, selectedTransactions is updated in next effect. We use this flag to whether selection is updated const isRefreshingSelection = useRef(false);