From 2c3e70dfe5ecb6e8a639de227c9ba2ad524bfda8 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 27 Feb 2026 22:35:36 +0000 Subject: [PATCH 1/5] Update version to 9.3.27-2 (cherry picked from commit f6bad4b3666871440c14689b714e7ce37b76310a) (cherry-picked to staging by roryabraham) --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- ios/ShareViewController/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index dbd3919fc9a..5652168ef4f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -111,8 +111,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009032701 - versionName "9.3.27-1" + versionCode 1009032702 + versionName "9.3.27-2" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index f365ffc872f..4fbe195f907 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -44,7 +44,7 @@ CFBundleVersion - 9.3.27.1 + 9.3.27.2 FullStory OrgId diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 5e423722d59..a418179d072 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.3.27 CFBundleVersion - 9.3.27.1 + 9.3.27.2 NSExtension NSExtensionPointIdentifier diff --git a/ios/ShareViewController/Info.plist b/ios/ShareViewController/Info.plist index b2378c8f347..da017c09829 100644 --- a/ios/ShareViewController/Info.plist +++ b/ios/ShareViewController/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.3.27 CFBundleVersion - 9.3.27.1 + 9.3.27.2 NSExtension NSExtensionAttributes diff --git a/package-lock.json b/package-lock.json index c0107c7422e..d37383113a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.3.27-1", + "version": "9.3.27-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.3.27-1", + "version": "9.3.27-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index c10d466f03d..fbc33299cf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.3.27-1", + "version": "9.3.27-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From a3f5518db50cd95ec77fb9f3adb2d757145b923d Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 27 Feb 2026 22:36:23 +0000 Subject: [PATCH 2/5] Update Mobile-Expensify submodule version to 9.3.27-2 --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index d2def548c47..adaf7330ca0 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit d2def548c474b3e4e2b5ac46f54b1607c735eef1 +Subproject commit adaf7330ca036168a42ba07f04d9ebeb560c7b40 From 2261a55d240ad92a38cc987b5f13256822a9aa04 Mon Sep 17 00:00:00 2001 From: Ben Limpich Date: Fri, 27 Feb 2026 15:09:59 -0800 Subject: [PATCH 3/5] cherry-pick PR #83749 to staging (cherry-picked to staging by roryabraham) --- src/hooks/useLoadReportActions.ts | 52 ++++++++++++------- src/libs/API/index.ts | 6 ++- src/libs/API/parameters/OpenReportParams.ts | 1 - src/libs/actions/Report/index.ts | 7 ++- src/pages/inbox/report/ReportActionsList.tsx | 28 ++++++++-- src/pages/inbox/report/ReportActionsView.tsx | 1 + .../index.ts | 2 +- tests/ui/PaginationTest.tsx | 11 ++-- tests/unit/useLoadReportActionsTest.tsx | 1 + 9 files changed, 70 insertions(+), 39 deletions(-) diff --git a/src/hooks/useLoadReportActions.ts b/src/hooks/useLoadReportActions.ts index 6eb00bcec4a..14755d8655c 100644 --- a/src/hooks/useLoadReportActions.ts +++ b/src/hooks/useLoadReportActions.ts @@ -1,5 +1,5 @@ import {useIsFocused} from '@react-navigation/native'; -import {useCallback, useMemo} from 'react'; +import {useCallback, useMemo, useRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {getNewerActions, getOlderActions} from '@userActions/Report'; import CONST from '@src/CONST'; @@ -11,6 +11,9 @@ type UseLoadReportActionsArguments = { /** The id of the current report */ reportID: string; + /** The id of the reportAction (if specific action was linked to */ + reportActionID?: string; + /** The list of reportActions linked to the current report */ reportActions: ReportAction[]; @@ -31,14 +34,16 @@ type UseLoadReportActionsArguments = { * Provides reusable logic to get the functions for loading older/newer reportActions. * Used in the report displaying components */ -function useLoadReportActions({reportID, reportActions, allReportActionIDs, transactionThreadReport, hasOlderActions, hasNewerActions}: UseLoadReportActionsArguments) { +function useLoadReportActions({reportID, reportActionID, reportActions, allReportActionIDs, transactionThreadReport, hasOlderActions, hasNewerActions}: UseLoadReportActionsArguments) { + const didLoadOlderChats = useRef(false); + const didLoadNewerChats = useRef(false); + const {isOffline} = useNetwork(); const isFocused = useIsFocused(); + const newestReportAction = useMemo(() => reportActions?.at(0), [reportActions]); const oldestReportAction = useMemo(() => reportActions?.at(-1), [reportActions]); - const isTransactionThreadReport = !isEmptyObject(transactionThreadReport); - // Track oldest/newest actions per report in a single pass const {currentReportOldest, currentReportNewest, transactionThreadOldest, transactionThreadNewest} = useMemo(() => { let currentReportNewestAction = null; @@ -61,7 +66,7 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran } // Oldest = last matching action we encounter currentReportOldestAction = action; - } else if (isTransactionThreadReport && transactionThreadReport?.reportID === targetReportID) { + } else if (!isEmptyObject(transactionThreadReport) && transactionThreadReport?.reportID === targetReportID) { // Same logic for transaction thread if (!transactionThreadNewestAction) { transactionThreadNewestAction = action; @@ -76,7 +81,7 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran transactionThreadOldest: transactionThreadOldestAction, transactionThreadNewest: transactionThreadNewestAction, }; - }, [allReportActionIDs, isTransactionThreadReport, reportActions, reportID, transactionThreadReport?.reportID]); + }, [reportActions, allReportActionIDs, reportID, transactionThreadReport]); /** * Retrieves the next set of reportActions for the chat once we are nearing the end of what we are currently @@ -94,40 +99,37 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran return; } - if (isTransactionThreadReport) { + didLoadOlderChats.current = true; + + if (!isEmptyObject(transactionThreadReport)) { getOlderActions(reportID, currentReportOldest?.reportActionID); - getOlderActions(transactionThreadReport?.reportID, transactionThreadOldest?.reportActionID); + getOlderActions(transactionThreadReport.reportID, transactionThreadOldest?.reportActionID); } else { getOlderActions(reportID, currentReportOldest?.reportActionID); } }, - [ - currentReportOldest?.reportActionID, - hasOlderActions, - isOffline, - isTransactionThreadReport, - oldestReportAction, - reportID, - transactionThreadOldest?.reportActionID, - transactionThreadReport?.reportID, - ], + [isOffline, oldestReportAction, hasOlderActions, transactionThreadReport, reportID, currentReportOldest?.reportActionID, transactionThreadOldest?.reportActionID], ); const loadNewerChats = useCallback( (force = false) => { if ( !force && - (!isFocused || + (!reportActionID || + !isFocused || !newestReportAction || !hasNewerActions || isOffline || // If there was an error only try again once on initial mount. We should also still load // more in case we have cached messages. + didLoadNewerChats.current || newestReportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) ) { return; } + didLoadNewerChats.current = true; + if (!isEmptyObject(transactionThreadReport)) { getNewerActions(reportID, currentReportNewest?.reportActionID); getNewerActions(transactionThreadReport.reportID, transactionThreadNewest?.reportActionID); @@ -135,7 +137,17 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran getNewerActions(reportID, newestReportAction.reportActionID); } }, - [currentReportNewest?.reportActionID, hasNewerActions, isFocused, isOffline, newestReportAction, reportID, transactionThreadNewest?.reportActionID, transactionThreadReport], + [ + reportActionID, + isFocused, + newestReportAction, + hasNewerActions, + isOffline, + transactionThreadReport, + reportID, + currentReportNewest?.reportActionID, + transactionThreadNewest?.reportActionID, + ], ); return { diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index 50c959552f0..e1b9419a0f6 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -311,11 +311,13 @@ function paginate processRequest(request, type)); + waitForWrites(command as ReadCommand).then(() => processRequest(request, type)); + return; default: throw new Error('Unknown API request type'); } diff --git a/src/libs/API/parameters/OpenReportParams.ts b/src/libs/API/parameters/OpenReportParams.ts index 7c3ab73bab0..aa58f4c9f67 100644 --- a/src/libs/API/parameters/OpenReportParams.ts +++ b/src/libs/API/parameters/OpenReportParams.ts @@ -26,7 +26,6 @@ type OpenReportParams = { */ moneyRequestPreviewReportActionID?: string; includePartiallySetupBankAccounts?: boolean; - useLastUnreadReportAction?: boolean; }; export default OpenReportParams; diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index b5828dac4da..65c295ba914 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -1287,7 +1287,6 @@ function openReport( parentReportActionID, transactionID: transaction?.transactionID, includePartiallySetupBankAccounts: true, - useLastUnreadReportAction: true, }; if (optimisticSelfDMReport) { @@ -2028,7 +2027,7 @@ function explain( */ function getOlderActions(reportID: string | undefined, reportActionID: string | undefined) { if (!reportID || !reportActionID) { - return Promise.resolve(); + return; } const optimisticData: Array> = [ @@ -2068,7 +2067,7 @@ function getOlderActions(reportID: string | undefined, reportActionID: string | reportActionID, }; - return API.paginate( + API.paginate( CONST.API_REQUEST_TYPE.READ, READ_COMMANDS.GET_OLDER_ACTIONS, parameters, @@ -2126,7 +2125,7 @@ function getNewerActions(reportID: string | undefined, reportActionID: string | reportActionID, }; - return API.paginate( + API.paginate( CONST.API_REQUEST_TYPE.READ, READ_COMMANDS.GET_NEWER_ACTIONS, parameters, diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index cbf9ff2875d..0cf417cef2e 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -7,7 +7,12 @@ import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent} from 'r import {DeviceEventEmitter, InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {renderScrollComponent as renderActionSheetAwareScrollView} from '@components/ActionSheetAwareScrollView'; +<<<<<<< HEAD import InvertedFlatList from '@components/InvertedFlatList'; +======= +import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@components/FlatList/hooks/useFlatListScrollKey'; +import InvertedFlatList from '@components/FlatList/InvertedFlatList'; +>>>>>>> 9c8341218f7 (Merge pull request #83749 from Expensify/blimpich-revertPR76104) import {usePersonalDetails} from '@components/OnyxListItemProvider'; import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; @@ -344,10 +349,13 @@ function ReportActionsList({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [lastAction?.created]); + const lastActionIndex = lastAction?.reportActionID; + const reportActionSize = useRef(sortedVisibleReportActions.length); const lastVisibleActionCreated = getReportLastVisibleActionCreated(report, transactionThreadReport); const hasNewestReportAction = lastAction?.created === lastVisibleActionCreated || isReportPreviewAction(lastAction); const hasNewestReportActionRef = useRef(hasNewestReportAction); hasNewestReportActionRef.current = hasNewestReportAction; + const previousLastIndex = useRef(lastActionIndex); const sortedVisibleReportActionsRef = useRef(sortedVisibleReportActions); const {isFloatingMessageCounterVisible, setIsFloatingMessageCounterVisible, trackVerticalScrolling, onViewableItemsChanged} = useReportUnreadMessageScrollTracking({ @@ -366,6 +374,20 @@ function ReportActionsList({ hasOnceLoadedReportActions: !!reportMetadata?.hasOnceLoadedReportActions, }); + useEffect(() => { + if ( + scrollOffsetRef.current < AUTOSCROLL_TO_TOP_THRESHOLD && + previousLastIndex.current !== lastActionIndex && + reportActionSize.current !== sortedVisibleReportActions.length && + hasNewestReportAction + ) { + setIsFloatingMessageCounterVisible(false); + reportScrollManager.scrollToBottom(); + } + previousLastIndex.current = lastActionIndex; + reportActionSize.current = sortedVisibleReportActions.length; + }, [lastActionIndex, sortedVisibleReportActions.length, reportScrollManager, hasNewestReportAction, linkedReportActionID, setIsFloatingMessageCounterVisible, scrollOffsetRef]); + useEffect(() => { const shouldTriggerScroll = shouldFocusToTopOnMount && prevHasCreatedActionAdded && !hasCreatedActionAdded; if (!shouldTriggerScroll) { @@ -526,13 +548,9 @@ function ReportActionsList({ if (action?.reportActionID) { setActionIdToHighlight(action.reportActionID); } - } else if (Navigation.getReportRHPActiveRoute()) { + } else { setIsFloatingMessageCounterVisible(false); reportScrollManager.scrollToBottom(); - } else { - Navigation.setNavigationActionToMicrotaskQueue(() => { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.reportID)); - }); } setIsScrollToBottomEnabled(true); diff --git a/src/pages/inbox/report/ReportActionsView.tsx b/src/pages/inbox/report/ReportActionsView.tsx index da9bb5d5f1f..8202baf851d 100755 --- a/src/pages/inbox/report/ReportActionsView.tsx +++ b/src/pages/inbox/report/ReportActionsView.tsx @@ -265,6 +265,7 @@ function ReportActionsView({ const {loadOlderChats, loadNewerChats} = useLoadReportActions({ reportID, + reportActionID, reportActions, allReportActionIDs, transactionThreadReport, diff --git a/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts b/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts index 6ef204b0acd..cef1d5e70e6 100644 --- a/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts +++ b/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts @@ -1,7 +1,7 @@ import type ChatContentScrollViewPlatformStyles from './types'; const chatContentScrollViewPlatformStyles: ChatContentScrollViewPlatformStyles = { - overflow: 'clip', + overflow: 'hidden', }; export default chatContentScrollViewPlatformStyles; diff --git a/tests/ui/PaginationTest.tsx b/tests/ui/PaginationTest.tsx index 07474755fdc..d2bebf6fca7 100644 --- a/tests/ui/PaginationTest.tsx +++ b/tests/ui/PaginationTest.tsx @@ -376,9 +376,6 @@ describe('Pagination', () => { // Here we have 5 messages from the initial OpenReport and 5 from the initial GetNewerActions. expect(getReportActions()).toHaveLength(10); - // Simulate the backend returning no new messages to simulate reaching the start of the chat. - mockGetNewerActions(0); - // There is 1 extra call here because of the comment linking report. TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalledWith('OpenReport', 1, {reportID: REPORT_ID, reportActionID: '5'}); @@ -393,20 +390,22 @@ describe('Pagination', () => { TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0); - TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 2); + TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1); // We now have 10 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call. expect(getReportActions()).toHaveLength(10); + // Simulate the backend returning no new messages to simulate reaching the start of the chat. + mockGetNewerActions(0); + scrollToOffset(500); await waitForBatchedUpdatesWithAct(); scrollToOffset(0); await waitForBatchedUpdatesWithAct(); - // When there are no newer actions, we don't want to trigger GetNewerActions again. TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0); - TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 2); + TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1); // We still have 15 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call. expect(getReportActions()).toHaveLength(10); diff --git a/tests/unit/useLoadReportActionsTest.tsx b/tests/unit/useLoadReportActionsTest.tsx index 871d57c808a..2f743e78d0c 100644 --- a/tests/unit/useLoadReportActionsTest.tsx +++ b/tests/unit/useLoadReportActionsTest.tsx @@ -124,6 +124,7 @@ describe('useLoadReportActions', () => { const props = { ...baseProps, hasNewerActions: true, + reportActionID: 'EXISTING_ACTION_ID', }; const {result} = renderHook(() => useLoadReportActions(props)); From 52ef8da06368219fc46fb8fd6c0df34cd727c77d Mon Sep 17 00:00:00 2001 From: Ben Limpich Date: Fri, 27 Feb 2026 15:13:14 -0800 Subject: [PATCH 4/5] Revert "cherry-pick PR #83749 to staging" This reverts commit 2261a55d240ad92a38cc987b5f13256822a9aa04. --- src/hooks/useLoadReportActions.ts | 52 +++++++------------ src/libs/API/index.ts | 6 +-- src/libs/API/parameters/OpenReportParams.ts | 1 + src/libs/actions/Report/index.ts | 7 +-- src/pages/inbox/report/ReportActionsList.tsx | 28 ++-------- src/pages/inbox/report/ReportActionsView.tsx | 1 - .../index.ts | 2 +- tests/ui/PaginationTest.tsx | 11 ++-- tests/unit/useLoadReportActionsTest.tsx | 1 - 9 files changed, 39 insertions(+), 70 deletions(-) diff --git a/src/hooks/useLoadReportActions.ts b/src/hooks/useLoadReportActions.ts index 14755d8655c..6eb00bcec4a 100644 --- a/src/hooks/useLoadReportActions.ts +++ b/src/hooks/useLoadReportActions.ts @@ -1,5 +1,5 @@ import {useIsFocused} from '@react-navigation/native'; -import {useCallback, useMemo, useRef} from 'react'; +import {useCallback, useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {getNewerActions, getOlderActions} from '@userActions/Report'; import CONST from '@src/CONST'; @@ -11,9 +11,6 @@ type UseLoadReportActionsArguments = { /** The id of the current report */ reportID: string; - /** The id of the reportAction (if specific action was linked to */ - reportActionID?: string; - /** The list of reportActions linked to the current report */ reportActions: ReportAction[]; @@ -34,16 +31,14 @@ type UseLoadReportActionsArguments = { * Provides reusable logic to get the functions for loading older/newer reportActions. * Used in the report displaying components */ -function useLoadReportActions({reportID, reportActionID, reportActions, allReportActionIDs, transactionThreadReport, hasOlderActions, hasNewerActions}: UseLoadReportActionsArguments) { - const didLoadOlderChats = useRef(false); - const didLoadNewerChats = useRef(false); - +function useLoadReportActions({reportID, reportActions, allReportActionIDs, transactionThreadReport, hasOlderActions, hasNewerActions}: UseLoadReportActionsArguments) { const {isOffline} = useNetwork(); const isFocused = useIsFocused(); - const newestReportAction = useMemo(() => reportActions?.at(0), [reportActions]); const oldestReportAction = useMemo(() => reportActions?.at(-1), [reportActions]); + const isTransactionThreadReport = !isEmptyObject(transactionThreadReport); + // Track oldest/newest actions per report in a single pass const {currentReportOldest, currentReportNewest, transactionThreadOldest, transactionThreadNewest} = useMemo(() => { let currentReportNewestAction = null; @@ -66,7 +61,7 @@ function useLoadReportActions({reportID, reportActionID, reportActions, allRepor } // Oldest = last matching action we encounter currentReportOldestAction = action; - } else if (!isEmptyObject(transactionThreadReport) && transactionThreadReport?.reportID === targetReportID) { + } else if (isTransactionThreadReport && transactionThreadReport?.reportID === targetReportID) { // Same logic for transaction thread if (!transactionThreadNewestAction) { transactionThreadNewestAction = action; @@ -81,7 +76,7 @@ function useLoadReportActions({reportID, reportActionID, reportActions, allRepor transactionThreadOldest: transactionThreadOldestAction, transactionThreadNewest: transactionThreadNewestAction, }; - }, [reportActions, allReportActionIDs, reportID, transactionThreadReport]); + }, [allReportActionIDs, isTransactionThreadReport, reportActions, reportID, transactionThreadReport?.reportID]); /** * Retrieves the next set of reportActions for the chat once we are nearing the end of what we are currently @@ -99,37 +94,40 @@ function useLoadReportActions({reportID, reportActionID, reportActions, allRepor return; } - didLoadOlderChats.current = true; - - if (!isEmptyObject(transactionThreadReport)) { + if (isTransactionThreadReport) { getOlderActions(reportID, currentReportOldest?.reportActionID); - getOlderActions(transactionThreadReport.reportID, transactionThreadOldest?.reportActionID); + getOlderActions(transactionThreadReport?.reportID, transactionThreadOldest?.reportActionID); } else { getOlderActions(reportID, currentReportOldest?.reportActionID); } }, - [isOffline, oldestReportAction, hasOlderActions, transactionThreadReport, reportID, currentReportOldest?.reportActionID, transactionThreadOldest?.reportActionID], + [ + currentReportOldest?.reportActionID, + hasOlderActions, + isOffline, + isTransactionThreadReport, + oldestReportAction, + reportID, + transactionThreadOldest?.reportActionID, + transactionThreadReport?.reportID, + ], ); const loadNewerChats = useCallback( (force = false) => { if ( !force && - (!reportActionID || - !isFocused || + (!isFocused || !newestReportAction || !hasNewerActions || isOffline || // If there was an error only try again once on initial mount. We should also still load // more in case we have cached messages. - didLoadNewerChats.current || newestReportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) ) { return; } - didLoadNewerChats.current = true; - if (!isEmptyObject(transactionThreadReport)) { getNewerActions(reportID, currentReportNewest?.reportActionID); getNewerActions(transactionThreadReport.reportID, transactionThreadNewest?.reportActionID); @@ -137,17 +135,7 @@ function useLoadReportActions({reportID, reportActionID, reportActions, allRepor getNewerActions(reportID, newestReportAction.reportActionID); } }, - [ - reportActionID, - isFocused, - newestReportAction, - hasNewerActions, - isOffline, - transactionThreadReport, - reportID, - currentReportNewest?.reportActionID, - transactionThreadNewest?.reportActionID, - ], + [currentReportNewest?.reportActionID, hasNewerActions, isFocused, isOffline, newestReportAction, reportID, transactionThreadNewest?.reportActionID, transactionThreadReport], ); return { diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index e1b9419a0f6..50c959552f0 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -311,13 +311,11 @@ function paginate processRequest(request, type)); - return; + return waitForWrites(command as ReadCommand).then(() => processRequest(request, type)); default: throw new Error('Unknown API request type'); } diff --git a/src/libs/API/parameters/OpenReportParams.ts b/src/libs/API/parameters/OpenReportParams.ts index aa58f4c9f67..7c3ab73bab0 100644 --- a/src/libs/API/parameters/OpenReportParams.ts +++ b/src/libs/API/parameters/OpenReportParams.ts @@ -26,6 +26,7 @@ type OpenReportParams = { */ moneyRequestPreviewReportActionID?: string; includePartiallySetupBankAccounts?: boolean; + useLastUnreadReportAction?: boolean; }; export default OpenReportParams; diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index 65c295ba914..b5828dac4da 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -1287,6 +1287,7 @@ function openReport( parentReportActionID, transactionID: transaction?.transactionID, includePartiallySetupBankAccounts: true, + useLastUnreadReportAction: true, }; if (optimisticSelfDMReport) { @@ -2027,7 +2028,7 @@ function explain( */ function getOlderActions(reportID: string | undefined, reportActionID: string | undefined) { if (!reportID || !reportActionID) { - return; + return Promise.resolve(); } const optimisticData: Array> = [ @@ -2067,7 +2068,7 @@ function getOlderActions(reportID: string | undefined, reportActionID: string | reportActionID, }; - API.paginate( + return API.paginate( CONST.API_REQUEST_TYPE.READ, READ_COMMANDS.GET_OLDER_ACTIONS, parameters, @@ -2125,7 +2126,7 @@ function getNewerActions(reportID: string | undefined, reportActionID: string | reportActionID, }; - API.paginate( + return API.paginate( CONST.API_REQUEST_TYPE.READ, READ_COMMANDS.GET_NEWER_ACTIONS, parameters, diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index 0cf417cef2e..cbf9ff2875d 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -7,12 +7,7 @@ import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent} from 'r import {DeviceEventEmitter, InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {renderScrollComponent as renderActionSheetAwareScrollView} from '@components/ActionSheetAwareScrollView'; -<<<<<<< HEAD import InvertedFlatList from '@components/InvertedFlatList'; -======= -import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@components/FlatList/hooks/useFlatListScrollKey'; -import InvertedFlatList from '@components/FlatList/InvertedFlatList'; ->>>>>>> 9c8341218f7 (Merge pull request #83749 from Expensify/blimpich-revertPR76104) import {usePersonalDetails} from '@components/OnyxListItemProvider'; import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; @@ -349,13 +344,10 @@ function ReportActionsList({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [lastAction?.created]); - const lastActionIndex = lastAction?.reportActionID; - const reportActionSize = useRef(sortedVisibleReportActions.length); const lastVisibleActionCreated = getReportLastVisibleActionCreated(report, transactionThreadReport); const hasNewestReportAction = lastAction?.created === lastVisibleActionCreated || isReportPreviewAction(lastAction); const hasNewestReportActionRef = useRef(hasNewestReportAction); hasNewestReportActionRef.current = hasNewestReportAction; - const previousLastIndex = useRef(lastActionIndex); const sortedVisibleReportActionsRef = useRef(sortedVisibleReportActions); const {isFloatingMessageCounterVisible, setIsFloatingMessageCounterVisible, trackVerticalScrolling, onViewableItemsChanged} = useReportUnreadMessageScrollTracking({ @@ -374,20 +366,6 @@ function ReportActionsList({ hasOnceLoadedReportActions: !!reportMetadata?.hasOnceLoadedReportActions, }); - useEffect(() => { - if ( - scrollOffsetRef.current < AUTOSCROLL_TO_TOP_THRESHOLD && - previousLastIndex.current !== lastActionIndex && - reportActionSize.current !== sortedVisibleReportActions.length && - hasNewestReportAction - ) { - setIsFloatingMessageCounterVisible(false); - reportScrollManager.scrollToBottom(); - } - previousLastIndex.current = lastActionIndex; - reportActionSize.current = sortedVisibleReportActions.length; - }, [lastActionIndex, sortedVisibleReportActions.length, reportScrollManager, hasNewestReportAction, linkedReportActionID, setIsFloatingMessageCounterVisible, scrollOffsetRef]); - useEffect(() => { const shouldTriggerScroll = shouldFocusToTopOnMount && prevHasCreatedActionAdded && !hasCreatedActionAdded; if (!shouldTriggerScroll) { @@ -548,9 +526,13 @@ function ReportActionsList({ if (action?.reportActionID) { setActionIdToHighlight(action.reportActionID); } - } else { + } else if (Navigation.getReportRHPActiveRoute()) { setIsFloatingMessageCounterVisible(false); reportScrollManager.scrollToBottom(); + } else { + Navigation.setNavigationActionToMicrotaskQueue(() => { + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.reportID)); + }); } setIsScrollToBottomEnabled(true); diff --git a/src/pages/inbox/report/ReportActionsView.tsx b/src/pages/inbox/report/ReportActionsView.tsx index 8202baf851d..da9bb5d5f1f 100755 --- a/src/pages/inbox/report/ReportActionsView.tsx +++ b/src/pages/inbox/report/ReportActionsView.tsx @@ -265,7 +265,6 @@ function ReportActionsView({ const {loadOlderChats, loadNewerChats} = useLoadReportActions({ reportID, - reportActionID, reportActions, allReportActionIDs, transactionThreadReport, diff --git a/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts b/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts index cef1d5e70e6..6ef204b0acd 100644 --- a/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts +++ b/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts @@ -1,7 +1,7 @@ import type ChatContentScrollViewPlatformStyles from './types'; const chatContentScrollViewPlatformStyles: ChatContentScrollViewPlatformStyles = { - overflow: 'hidden', + overflow: 'clip', }; export default chatContentScrollViewPlatformStyles; diff --git a/tests/ui/PaginationTest.tsx b/tests/ui/PaginationTest.tsx index d2bebf6fca7..07474755fdc 100644 --- a/tests/ui/PaginationTest.tsx +++ b/tests/ui/PaginationTest.tsx @@ -376,6 +376,9 @@ describe('Pagination', () => { // Here we have 5 messages from the initial OpenReport and 5 from the initial GetNewerActions. expect(getReportActions()).toHaveLength(10); + // Simulate the backend returning no new messages to simulate reaching the start of the chat. + mockGetNewerActions(0); + // There is 1 extra call here because of the comment linking report. TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalledWith('OpenReport', 1, {reportID: REPORT_ID, reportActionID: '5'}); @@ -390,22 +393,20 @@ describe('Pagination', () => { TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0); - TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1); + TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 2); // We now have 10 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call. expect(getReportActions()).toHaveLength(10); - // Simulate the backend returning no new messages to simulate reaching the start of the chat. - mockGetNewerActions(0); - scrollToOffset(500); await waitForBatchedUpdatesWithAct(); scrollToOffset(0); await waitForBatchedUpdatesWithAct(); + // When there are no newer actions, we don't want to trigger GetNewerActions again. TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0); - TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1); + TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 2); // We still have 15 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call. expect(getReportActions()).toHaveLength(10); diff --git a/tests/unit/useLoadReportActionsTest.tsx b/tests/unit/useLoadReportActionsTest.tsx index 2f743e78d0c..871d57c808a 100644 --- a/tests/unit/useLoadReportActionsTest.tsx +++ b/tests/unit/useLoadReportActionsTest.tsx @@ -124,7 +124,6 @@ describe('useLoadReportActions', () => { const props = { ...baseProps, hasNewerActions: true, - reportActionID: 'EXISTING_ACTION_ID', }; const {result} = renderHook(() => useLoadReportActions(props)); From f65c86924a5af2220355bd7c27735ec386bd51d4 Mon Sep 17 00:00:00 2001 From: Rory Abraham <47436092+roryabraham@users.noreply.github.com> Date: Fri, 27 Feb 2026 14:34:31 -0800 Subject: [PATCH 5/5] Merge pull request #83749 from Expensify/blimpich-revertPR76104 Revert "fix: Allow multiple loads in useLoadReportActions hook" (cherry picked from commit 9c8341218f787c5c5050138f8b38610e60cb87d8) (cherry-picked to staging by roryabraham) --- src/hooks/useLoadReportActions.ts | 52 ++++++++++++------- src/libs/API/index.ts | 6 ++- src/libs/API/parameters/OpenReportParams.ts | 1 - src/libs/actions/Report/index.ts | 7 ++- src/pages/inbox/report/ReportActionsList.tsx | 24 +++++++-- src/pages/inbox/report/ReportActionsView.tsx | 1 + .../index.ts | 2 +- tests/ui/PaginationTest.tsx | 11 ++-- tests/unit/useLoadReportActionsTest.tsx | 1 + 9 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/hooks/useLoadReportActions.ts b/src/hooks/useLoadReportActions.ts index 6eb00bcec4a..14755d8655c 100644 --- a/src/hooks/useLoadReportActions.ts +++ b/src/hooks/useLoadReportActions.ts @@ -1,5 +1,5 @@ import {useIsFocused} from '@react-navigation/native'; -import {useCallback, useMemo} from 'react'; +import {useCallback, useMemo, useRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {getNewerActions, getOlderActions} from '@userActions/Report'; import CONST from '@src/CONST'; @@ -11,6 +11,9 @@ type UseLoadReportActionsArguments = { /** The id of the current report */ reportID: string; + /** The id of the reportAction (if specific action was linked to */ + reportActionID?: string; + /** The list of reportActions linked to the current report */ reportActions: ReportAction[]; @@ -31,14 +34,16 @@ type UseLoadReportActionsArguments = { * Provides reusable logic to get the functions for loading older/newer reportActions. * Used in the report displaying components */ -function useLoadReportActions({reportID, reportActions, allReportActionIDs, transactionThreadReport, hasOlderActions, hasNewerActions}: UseLoadReportActionsArguments) { +function useLoadReportActions({reportID, reportActionID, reportActions, allReportActionIDs, transactionThreadReport, hasOlderActions, hasNewerActions}: UseLoadReportActionsArguments) { + const didLoadOlderChats = useRef(false); + const didLoadNewerChats = useRef(false); + const {isOffline} = useNetwork(); const isFocused = useIsFocused(); + const newestReportAction = useMemo(() => reportActions?.at(0), [reportActions]); const oldestReportAction = useMemo(() => reportActions?.at(-1), [reportActions]); - const isTransactionThreadReport = !isEmptyObject(transactionThreadReport); - // Track oldest/newest actions per report in a single pass const {currentReportOldest, currentReportNewest, transactionThreadOldest, transactionThreadNewest} = useMemo(() => { let currentReportNewestAction = null; @@ -61,7 +66,7 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran } // Oldest = last matching action we encounter currentReportOldestAction = action; - } else if (isTransactionThreadReport && transactionThreadReport?.reportID === targetReportID) { + } else if (!isEmptyObject(transactionThreadReport) && transactionThreadReport?.reportID === targetReportID) { // Same logic for transaction thread if (!transactionThreadNewestAction) { transactionThreadNewestAction = action; @@ -76,7 +81,7 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran transactionThreadOldest: transactionThreadOldestAction, transactionThreadNewest: transactionThreadNewestAction, }; - }, [allReportActionIDs, isTransactionThreadReport, reportActions, reportID, transactionThreadReport?.reportID]); + }, [reportActions, allReportActionIDs, reportID, transactionThreadReport]); /** * Retrieves the next set of reportActions for the chat once we are nearing the end of what we are currently @@ -94,40 +99,37 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran return; } - if (isTransactionThreadReport) { + didLoadOlderChats.current = true; + + if (!isEmptyObject(transactionThreadReport)) { getOlderActions(reportID, currentReportOldest?.reportActionID); - getOlderActions(transactionThreadReport?.reportID, transactionThreadOldest?.reportActionID); + getOlderActions(transactionThreadReport.reportID, transactionThreadOldest?.reportActionID); } else { getOlderActions(reportID, currentReportOldest?.reportActionID); } }, - [ - currentReportOldest?.reportActionID, - hasOlderActions, - isOffline, - isTransactionThreadReport, - oldestReportAction, - reportID, - transactionThreadOldest?.reportActionID, - transactionThreadReport?.reportID, - ], + [isOffline, oldestReportAction, hasOlderActions, transactionThreadReport, reportID, currentReportOldest?.reportActionID, transactionThreadOldest?.reportActionID], ); const loadNewerChats = useCallback( (force = false) => { if ( !force && - (!isFocused || + (!reportActionID || + !isFocused || !newestReportAction || !hasNewerActions || isOffline || // If there was an error only try again once on initial mount. We should also still load // more in case we have cached messages. + didLoadNewerChats.current || newestReportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) ) { return; } + didLoadNewerChats.current = true; + if (!isEmptyObject(transactionThreadReport)) { getNewerActions(reportID, currentReportNewest?.reportActionID); getNewerActions(transactionThreadReport.reportID, transactionThreadNewest?.reportActionID); @@ -135,7 +137,17 @@ function useLoadReportActions({reportID, reportActions, allReportActionIDs, tran getNewerActions(reportID, newestReportAction.reportActionID); } }, - [currentReportNewest?.reportActionID, hasNewerActions, isFocused, isOffline, newestReportAction, reportID, transactionThreadNewest?.reportActionID, transactionThreadReport], + [ + reportActionID, + isFocused, + newestReportAction, + hasNewerActions, + isOffline, + transactionThreadReport, + reportID, + currentReportNewest?.reportActionID, + transactionThreadNewest?.reportActionID, + ], ); return { diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index 50c959552f0..e1b9419a0f6 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -311,11 +311,13 @@ function paginate processRequest(request, type)); + waitForWrites(command as ReadCommand).then(() => processRequest(request, type)); + return; default: throw new Error('Unknown API request type'); } diff --git a/src/libs/API/parameters/OpenReportParams.ts b/src/libs/API/parameters/OpenReportParams.ts index 7c3ab73bab0..aa58f4c9f67 100644 --- a/src/libs/API/parameters/OpenReportParams.ts +++ b/src/libs/API/parameters/OpenReportParams.ts @@ -26,7 +26,6 @@ type OpenReportParams = { */ moneyRequestPreviewReportActionID?: string; includePartiallySetupBankAccounts?: boolean; - useLastUnreadReportAction?: boolean; }; export default OpenReportParams; diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index b5828dac4da..65c295ba914 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -1287,7 +1287,6 @@ function openReport( parentReportActionID, transactionID: transaction?.transactionID, includePartiallySetupBankAccounts: true, - useLastUnreadReportAction: true, }; if (optimisticSelfDMReport) { @@ -2028,7 +2027,7 @@ function explain( */ function getOlderActions(reportID: string | undefined, reportActionID: string | undefined) { if (!reportID || !reportActionID) { - return Promise.resolve(); + return; } const optimisticData: Array> = [ @@ -2068,7 +2067,7 @@ function getOlderActions(reportID: string | undefined, reportActionID: string | reportActionID, }; - return API.paginate( + API.paginate( CONST.API_REQUEST_TYPE.READ, READ_COMMANDS.GET_OLDER_ACTIONS, parameters, @@ -2126,7 +2125,7 @@ function getNewerActions(reportID: string | undefined, reportActionID: string | reportActionID, }; - return API.paginate( + API.paginate( CONST.API_REQUEST_TYPE.READ, READ_COMMANDS.GET_NEWER_ACTIONS, parameters, diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index cbf9ff2875d..77ebc4e914f 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -11,6 +11,7 @@ import InvertedFlatList from '@components/InvertedFlatList'; import {usePersonalDetails} from '@components/OnyxListItemProvider'; import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@hooks/useFlatListScrollKey'; import useIsAnonymousUser from '@hooks/useIsAnonymousUser'; import useLocalize from '@hooks/useLocalize'; import useNetworkWithOfflineStatus from '@hooks/useNetworkWithOfflineStatus'; @@ -344,10 +345,13 @@ function ReportActionsList({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [lastAction?.created]); + const lastActionIndex = lastAction?.reportActionID; + const reportActionSize = useRef(sortedVisibleReportActions.length); const lastVisibleActionCreated = getReportLastVisibleActionCreated(report, transactionThreadReport); const hasNewestReportAction = lastAction?.created === lastVisibleActionCreated || isReportPreviewAction(lastAction); const hasNewestReportActionRef = useRef(hasNewestReportAction); hasNewestReportActionRef.current = hasNewestReportAction; + const previousLastIndex = useRef(lastActionIndex); const sortedVisibleReportActionsRef = useRef(sortedVisibleReportActions); const {isFloatingMessageCounterVisible, setIsFloatingMessageCounterVisible, trackVerticalScrolling, onViewableItemsChanged} = useReportUnreadMessageScrollTracking({ @@ -366,6 +370,20 @@ function ReportActionsList({ hasOnceLoadedReportActions: !!reportMetadata?.hasOnceLoadedReportActions, }); + useEffect(() => { + if ( + scrollOffsetRef.current < AUTOSCROLL_TO_TOP_THRESHOLD && + previousLastIndex.current !== lastActionIndex && + reportActionSize.current !== sortedVisibleReportActions.length && + hasNewestReportAction + ) { + setIsFloatingMessageCounterVisible(false); + reportScrollManager.scrollToBottom(); + } + previousLastIndex.current = lastActionIndex; + reportActionSize.current = sortedVisibleReportActions.length; + }, [lastActionIndex, sortedVisibleReportActions.length, reportScrollManager, hasNewestReportAction, linkedReportActionID, setIsFloatingMessageCounterVisible, scrollOffsetRef]); + useEffect(() => { const shouldTriggerScroll = shouldFocusToTopOnMount && prevHasCreatedActionAdded && !hasCreatedActionAdded; if (!shouldTriggerScroll) { @@ -526,13 +544,9 @@ function ReportActionsList({ if (action?.reportActionID) { setActionIdToHighlight(action.reportActionID); } - } else if (Navigation.getReportRHPActiveRoute()) { + } else { setIsFloatingMessageCounterVisible(false); reportScrollManager.scrollToBottom(); - } else { - Navigation.setNavigationActionToMicrotaskQueue(() => { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.reportID)); - }); } setIsScrollToBottomEnabled(true); diff --git a/src/pages/inbox/report/ReportActionsView.tsx b/src/pages/inbox/report/ReportActionsView.tsx index da9bb5d5f1f..8202baf851d 100755 --- a/src/pages/inbox/report/ReportActionsView.tsx +++ b/src/pages/inbox/report/ReportActionsView.tsx @@ -265,6 +265,7 @@ function ReportActionsView({ const {loadOlderChats, loadNewerChats} = useLoadReportActions({ reportID, + reportActionID, reportActions, allReportActionIDs, transactionThreadReport, diff --git a/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts b/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts index 6ef204b0acd..cef1d5e70e6 100644 --- a/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts +++ b/src/styles/utils/chatContentScrollViewPlatformStyles/index.ts @@ -1,7 +1,7 @@ import type ChatContentScrollViewPlatformStyles from './types'; const chatContentScrollViewPlatformStyles: ChatContentScrollViewPlatformStyles = { - overflow: 'clip', + overflow: 'hidden', }; export default chatContentScrollViewPlatformStyles; diff --git a/tests/ui/PaginationTest.tsx b/tests/ui/PaginationTest.tsx index 07474755fdc..d2bebf6fca7 100644 --- a/tests/ui/PaginationTest.tsx +++ b/tests/ui/PaginationTest.tsx @@ -376,9 +376,6 @@ describe('Pagination', () => { // Here we have 5 messages from the initial OpenReport and 5 from the initial GetNewerActions. expect(getReportActions()).toHaveLength(10); - // Simulate the backend returning no new messages to simulate reaching the start of the chat. - mockGetNewerActions(0); - // There is 1 extra call here because of the comment linking report. TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalledWith('OpenReport', 1, {reportID: REPORT_ID, reportActionID: '5'}); @@ -393,20 +390,22 @@ describe('Pagination', () => { TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0); - TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 2); + TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1); // We now have 10 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call. expect(getReportActions()).toHaveLength(10); + // Simulate the backend returning no new messages to simulate reaching the start of the chat. + mockGetNewerActions(0); + scrollToOffset(500); await waitForBatchedUpdatesWithAct(); scrollToOffset(0); await waitForBatchedUpdatesWithAct(); - // When there are no newer actions, we don't want to trigger GetNewerActions again. TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3); TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0); - TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 2); + TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1); // We still have 15 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call. expect(getReportActions()).toHaveLength(10); diff --git a/tests/unit/useLoadReportActionsTest.tsx b/tests/unit/useLoadReportActionsTest.tsx index 871d57c808a..2f743e78d0c 100644 --- a/tests/unit/useLoadReportActionsTest.tsx +++ b/tests/unit/useLoadReportActionsTest.tsx @@ -124,6 +124,7 @@ describe('useLoadReportActions', () => { const props = { ...baseProps, hasNewerActions: true, + reportActionID: 'EXISTING_ACTION_ID', }; const {result} = renderHook(() => useLoadReportActions(props));