From 601bec3bed96868a14b7e4394bc08c6e6cd31c38 Mon Sep 17 00:00:00 2001
From: Vit Horacek <vit@expensify.com>
Date: Thu, 13 Mar 2025 22:09:07 +0100
Subject: [PATCH] Revert "Merge pull request #57610 from
 callstack-internal/loading-state-perception-improvement"

This reverts commit 52666fba347cb148119c10ebc9d2b38161674863, reversing
changes made to c25a843cef4067bb3b697937affbaabf8ff22881.
---
 src/CONST.ts                                  |  2 -
 src/components/LoadingBar.tsx                 | 85 +++++++++++--------
 src/components/MoneyReportHeader.tsx          |  3 +
 src/components/MoneyRequestHeader.tsx         |  3 +
 .../SkeletonViewLines.tsx                     |  1 -
 .../DebugReportActionCreatePage.tsx           |  9 +-
 .../ReportAction/DebugReportActionPreview.tsx |  1 +
 .../DuplicateTransactionItem.tsx              |  8 +-
 src/pages/home/HeaderView.tsx                 |  3 +
 src/pages/home/ReportScreen.tsx               |  2 +-
 .../home/report/PureReportActionItem.tsx      |  5 ++
 .../report/ReportActionItemParentAction.tsx   |  5 ++
 src/pages/home/report/ReportActionsList.tsx   |  3 +-
 .../report/ReportActionsListItemRenderer.tsx  |  6 ++
 src/pages/home/report/ReportActionsView.tsx   | 16 ++--
 src/styles/index.ts                           | 10 +++
 tests/ui/PaginationTest.tsx                   |  8 +-
 17 files changed, 107 insertions(+), 63 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index a8d2fffd661f..b73bc7c33846 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -1494,8 +1494,6 @@ const CONST = {
         WARM: 'warm',
         REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME: 1500,
         SHOW_LOADING_SPINNER_DEBOUNCE_TIME: 250,
-        SKELETON_FADE_DURATION: 300,
-        SKELETON_SLIDE_DURATION: 1200,
         TEST_TOOLS_MODAL_THROTTLE_TIME: 800,
         TOOLTIP_SENSE: 1000,
         TRIE_INITIALIZATION: 'trie_initialization',
diff --git a/src/components/LoadingBar.tsx b/src/components/LoadingBar.tsx
index e13702517e10..e6d1ec0cd66d 100644
--- a/src/components/LoadingBar.tsx
+++ b/src/components/LoadingBar.tsx
@@ -1,68 +1,83 @@
 import React, {useEffect} from 'react';
-import {View} from 'react-native';
-import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
+import Animated, {cancelAnimation, Easing, useAnimatedStyle, useSharedValue, withDelay, withRepeat, withSequence, withTiming} from 'react-native-reanimated';
 import useThemeStyles from '@hooks/useThemeStyles';
-import colors from '@styles/theme/colors';
 import CONST from '@src/CONST';
 
 type LoadingBarProps = {
-    // Whether to show the loading bar
+    // Whether or not to show the loading bar
     shouldShow: boolean;
 };
 
 function LoadingBar({shouldShow}: LoadingBarProps) {
-    const left = useSharedValue(-30);
+    const left = useSharedValue(0);
+    const width = useSharedValue(0);
     const opacity = useSharedValue(0);
-    const isAnimating = useSharedValue(false);
     const styles = useThemeStyles();
 
     useEffect(() => {
-        if (shouldShow && !isAnimating.get()) {
-            isAnimating.set(true);
-            opacity.set(withTiming(1, {duration: CONST.TIMING.SKELETON_FADE_DURATION}));
+        if (shouldShow) {
+            // eslint-disable-next-line react-compiler/react-compiler
+            left.set(0);
+            width.set(0);
+            opacity.set(withTiming(1, {duration: CONST.ANIMATED_PROGRESS_BAR_OPACITY_DURATION}));
 
             left.set(
-                withTiming(100, {duration: CONST.TIMING.SKELETON_SLIDE_DURATION}, () => {
-                    requestAnimationFrame(() => {
-                        if (shouldShow) {
-                            left.set(-30);
-                            left.set(withTiming(100, {duration: CONST.TIMING.SKELETON_SLIDE_DURATION}));
-                        } else {
-                            opacity.set(
-                                withTiming(0, {duration: CONST.TIMING.SKELETON_FADE_DURATION}, () => {
-                                    isAnimating.set(false);
-                                }),
-                            );
-                        }
-                    });
-                }),
+                withDelay(
+                    CONST.ANIMATED_PROGRESS_BAR_DELAY,
+                    withRepeat(
+                        withSequence(
+                            withTiming(0, {duration: 0}),
+                            withTiming(0, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
+                            withTiming(100, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
+                        ),
+                        -1,
+                        false,
+                    ),
+                ),
+            );
+
+            width.set(
+                withDelay(
+                    CONST.ANIMATED_PROGRESS_BAR_DELAY,
+                    withRepeat(
+                        withSequence(
+                            withTiming(0, {duration: 0}),
+                            withTiming(100, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
+                            withTiming(0, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
+                        ),
+                        -1,
+                        false,
+                    ),
+                ),
             );
-        } else if (!shouldShow) {
+        } else {
             opacity.set(
-                withTiming(0, {duration: CONST.TIMING.SKELETON_FADE_DURATION}, () => {
-                    isAnimating.set(false);
+                withTiming(0, {duration: CONST.ANIMATED_PROGRESS_BAR_OPACITY_DURATION}, () => {
+                    cancelAnimation(left);
+                    cancelAnimation(width);
                 }),
             );
         }
+        // we want to update only when shouldShow changes
         // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
     }, [shouldShow]);
 
-    const barStyle = useAnimatedStyle(() => ({
+    const animatedIndicatorStyle = useAnimatedStyle(() => ({
         left: `${left.get()}%`,
-        width: '30%',
-        height: '100%',
-        backgroundColor: colors.green,
+        width: `${width.get()}%`,
+    }));
+
+    const animatedContainerStyle = useAnimatedStyle(() => ({
         opacity: opacity.get(),
-        borderRadius: 2,
     }));
 
     return (
-        <View style={[styles.progressBarWrapper]}>
-            <Animated.View style={barStyle} />
-        </View>
+        <Animated.View style={[styles.progressBarWrapper, animatedContainerStyle]}>
+            <Animated.View style={[styles.progressBar, animatedIndicatorStyle]} />
+        </Animated.View>
     );
 }
 
-LoadingBar.displayName = 'LoadingBar';
+LoadingBar.displayName = 'ProgressBar';
 
 export default LoadingBar;
diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx
index 06d679d98207..a085385589a3 100644
--- a/src/components/MoneyReportHeader.tsx
+++ b/src/components/MoneyReportHeader.tsx
@@ -77,6 +77,7 @@ import DelegateNoAccessModal from './DelegateNoAccessModal';
 import HeaderWithBackButton from './HeaderWithBackButton';
 import Icon from './Icon';
 import * as Expensicons from './Icon/Expensicons';
+import LoadingBar from './LoadingBar';
 import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
 import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar';
 import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
@@ -234,6 +235,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
     const isMoreContentShown = shouldShowNextStep || shouldShowStatusBar || (shouldShowAnyButton && shouldUseNarrowLayout);
     const {isDelegateAccessRestricted} = useDelegateUserDetails();
     const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
+    const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);
 
     const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP;
     const shouldDisplaySearchRouter = !isReportInRHP || isSmallScreenWidth;
@@ -528,6 +530,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
                     )}
                 </View>
             )}
+            <LoadingBar shouldShow={(isLoadingReportData && shouldUseNarrowLayout) ?? false} />
             {isHoldMenuVisible && requestType !== undefined && (
                 <ProcessMoneyReportHoldMenu
                     nonHeldAmount={!hasOnlyHeldExpenses && hasValidNonHeldAmount ? nonHeldAmount : undefined}
diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx
index 3fd7dd74f43c..6d7ca116a782 100644
--- a/src/components/MoneyRequestHeader.tsx
+++ b/src/components/MoneyRequestHeader.tsx
@@ -36,6 +36,7 @@ import Button from './Button';
 import HeaderWithBackButton from './HeaderWithBackButton';
 import Icon from './Icon';
 import * as Expensicons from './Icon/Expensicons';
+import LoadingBar from './LoadingBar';
 import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar';
 import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
 
@@ -67,6 +68,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
     const transactionViolations = useTransactionViolations(transaction?.transactionID);
 
     const [dismissedHoldUseExplanation, dismissedHoldUseExplanationResult] = useOnyx(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, {initialValue: true});
+    const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);
     const isLoadingHoldUseExplained = isLoadingOnyxValue(dismissedHoldUseExplanationResult);
     const styles = useThemeStyles();
     const theme = useTheme();
@@ -212,6 +214,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
                     />
                 </View>
             )}
+            <LoadingBar shouldShow={(isLoadingReportData && shouldUseNarrowLayout) ?? false} />
         </View>
     );
 }
diff --git a/src/components/ReportActionsSkeletonView/SkeletonViewLines.tsx b/src/components/ReportActionsSkeletonView/SkeletonViewLines.tsx
index d3ea26ab5880..c4c2a3f43eb3 100644
--- a/src/components/ReportActionsSkeletonView/SkeletonViewLines.tsx
+++ b/src/components/ReportActionsSkeletonView/SkeletonViewLines.tsx
@@ -20,7 +20,6 @@ function SkeletonViewLines({numberOfRows, shouldAnimate = true}: SkeletonViewLin
             height={CONST.CHAT_SKELETON_VIEW.HEIGHT_FOR_ROW_COUNT[numberOfRows]}
             backgroundColor={theme.skeletonLHNIn}
             foregroundColor={theme.skeletonLHNOut}
-            speed={3}
             style={styles.mr5}
         >
             <Circle
diff --git a/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx b/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx
index 2331d84b1a16..1162146b8f4d 100644
--- a/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx
+++ b/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx
@@ -12,11 +12,11 @@ import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
 import DateUtils from '@libs/DateUtils';
 import DebugUtils from '@libs/DebugUtils';
-import {canUseTouchScreen} from '@libs/DeviceCapabilities';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
 import Navigation from '@libs/Navigation/Navigation';
 import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
 import type {DebugParamList} from '@libs/Navigation/types';
-import {rand64} from '@libs/NumberUtils';
+import * as NumberUtils from '@libs/NumberUtils';
 import ReportActionItem from '@pages/home/report/ReportActionItem';
 import Debug from '@userActions/Debug';
 import CONST from '@src/CONST';
@@ -32,7 +32,7 @@ const getInitialReportAction = (reportID: string, session: OnyxEntry<Session>, p
     DebugUtils.stringifyJSON({
         actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
         reportID,
-        reportActionID: rand64(),
+        reportActionID: NumberUtils.rand64(),
         created: DateUtils.getDBTime(),
         actorAccountID: session?.accountID,
         avatar: (session?.accountID && personalDetailsList?.[session.accountID]?.avatar) ?? '',
@@ -78,7 +78,7 @@ function DebugReportActionCreatePage({
         <ScreenWrapper
             includeSafeAreaPaddingBottom={false}
             shouldEnableKeyboardAvoidingView={false}
-            shouldEnableMinHeight={canUseTouchScreen()}
+            shouldEnableMinHeight={DeviceCapabilities.canUseTouchScreen()}
             testID={DebugReportActionCreatePage.displayName}
         >
             {({safeAreaPaddingBottomStyle}) => (
@@ -107,6 +107,7 @@ function DebugReportActionCreatePage({
                                 <ReportActionItem
                                     action={JSON.parse(draftReportAction.replaceAll('\n', '')) as ReportAction}
                                     report={{reportID}}
+                                    reportActions={[]}
                                     parentReportAction={undefined}
                                     displayAsGroup={false}
                                     isMostRecentIOUReportAction={false}
diff --git a/src/pages/Debug/ReportAction/DebugReportActionPreview.tsx b/src/pages/Debug/ReportAction/DebugReportActionPreview.tsx
index 5b58a74bf3af..53f37c8e4d69 100644
--- a/src/pages/Debug/ReportAction/DebugReportActionPreview.tsx
+++ b/src/pages/Debug/ReportAction/DebugReportActionPreview.tsx
@@ -22,6 +22,7 @@ function DebugReportActionPreview({reportAction, reportID}: DebugReportActionPre
             <ReportActionItem
                 action={reportAction ?? ({} as ReportAction)}
                 report={report ?? ({} as Report)}
+                reportActions={[]}
                 parentReportAction={undefined}
                 displayAsGroup={false}
                 isMostRecentIOUReportAction={false}
diff --git a/src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx b/src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx
index ec180136a979..398ea8ae336b 100644
--- a/src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx
+++ b/src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx
@@ -3,9 +3,8 @@ import {View} from 'react-native';
 import type {OnyxEntry} from 'react-native-onyx';
 import {useOnyx} from 'react-native-onyx';
 import useThemeStyles from '@hooks/useThemeStyles';
-import {getOriginalMessage, getReportAction, isMoneyRequestAction} from '@libs/ReportActionsUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
 import ReportActionItem from '@pages/home/report/ReportActionItem';
-import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {Transaction} from '@src/types/onyx';
 
@@ -21,7 +20,7 @@ function DuplicateTransactionItem(props: DuplicateTransactionItemProps) {
 
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/non-nullable-type-assertion-style
     const action = Object.values(reportActions ?? {})?.find((reportAction) => {
-        const IOUTransactionID = isMoneyRequestAction(reportAction) ? getOriginalMessage(reportAction)?.IOUTransactionID : CONST.DEFAULT_NUMBER_ID;
+        const IOUTransactionID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID : -1;
         return IOUTransactionID === props.transaction?.transactionID;
     });
 
@@ -34,8 +33,9 @@ function DuplicateTransactionItem(props: DuplicateTransactionItemProps) {
             <ReportActionItem
                 action={action}
                 report={report}
-                parentReportAction={getReportAction(report?.parentReportID, report?.parentReportActionID)}
+                parentReportAction={ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? '')}
                 index={props.index}
+                reportActions={Object.values(reportActions ?? {})}
                 displayAsGroup={false}
                 shouldDisplayNewMarker={false}
                 isMostRecentIOUReportAction={false}
diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx
index 60412186ad1b..faf0aeb2e963 100644
--- a/src/pages/home/HeaderView.tsx
+++ b/src/pages/home/HeaderView.tsx
@@ -9,6 +9,7 @@ import ConfirmModal from '@components/ConfirmModal';
 import DisplayNames from '@components/DisplayNames';
 import Icon from '@components/Icon';
 import {BackArrow, CalendarSolid, DotIndicator, FallbackAvatar} from '@components/Icon/Expensicons';
+import LoadingBar from '@components/LoadingBar';
 import MultipleAvatars from '@components/MultipleAvatars';
 import OfflineWithFeedback from '@components/OfflineWithFeedback';
 import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle';
@@ -106,6 +107,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
     const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(report?.parentReportID) ?? getNonEmptyStringOnyxID(report?.reportID)}`);
     const policy = usePolicy(report?.policyID);
     const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
+    const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);
     const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL);
     const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL);
     const [account] = useOnyx(ONYXKEYS.ACCOUNT);
@@ -392,6 +394,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
                         </View>
                     </View>
                 )}
+                <LoadingBar shouldShow={(isLoadingReportData && shouldUseNarrowLayout) ?? false} />
             </View>
             {shouldShowEarlyDiscountBanner && (
                 <EarlyDiscountBanner
diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx
index 99906a5551d8..f29a4d85fc56 100644
--- a/src/pages/home/ReportScreen.tsx
+++ b/src/pages/home/ReportScreen.tsx
@@ -731,7 +731,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
                                     <ReportActionsView
                                         report={report}
                                         reportActions={reportActions}
-                                        reportMetadata={reportMetadata}
+                                        isLoadingInitialReportActions={reportMetadata?.isLoadingInitialReportActions}
                                         hasNewerActions={hasNewerActions}
                                         hasOlderActions={hasOlderActions}
                                         parentReportAction={parentReportAction}
diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx
index 84b02db60203..5513d3404d3f 100644
--- a/src/pages/home/report/PureReportActionItem.tsx
+++ b/src/pages/home/report/PureReportActionItem.tsx
@@ -164,6 +164,10 @@ type PureReportActionItemProps = {
     /** The transaction thread report associated with the report for this action, if any */
     transactionThreadReport?: OnyxEntry<OnyxTypes.Report>;
 
+    /** Array of report actions for the report for this action */
+    // eslint-disable-next-line react/no-unused-prop-types
+    reportActions: OnyxTypes.ReportAction[];
+
     /** Report action belonging to the report's parent */
     parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;
 
@@ -1298,6 +1302,7 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => {
         prevProps.linkedReportActionID === nextProps.linkedReportActionID &&
         lodashIsEqual(prevProps.report?.fieldList, nextProps.report?.fieldList) &&
         lodashIsEqual(prevProps.transactionThreadReport, nextProps.transactionThreadReport) &&
+        lodashIsEqual(prevProps.reportActions, nextProps.reportActions) &&
         lodashIsEqual(prevParentReportAction, nextParentReportAction) &&
         prevProps.draftMessage === nextProps.draftMessage &&
         prevProps.iouReport?.reportID === nextProps.iouReport?.reportID &&
diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx
index 5d3284d7bee8..b7134fd7059e 100644
--- a/src/pages/home/report/ReportActionItemParentAction.tsx
+++ b/src/pages/home/report/ReportActionItemParentAction.tsx
@@ -36,6 +36,9 @@ type ReportActionItemParentActionProps = {
     /** The transaction thread report associated with the current report, if any */
     transactionThreadReport: OnyxEntry<OnyxTypes.Report>;
 
+    /** Array of report actions for this report */
+    reportActions: OnyxTypes.ReportAction[];
+
     /** Report actions belonging to the report's parent */
     parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;
 
@@ -52,6 +55,7 @@ type ReportActionItemParentActionProps = {
 function ReportActionItemParentAction({
     report,
     transactionThreadReport,
+    reportActions,
     parentReportAction,
     index = 0,
     shouldHideThreadDividerLine = false,
@@ -140,6 +144,7 @@ function ReportActionItemParentAction({
                             }
                             parentReportAction={parentReportAction}
                             report={ancestor.report}
+                            reportActions={reportActions}
                             transactionThreadReport={transactionThreadReport}
                             action={ancestor.reportAction}
                             displayAsGroup={false}
diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx
index 511748f9194b..5c140589e4f3 100644
--- a/src/pages/home/report/ReportActionsList.tsx
+++ b/src/pages/home/report/ReportActionsList.tsx
@@ -221,7 +221,6 @@ function ReportActionsList({
     }, [report.reportID]);
 
     const prevUnreadMarkerReportActionID = useRef<string | null>(null);
-
     /**
      * Whether a message is NOT from the active user and it was received while the user was offline.
      */
@@ -622,6 +621,7 @@ function ReportActionsList({
         ({item: reportAction, index}: ListRenderItemInfo<OnyxTypes.ReportAction>) => (
             <ReportActionsListItemRenderer
                 reportAction={reportAction}
+                reportActions={sortedReportActions}
                 parentReportAction={parentReportAction}
                 parentReportActionForTransactionThread={parentReportActionForTransactionThread}
                 index={index}
@@ -647,6 +647,7 @@ function ReportActionsList({
             mostRecentIOUReportActionID,
             shouldHideThreadDividerLine,
             parentReportAction,
+            sortedReportActions,
             transactionThreadReport,
             parentReportActionForTransactionThread,
             shouldUseThreadDividerLine,
diff --git a/src/pages/home/report/ReportActionsListItemRenderer.tsx b/src/pages/home/report/ReportActionsListItemRenderer.tsx
index b9cc7406b890..1a0d8db13661 100644
--- a/src/pages/home/report/ReportActionsListItemRenderer.tsx
+++ b/src/pages/home/report/ReportActionsListItemRenderer.tsx
@@ -11,6 +11,9 @@ type ReportActionsListItemRendererProps = {
     /** All the data of the action item */
     reportAction: ReportAction;
 
+    /** Array of report actions for the report */
+    reportActions: ReportAction[];
+
     /** The report's parentReportAction */
     parentReportAction: OnyxEntry<ReportAction>;
 
@@ -53,6 +56,7 @@ type ReportActionsListItemRendererProps = {
 
 function ReportActionsListItemRenderer({
     reportAction,
+    reportActions = [],
     parentReportAction,
     index,
     report,
@@ -148,6 +152,7 @@ function ReportActionsListItemRenderer({
                 parentReportAction={parentReportAction}
                 reportID={report.reportID}
                 report={report}
+                reportActions={reportActions}
                 transactionThreadReport={transactionThreadReport}
                 index={index}
                 isFirstVisibleReportAction={isFirstVisibleReportAction}
@@ -164,6 +169,7 @@ function ReportActionsListItemRenderer({
             transactionThreadReport={transactionThreadReport}
             parentReportActionForTransactionThread={parentReportActionForTransactionThread}
             action={action}
+            reportActions={reportActions}
             linkedReportActionID={linkedReportActionID}
             displayAsGroup={displayAsGroup}
             shouldDisplayNewMarker={shouldDisplayNewMarker}
diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx
index 6bd98e47f8aa..88b4cae332ed 100755
--- a/src/pages/home/report/ReportActionsView.tsx
+++ b/src/pages/home/report/ReportActionsView.tsx
@@ -5,7 +5,6 @@ import type {OnyxEntry} from 'react-native-onyx';
 import {useOnyx} from 'react-native-onyx';
 import EmptyStateComponent from '@components/EmptyStateComponent';
 import * as Illustrations from '@components/Icon/Illustrations';
-import LoadingBar from '@components/LoadingBar';
 import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView';
 import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton';
 import useCopySelectionHelper from '@hooks/useCopySelectionHelper';
@@ -54,8 +53,8 @@ type ReportActionsViewProps = {
     /** The report's parentReportAction */
     parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;
 
-    /** The report's metadata */
-    reportMetadata: OnyxTypes.ReportMetadata;
+    /** The report metadata loading states */
+    isLoadingInitialReportActions?: boolean;
 
     /** The reportID of the transaction thread report associated with this current report, if any */
     // eslint-disable-next-line react/no-unused-prop-types
@@ -74,7 +73,7 @@ function ReportActionsView({
     report,
     parentReportAction,
     reportActions: allReportActions,
-    reportMetadata,
+    isLoadingInitialReportActions,
     transactionThreadReportID,
     hasNewerActions,
     hasOlderActions,
@@ -104,8 +103,6 @@ function ReportActionsView({
     const reportID = report.reportID;
     const isReportFullyVisible = useMemo((): boolean => getIsReportFullyVisible(isFocused), [isFocused]);
 
-    const {isLoadingInitialReportActions, isLoadingOlderReportActions, isLoadingNewerReportActions, hasLoadingNewerReportActionsError} = reportMetadata;
-
     useEffect(() => {
         // When we linked to message - we do not need to wait for initial actions - they already exists
         if (!reportActionID || !isOffline) {
@@ -214,8 +211,6 @@ function ReportActionsView({
         [reportActions, isOffline, canPerformWriteAction],
     );
 
-    const showLoadingBar = !!isLoadingOlderReportActions || !!isLoadingNewerReportActions || !!(visibleReportActions.length > 0 && isLoadingInitialReportActions);
-
     const reportActionIDMap = useMemo(() => {
         const reportActionIDs = allReportActions?.map((action) => action.reportActionID);
         return reportActions.map((action) => ({
@@ -287,7 +282,7 @@ function ReportActionsView({
                     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 && hasLoadingNewerReportActionsError) ||
+                    didLoadNewerChats.current ||
                     newestReportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)
             ) {
                 return;
@@ -308,7 +303,7 @@ function ReportActionsView({
                 getNewerActions(reportID, newestReportAction.reportActionID);
             }
         },
-        [reportActionID, isFocused, newestReportAction, hasNewerActions, isOffline, hasLoadingNewerReportActionsError, transactionThreadReport, reportActionIDMap, reportID],
+        [reportActionID, isFocused, newestReportAction, hasNewerActions, isOffline, transactionThreadReport, reportActionIDMap, reportID],
     );
 
     /**
@@ -377,7 +372,6 @@ function ReportActionsView({
     const shouldEnableAutoScroll = (hasNewestReportAction && (!reportActionID || !isNavigatingToLinkedMessage)) || (transactionThreadReport && !prevTransactionThreadReport);
     return (
         <>
-            <LoadingBar shouldShow={showLoadingBar} />
             <ReportActionsList
                 report={report}
                 transactionThreadReport={transactionThreadReport}
diff --git a/src/styles/index.ts b/src/styles/index.ts
index ebd80fb6d00d..c95b126d1278 100644
--- a/src/styles/index.ts
+++ b/src/styles/index.ts
@@ -5436,7 +5436,17 @@ const styles = (theme: ThemeColors) =>
 
         progressBarWrapper: {
             height: 2,
+            width: '100%',
+            backgroundColor: theme.transparent,
             overflow: 'hidden',
+            position: 'absolute',
+            bottom: -1,
+        },
+
+        progressBar: {
+            height: '100%',
+            backgroundColor: theme.success,
+            width: '100%',
         },
 
         accountSwitcherAnchorPosition: {
diff --git a/tests/ui/PaginationTest.tsx b/tests/ui/PaginationTest.tsx
index e08a4d50f51f..73df63153b1d 100644
--- a/tests/ui/PaginationTest.tsx
+++ b/tests/ui/PaginationTest.tsx
@@ -359,10 +359,10 @@ 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(15);
+        expect(getReportActions()).toHaveLength(10);
 
         // Simulate the backend returning no new messages to simulate reaching the start of the chat.
         mockGetNewerActions(0);
@@ -374,9 +374,9 @@ describe('Pagination', () => {
 
         TestHelper.expectAPICommandToHaveBeenCalled('OpenReport', 3);
         TestHelper.expectAPICommandToHaveBeenCalled('GetOlderActions', 0);
-        TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 3);
+        TestHelper.expectAPICommandToHaveBeenCalled('GetNewerActions', 1);
 
         // We still have 15 messages. 5 from the initial OpenReport and 5 from the GetNewerActions call.
-        expect(getReportActions()).toHaveLength(15);
+        expect(getReportActions()).toHaveLength(10);
     });
 });
