From 2a9c4e78e33a1b0cac64cb7589c71abd79f08e7a Mon Sep 17 00:00:00 2001
From: daledah <daleda261@outlook.com>
Date: Thu, 9 Jan 2025 16:45:08 +0700
Subject: [PATCH 1/4] fix: highlight parent conversation when go back in
 offline

---
 src/components/ParentNavigationSubtitle.tsx            | 4 +---
 src/libs/PaginationUtils.ts                            | 3 ++-
 src/pages/home/report/ReportActionItemParentAction.tsx | 4 +---
 src/pages/home/report/ThreadDivider.tsx                | 4 +---
 4 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx
index 1896bc4f5f07..e59eae2b2f28 100644
--- a/src/components/ParentNavigationSubtitle.tsx
+++ b/src/components/ParentNavigationSubtitle.tsx
@@ -2,7 +2,6 @@ import React from 'react';
 import type {StyleProp, ViewStyle} from 'react-native';
 import {useOnyx} from 'react-native-onyx';
 import useLocalize from '@hooks/useLocalize';
-import useNetwork from '@hooks/useNetwork';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
 import * as ReportActionsUtils from '@libs/ReportActionsUtils';
@@ -30,7 +29,6 @@ type ParentNavigationSubtitleProps = {
 function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportActionID, parentReportID = '', pressableStyles}: ParentNavigationSubtitleProps) {
     const styles = useThemeStyles();
     const {workspaceName, reportName} = parentNavigationSubtitleData;
-    const {isOffline} = useNetwork();
     const {translate} = useLocalize();
     const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`);
     const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report);
@@ -47,7 +45,7 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct
                 const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? '-1', canUserPerformWriteAction);
                 // Pop the thread report screen before navigating to the chat report.
                 Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID));
-                if (isVisibleAction && !isOffline) {
+                if (isVisibleAction) {
                     // Pop the chat report screen before navigating to the linked report action.
                     Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID), true);
                 }
diff --git a/src/libs/PaginationUtils.ts b/src/libs/PaginationUtils.ts
index 1cb3e7295c27..59302abd2d43 100644
--- a/src/libs/PaginationUtils.ts
+++ b/src/libs/PaginationUtils.ts
@@ -173,7 +173,8 @@ function getContinuousChain<TResource>(
     id?: string,
 ): {data: TResource[]; hasNextPage: boolean; hasPreviousPage: boolean} {
     if (pages.length === 0) {
-        return {data: id ? [] : sortedItems, hasNextPage: false, hasPreviousPage: false};
+        const dataItem = sortedItems.find((item) => getID(item) === id);
+        return {data: id && !dataItem ? [] : sortedItems, hasNextPage: false, hasPreviousPage: false};
     }
 
     const pagesWithIndexes = getPagesWithIndexes(sortedItems, pages, getID);
diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx
index 5976ac5de725..12963df38c46 100644
--- a/src/pages/home/report/ReportActionItemParentAction.tsx
+++ b/src/pages/home/report/ReportActionItemParentAction.tsx
@@ -4,7 +4,6 @@ import type {OnyxEntry} from 'react-native-onyx';
 import {useOnyx} from 'react-native-onyx';
 import OfflineWithFeedback from '@components/OfflineWithFeedback';
 import TripDetailsView from '@components/ReportActionItem/TripDetailsView';
-import useNetwork from '@hooks/useNetwork';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
 import onyxSubscribe from '@libs/onyxSubscribe';
@@ -68,7 +67,6 @@ function ReportActionItemParentAction({
     const ancestorIDs = useRef(ReportUtils.getAllAncestorReportActionIDs(report));
     const ancestorReports = useRef<Record<string, OnyxEntry<OnyxTypes.Report>>>({});
     const [allAncestors, setAllAncestors] = useState<ReportUtils.Ancestor[]>([]);
-    const {isOffline} = useNetwork();
 
     useEffect(() => {
         const unsubscribeReports: Array<() => void> = [];
@@ -143,7 +141,7 @@ function ReportActionItemParentAction({
                                               );
                                               // Pop the thread report screen before navigating to the chat report.
                                               Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1'));
-                                              if (isVisibleAction && !isOffline) {
+                                              if (isVisibleAction) {
                                                   // Pop the chat report screen before navigating to the linked report action.
                                                   Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1', ancestor.reportAction.reportActionID));
                                               }
diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx
index 0cf34d6f40e6..bb7679c18870 100644
--- a/src/pages/home/report/ThreadDivider.tsx
+++ b/src/pages/home/report/ThreadDivider.tsx
@@ -5,7 +5,6 @@ import * as Expensicons from '@components/Icon/Expensicons';
 import {PressableWithoutFeedback} from '@components/Pressable';
 import Text from '@components/Text';
 import useLocalize from '@hooks/useLocalize';
-import useNetwork from '@hooks/useNetwork';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
@@ -28,7 +27,6 @@ function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) {
     const styles = useThemeStyles();
     const theme = useTheme();
     const {translate} = useLocalize();
-    const {isOffline} = useNetwork();
 
     return (
         <View
@@ -55,7 +53,7 @@ function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) {
                         );
                         // Pop the thread report screen before navigating to the chat report.
                         Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1'));
-                        if (isVisibleAction && !isOffline) {
+                        if (isVisibleAction) {
                             // Pop the chat report screen before navigating to the linked report action.
                             Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1', ancestor.reportAction.reportActionID));
                         }

From 9dbc9fd0c52709b3e6c355501a05e1642d8589ea Mon Sep 17 00:00:00 2001
From: daledah <daleda261@outlook.com>
Date: Fri, 10 Jan 2025 12:04:35 +0700
Subject: [PATCH 2/4] fix lint

---
 src/components/ParentNavigationSubtitle.tsx         |  4 ++--
 .../home/report/ReportActionItemParentAction.tsx    | 13 +++++++------
 src/pages/home/report/ThreadDivider.tsx             |  6 +++---
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx
index e59eae2b2f28..424c24545708 100644
--- a/src/components/ParentNavigationSubtitle.tsx
+++ b/src/components/ParentNavigationSubtitle.tsx
@@ -41,8 +41,8 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct
     return (
         <PressableWithoutFeedback
             onPress={() => {
-                const parentAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? '-1');
-                const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? '-1', canUserPerformWriteAction);
+                const parentAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID);
+                const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? CONST.DEFAULT_NUMBER_ID, canUserPerformWriteAction);
                 // Pop the thread report screen before navigating to the chat report.
                 Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID));
                 if (isVisibleAction) {
diff --git a/src/pages/home/report/ReportActionItemParentAction.tsx b/src/pages/home/report/ReportActionItemParentAction.tsx
index 12963df38c46..7760c6a2e16f 100644
--- a/src/pages/home/report/ReportActionItemParentAction.tsx
+++ b/src/pages/home/report/ReportActionItemParentAction.tsx
@@ -10,6 +10,7 @@ import onyxSubscribe from '@libs/onyxSubscribe';
 import * as ReportActionsUtils from '@libs/ReportActionsUtils';
 import * as ReportUtils from '@libs/ReportUtils';
 import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type * as OnyxTypes from '@src/types/onyx';
@@ -120,30 +121,30 @@ function ReportActionItemParentAction({
                     >
                         <ThreadDivider
                             ancestor={ancestor}
-                            isLinkDisabled={!ReportUtils.canCurrentUserOpenReport(ancestorReports.current?.[ancestor?.report?.reportID ?? '-1'])}
+                            isLinkDisabled={!ReportUtils.canCurrentUserOpenReport(ancestorReports.current?.[ancestor?.report?.reportID])}
                         />
                         {ReportActionsUtils.isTripPreview(ancestor?.reportAction) ? (
                             <OfflineWithFeedback pendingAction={ancestor.reportAction.pendingAction}>
                                 <TripDetailsView
-                                    tripRoomReportID={ReportActionsUtils.getOriginalMessage(ancestor.reportAction)?.linkedReportID ?? '-1'}
+                                    tripRoomReportID={ReportActionsUtils.getOriginalMessage(ancestor.reportAction)?.linkedReportID ?? CONST.EMPTY_STRING}
                                     shouldShowHorizontalRule={false}
                                 />
                             </OfflineWithFeedback>
                         ) : (
                             <ReportActionItem
                                 onPress={
-                                    ReportUtils.canCurrentUserOpenReport(ancestorReports.current?.[ancestor?.report?.reportID ?? '-1'])
+                                    ReportUtils.canCurrentUserOpenReport(ancestorReports.current?.[ancestor?.report?.reportID])
                                         ? () => {
                                               const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(
                                                   ancestor.reportAction,
-                                                  ancestor.reportAction.reportActionID ?? '-1',
+                                                  ancestor.reportAction.reportActionID,
                                                   canUserPerformWriteAction,
                                               );
                                               // Pop the thread report screen before navigating to the chat report.
-                                              Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1'));
+                                              Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID));
                                               if (isVisibleAction) {
                                                   // Pop the chat report screen before navigating to the linked report action.
-                                                  Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1', ancestor.reportAction.reportActionID));
+                                                  Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID, ancestor.reportAction.reportActionID));
                                               }
                                           }
                                         : undefined
diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx
index bb7679c18870..57d2474a7d8b 100644
--- a/src/pages/home/report/ThreadDivider.tsx
+++ b/src/pages/home/report/ThreadDivider.tsx
@@ -48,14 +48,14 @@ function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) {
                     onPress={() => {
                         const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(
                             ancestor.reportAction,
-                            ancestor.reportAction.reportActionID ?? '-1',
+                            ancestor.reportAction.reportActionID,
                             ReportUtils.canUserPerformWriteAction(ancestor.report),
                         );
                         // Pop the thread report screen before navigating to the chat report.
-                        Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1'));
+                        Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID));
                         if (isVisibleAction) {
                             // Pop the chat report screen before navigating to the linked report action.
-                            Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID ?? '-1', ancestor.reportAction.reportActionID));
+                            Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID, ancestor.reportAction.reportActionID));
                         }
                     }}
                     accessibilityLabel={translate('threads.thread')}

From 5bb5550ee03791ca8fdc0cd207a33161e2d81cfa Mon Sep 17 00:00:00 2001
From: daledah <daleda261@outlook.com>
Date: Fri, 10 Jan 2025 12:14:45 +0700
Subject: [PATCH 3/4] fix test

---
 tests/unit/PaginationUtilsTest.ts | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/tests/unit/PaginationUtilsTest.ts b/tests/unit/PaginationUtilsTest.ts
index e5f4ce7675e8..28e754ce5ff7 100644
--- a/tests/unit/PaginationUtilsTest.ts
+++ b/tests/unit/PaginationUtilsTest.ts
@@ -163,7 +163,7 @@ describe('PaginationUtils', () => {
             expect(result.hasNextPage).toBe(false);
         });
 
-        it('given an input ID and the report only contains pending actions, it will return an empty array', () => {
+        it('given an input ID and the report only contains pending actions, it will return all actions', () => {
             const input = createItems([
                 // Given these sortedItems
                 '7',
@@ -178,8 +178,31 @@ describe('PaginationUtils', () => {
             const pages: Pages = [];
 
             // Expect these sortedItems
-            const expectedResult: Item[] = [];
+            const expectedResult = [...input];
             const result = PaginationUtils.getContinuousChain(input, pages, getID, '4');
+            // Expect the result to be the same
+            expect(result.data).toStrictEqual(expectedResult);
+            expect(result.hasPreviousPage).toBe(false);
+            expect(result.hasNextPage).toBe(false);
+        });
+
+        it('given an input ID of 8 which does not exist in Onyx and the report only contains pending actions, it will return an empty array', () => {
+            const input = createItems([
+                // Given these sortedItems
+                '7',
+                '6',
+                '5',
+                '4',
+                '3',
+                '2',
+                '1',
+            ]);
+
+            const pages: Pages = [];
+
+            // Expect these sortedItems
+            const expectedResult: Item[] = [];
+            const result = PaginationUtils.getContinuousChain(input, pages, getID, '8');
             expect(result.data).toStrictEqual(expectedResult);
             expect(result.hasPreviousPage).toBe(false);
             expect(result.hasNextPage).toBe(false);

From 7f4b9a2abb78d0e313017a7ed16716fe772cbe31 Mon Sep 17 00:00:00 2001
From: daledah <daleda261@outlook.com>
Date: Wed, 15 Jan 2025 16:04:25 +0700
Subject: [PATCH 4/4] fix: lint

---
 src/components/ParentNavigationSubtitle.tsx | 10 +++++-----
 src/pages/home/report/ThreadDivider.tsx     | 10 +++-------
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx
index 424c24545708..f9d84fb423bb 100644
--- a/src/components/ParentNavigationSubtitle.tsx
+++ b/src/components/ParentNavigationSubtitle.tsx
@@ -4,8 +4,8 @@ import {useOnyx} from 'react-native-onyx';
 import useLocalize from '@hooks/useLocalize';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
-import * as ReportActionsUtils from '@libs/ReportActionsUtils';
-import * as ReportUtils from '@libs/ReportUtils';
+import {getReportAction, shouldReportActionBeVisible} from '@libs/ReportActionsUtils';
+import {canUserPerformWriteAction as canUserPerformWriteActionReportUtils} from '@libs/ReportUtils';
 import CONST from '@src/CONST';
 import type {ParentNavigationSummaryParams} from '@src/languages/params';
 import ONYXKEYS from '@src/ONYXKEYS';
@@ -31,7 +31,7 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct
     const {workspaceName, reportName} = parentNavigationSubtitleData;
     const {translate} = useLocalize();
     const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`);
-    const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report);
+    const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report);
 
     // We should not display the parent navigation subtitle if the user does not have access to the parent chat (the reportName is empty in this case)
     if (!reportName) {
@@ -41,8 +41,8 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct
     return (
         <PressableWithoutFeedback
             onPress={() => {
-                const parentAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID);
-                const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? CONST.DEFAULT_NUMBER_ID, canUserPerformWriteAction);
+                const parentAction = getReportAction(parentReportID, parentReportActionID);
+                const isVisibleAction = shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? CONST.DEFAULT_NUMBER_ID, canUserPerformWriteAction);
                 // Pop the thread report screen before navigating to the chat report.
                 Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID));
                 if (isVisibleAction) {
diff --git a/src/pages/home/report/ThreadDivider.tsx b/src/pages/home/report/ThreadDivider.tsx
index 57d2474a7d8b..7bb03c42ac82 100644
--- a/src/pages/home/report/ThreadDivider.tsx
+++ b/src/pages/home/report/ThreadDivider.tsx
@@ -8,9 +8,9 @@ import useLocalize from '@hooks/useLocalize';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import Navigation from '@libs/Navigation/Navigation';
-import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import {shouldReportActionBeVisible} from '@libs/ReportActionsUtils';
+import {canUserPerformWriteAction} from '@libs/ReportUtils';
 import type {Ancestor} from '@libs/ReportUtils';
-import * as ReportUtils from '@libs/ReportUtils';
 import variables from '@styles/variables';
 import CONST from '@src/CONST';
 import ROUTES from '@src/ROUTES';
@@ -46,11 +46,7 @@ function ThreadDivider({ancestor, isLinkDisabled = false}: ThreadDividerProps) {
             ) : (
                 <PressableWithoutFeedback
                     onPress={() => {
-                        const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(
-                            ancestor.reportAction,
-                            ancestor.reportAction.reportActionID,
-                            ReportUtils.canUserPerformWriteAction(ancestor.report),
-                        );
+                        const isVisibleAction = shouldReportActionBeVisible(ancestor.reportAction, ancestor.reportAction.reportActionID, canUserPerformWriteAction(ancestor.report));
                         // Pop the thread report screen before navigating to the chat report.
                         Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID));
                         if (isVisibleAction) {
