From 1ff0a7c91b95aca5a067db3131a25580c4d52964 Mon Sep 17 00:00:00 2001 From: "Aimane Chnaif (via MelvinBot)" Date: Thu, 23 Apr 2026 08:17:24 +0000 Subject: [PATCH 1/4] Fix QA guide avatar disappearing when reopening admins room Use the action's actual index in sortedVisibleReportActions for displayAsGroup computation instead of the FlashList-provided index, which may be offset when useFlashListScrollKey slices the data array for deep-link scroll positioning. Co-authored-by: Aimane Chnaif --- src/pages/inbox/report/ReportActionsList.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index 4c6d19e4fd3e..d89a68e15aaa 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -700,6 +700,12 @@ function ReportActionsList({ const originalReportID = getOriginalReportID(report.reportID, reportAction, reportActionsFromOnyx); const showPreviousMessagesButton = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED && !!isConciergeSidePanel && !!showHiddenHistory && !!hasPreviousMessages; + // Use the action's actual index in sortedVisibleReportActions rather than the FlashList-provided index, + // because useFlashListScrollKey may slice the data for deep-link scroll positioning, making the + // FlashList index offset from the full array and causing wrong displayAsGroup computation. + const actionIndex = sortedVisibleReportActions.indexOf(reportAction); + const safeIndex = actionIndex >= 0 ? actionIndex : index; + return ( <> Date: Thu, 23 Apr 2026 08:25:46 +0000 Subject: [PATCH 2/4] Remove redundant indexOf in renderTopReportActions Since renderItem now computes the real index via indexOf internally, the call site in renderTopReportActions no longer needs to compute it. Co-authored-by: Aimane Chnaif --- src/pages/inbox/report/ReportActionsList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index d89a68e15aaa..ff7d52867f7c 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -849,11 +849,11 @@ function ReportActionsList({ <> {!shouldShowReportRecipientLocalTime && !hideComposer && } - {previewItems.map((action) => ( + {previewItems.map((action, index) => ( {renderItem({ item: action, - index: sortedVisibleReportActions.indexOf(action), + index, } as ListRenderItemInfo)} ))} From b9d902d46ad20737b28ab41c7b8634cfb435feb9 Mon Sep 17 00:00:00 2001 From: "Aimane Chnaif (via MelvinBot)" Date: Thu, 23 Apr 2026 09:19:44 +0000 Subject: [PATCH 3/4] Replace indexOf with precomputed index map in renderItem Avoids O(n) array scan per rendered row by precomputing a reportActionID-to-index Map once per data change. Co-authored-by: Aimane Chnaif --- src/pages/inbox/report/ReportActionsList.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index ff7d52867f7c..342533e4f771 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -695,6 +695,16 @@ function ReportActionsList({ return isExpenseReport(report) || isIOUReport(report) || isInvoiceReport(report); }, [parentReportAction, report, sortedVisibleReportActions]); + // Precompute a reportActionID → index map so renderItem can resolve the real index in O(1) + // instead of scanning sortedVisibleReportActions with indexOf on every render. + const actionIndexMap = useMemo(() => { + const map = new Map(); + for (const [i, action] of sortedVisibleReportActions.entries()) { + map.set(action.reportActionID, i); + } + return map; + }, [sortedVisibleReportActions]); + const renderItem = useCallback( ({item: reportAction, index}: ListRenderItemInfo) => { const originalReportID = getOriginalReportID(report.reportID, reportAction, reportActionsFromOnyx); @@ -703,8 +713,7 @@ function ReportActionsList({ // Use the action's actual index in sortedVisibleReportActions rather than the FlashList-provided index, // because useFlashListScrollKey may slice the data for deep-link scroll positioning, making the // FlashList index offset from the full array and causing wrong displayAsGroup computation. - const actionIndex = sortedVisibleReportActions.indexOf(reportAction); - const safeIndex = actionIndex >= 0 ? actionIndex : index; + const safeIndex = actionIndexMap.get(reportAction.reportActionID) ?? index; return ( <> @@ -760,6 +769,7 @@ function ReportActionsList({ isOffline, transactionThreadReport, linkedReportActionID, + actionIndexMap, sortedVisibleReportActions, shouldHideThreadDividerLine, unreadMarkerReportActionID, From cceddfb9f79ca207125d91924efd834df773d967 Mon Sep 17 00:00:00 2001 From: "Aimane Chnaif (via MelvinBot)" Date: Thu, 23 Apr 2026 10:26:01 +0000 Subject: [PATCH 4/4] Revert renderTopReportActions to pass global index The preview-local map index doesn't match the global list index, which can cause wrong scroll behavior for draft dismiss/save. Use actionIndexMap to pass the correct global index. Co-authored-by: Aimane Chnaif --- src/pages/inbox/report/ReportActionsList.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/inbox/report/ReportActionsList.tsx b/src/pages/inbox/report/ReportActionsList.tsx index 342533e4f771..923623ee0641 100644 --- a/src/pages/inbox/report/ReportActionsList.tsx +++ b/src/pages/inbox/report/ReportActionsList.tsx @@ -859,18 +859,18 @@ function ReportActionsList({ <> {!shouldShowReportRecipientLocalTime && !hideComposer && } - {previewItems.map((action, index) => ( + {previewItems.map((action) => ( {renderItem({ item: action, - index, + index: actionIndexMap.get(action.reportActionID) ?? 0, } as ListRenderItemInfo)} ))} ); - }, [hideComposer, initialNumToRender, renderItem, shouldShowReportRecipientLocalTime, sortedVisibleReportActions, styles]); + }, [actionIndexMap, hideComposer, initialNumToRender, renderItem, shouldShowReportRecipientLocalTime, sortedVisibleReportActions, styles]); const onStartReached = useCallback(() => { if (!isSearchTopmostFullScreenRoute()) {