From 520c7413b292cd33fd496e0e8168b0a258c60f33 Mon Sep 17 00:00:00 2001
From: DylanDylann <dylandylan9112@gmail.com>
Date: Thu, 2 Apr 2026 17:42:51 +0700
Subject: [PATCH 1/6] refactor

---
 src/components/KYCWall/BaseKYCWall.tsx  |  8 ++++++-
 src/hooks/useSearchBulkActions.ts       | 24 ++++---------------
 src/libs/ReportActionsUtils.ts          | 32 +++++++++++++++++++++++++
 src/libs/actions/Policy/Policy.ts       |  3 ++-
 src/libs/actions/Report/index.ts        |  3 ++-
 src/pages/ReportChangeWorkspacePage.tsx |  8 ++++++-
 6 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx
index 4f1006314248..a17af513f418 100644
--- a/src/components/KYCWall/BaseKYCWall.tsx
+++ b/src/components/KYCWall/BaseKYCWall.tsx
@@ -19,6 +19,7 @@ import Log from '@libs/Log';
 import setNavigationActionToMicrotaskQueue from '@libs/Navigation/helpers/setNavigationActionToMicrotaskQueue';
 import Navigation from '@libs/Navigation/Navigation';
 import {hasExpensifyPaymentMethod} from '@libs/PaymentUtils';
+import {filterReportActionsByPolicyID} from '@libs/ReportActionsUtils';
 import {getBankAccountRoute, isExpenseReport as isExpenseReportReportUtils, isIOUReport} from '@libs/ReportUtils';
 import {getEligibleExistingBusinessBankAccounts, getOpenConnectedToPolicyBusinessBankAccounts} from '@libs/WorkflowUtils';
 import {createWorkspaceFromIOUPayment} from '@userActions/Policy/Policy';
@@ -73,6 +74,8 @@ function KYCWall({
     const personalDetails = usePersonalDetails();
     const employeeEmail = personalDetails?.[iouReport?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID]?.login ?? '';
     const reportTransactions = useReportTransactions(iouReport?.reportID);
+    const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
+    const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
     const anchorRef = useRef<HTMLDivElement | View>(null);
     const transferBalanceButtonRef = useRef<HTMLDivElement | View | null>(null);
 
@@ -138,7 +141,8 @@ function KYCWall({
                 if (iouReport && isIOUReport(iouReport)) {
                     const adminPolicy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policy?.id}`];
                     if (adminPolicy) {
-                        const inviteResult = moveIOUReportToPolicyAndInviteSubmitter(iouReport, adminPolicy, formatPhoneNumber, reportTransactions);
+                        const policyReportActions = filterReportActionsByPolicyID(allReportActions, allReports, adminPolicy.id);
+                        const inviteResult = moveIOUReportToPolicyAndInviteSubmitter(iouReport, adminPolicy, formatPhoneNumber, policyReportActions, reportTransactions);
                         if (inviteResult?.policyExpenseChatReportID) {
                             setNavigationActionToMicrotaskQueue(() => {
                                 Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(inviteResult.policyExpenseChatReportID));
@@ -213,6 +217,8 @@ function KYCWall({
             introSelected,
             formatPhoneNumber,
             reportTransactions,
+            allReportActions,
+            allReports,
             lastPaymentMethod,
             isSelfTourViewed,
             betas,
diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts
index 8c63c3f9097f..fd4f2f0d269d 100644
--- a/src/hooks/useSearchBulkActions.ts
+++ b/src/hooks/useSearchBulkActions.ts
@@ -36,6 +36,7 @@ import {setNameValuePair} from '@libs/actions/User';
 import {getTransactionsAndReportsFromSearch} from '@libs/MergeTransactionUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import {getConnectedIntegration, isSubmitAndClose} from '@libs/PolicyUtils';
+import {filterReportActionsByPolicyID} from '@libs/ReportActionsUtils';
 import {getSecondaryExportReportActions, isMergeActionForSelectedTransactions} from '@libs/ReportSecondaryActionUtils';
 import {
     canEditMultipleTransactions,
@@ -631,7 +632,8 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
                         );
                         return;
                     }
-                    const invite = moveIOUReportToPolicyAndInviteSubmitter(itemReport, adminPolicy, formatPhoneNumber, reportTransactions);
+                    const policyReportActions = filterReportActionsByPolicyID(allReportActions, allReports, adminPolicy.id);
+                    const invite = moveIOUReportToPolicyAndInviteSubmitter(itemReport, adminPolicy, formatPhoneNumber, policyReportActions, reportTransactions);
                     if (!invite?.policyExpenseChatReportID) {
                         moveIOUReportToPolicy(itemReport, adminPolicy, false, reportTransactions);
                     }
@@ -679,25 +681,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
                 clearSelectedTransactions();
             });
         },
-        [
-            clearSelectedTransactions,
-            hash,
-            isOffline,
-            lastPaymentMethods,
-            selectedReports,
-            selectedTransactions,
-            policies,
-            formatPhoneNumber,
-            policyIDsWithVBBA,
-            isDelegateAccessRestricted,
-            showDelegateNoAccessModal,
-            personalPolicyID,
-            allTransactions,
-            allReports,
-            userBillingGracePeriodEnds,
-            amountOwed,
-            ownerBillingGracePeriodEnd,
-        ],
+        [hash, isOffline, isDelegateAccessRestricted, selectedReports, selectedTransactions, userBillingGracePeriodEnds, ownerBillingGracePeriodEnd, amountOwed, policies, showDelegateNoAccessModal, allReports, personalPolicyID, lastPaymentMethods, allTransactions, policyIDsWithVBBA, allReportActions, formatPhoneNumber, clearSelectedTransactions],
     );
 
     const onBulkPaySelectedRef = useRef(onBulkPaySelected);
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 2c4beee07940..015c188944ad 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -4539,6 +4539,37 @@ function hasReasoning(action: OnyxInputOrEntry<ReportAction>): boolean {
     return !!originalMessage && typeof originalMessage === 'object' && 'reasoning' in originalMessage && !!originalMessage.reasoning;
 }
 
+/**
+ * Given all report actions and all reports, return report actions keyed by reportID
+ * for reports whose policyID matches the given policyID.
+ */
+function filterReportActionsByPolicyID(allReportActions: OnyxCollection<ReportActions>, allReports: OnyxCollection<Report>, policyID: string | undefined): Record<string, ReportActions> {
+    if (!allReportActions || !allReports || !policyID) {
+        return {};
+    }
+
+    const policyReportIDs = new Set<string>();
+    for (const [key, report] of Object.entries(allReports)) {
+        if (report?.policyID === policyID) {
+            const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT, '');
+            policyReportIDs.add(reportID);
+        }
+    }
+
+    const result: Record<string, ReportActions> = {};
+    for (const [key, actions] of Object.entries(allReportActions)) {
+        if (!actions) {
+            continue;
+        }
+        const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, '');
+        if (policyReportIDs.has(reportID)) {
+            result[reportID] = actions;
+        }
+    }
+
+    return result;
+}
+
 export {
     doesReportHaveVisibleActions,
     extractLinksFromMessageHtml,
@@ -4798,6 +4829,7 @@ export {
     getReportActionActorAccountID,
     getSettlementAccountLockedMessage,
     stripFollowupListFromHtml,
+    filterReportActionsByPolicyID,
     getDynamicExternalWorkflowSubmitFailedActionMessage,
     getDynamicExternalWorkflowApproveFailedActionMessage,
 };
diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts
index 06211b30d322..4f70e0b2e06b 100644
--- a/src/libs/actions/Policy/Policy.ts
+++ b/src/libs/actions/Policy/Policy.ts
@@ -1544,6 +1544,7 @@ function verifySetupIntentAndRequestPolicyOwnerChange(policyID: string) {
 function createPolicyExpenseChats(
     policyID: string,
     invitedEmailsToAccountIDs: InvitedEmailsToAccountIDs,
+    reportActionsList?: OnyxCollection<ReportActions>,
     hasOutstandingChildRequest = false,
     notificationPreference: NotificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN,
 ): WorkspaceMembersChats {
@@ -1583,7 +1584,7 @@ function createPolicyExpenseChats(
                 },
             });
             const currentTime = DateUtils.getDBTime();
-            const reportActions = deprecatedAllReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChat.reportID}`] ?? {};
+            const reportActions = (reportActionsList ?? deprecatedAllReportActions)?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${oldChat.reportID}`] ?? {};
             for (const action of Object.values(reportActions)) {
                 if (action.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) {
                     continue;
diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts
index 7166a0a90e0e..93f99c62d68f 100644
--- a/src/libs/actions/Report/index.ts
+++ b/src/libs/actions/Report/index.ts
@@ -6103,6 +6103,7 @@ function moveIOUReportToPolicyAndInviteSubmitter(
     iouReport: OnyxEntry<Report>,
     policy: Policy,
     formatPhoneNumber: LocaleContextProps['formatPhoneNumber'],
+    reportActions: OnyxCollection<ReportActions>,
     reportTransactions: Transaction[] = [],
 ): {policyExpenseChatReportID?: string} | undefined {
     if (!policy || !iouReport) {
@@ -6176,7 +6177,7 @@ function moveIOUReportToPolicyAndInviteSubmitter(
     const announceRoomMembers = buildRoomMembersOnyxData(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID, [submitterAccountID]);
 
     // Create policy expense chat for the submitter
-    const policyExpenseChats = createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs);
+    const policyExpenseChats = createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, reportActions);
     const optimisticPolicyExpenseChatReportID = policyExpenseChats.reportCreationData[submitterEmail].reportID;
     const optimisticPolicyExpenseChatCreatedReportActionID = policyExpenseChats.reportCreationData[submitterEmail].reportActionID;
 
diff --git a/src/pages/ReportChangeWorkspacePage.tsx b/src/pages/ReportChangeWorkspacePage.tsx
index 96fa4c97a99a..62f187cdccda 100644
--- a/src/pages/ReportChangeWorkspacePage.tsx
+++ b/src/pages/ReportChangeWorkspacePage.tsx
@@ -22,6 +22,7 @@ import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavig
 import type {ReportChangeWorkspaceNavigatorParamList} from '@libs/Navigation/types';
 import {getLoginByAccountID} from '@libs/PersonalDetailsUtils';
 import {isPolicyAdmin, isPolicyMember} from '@libs/PolicyUtils';
+import {filterReportActionsByPolicyID} from '@libs/ReportActionsUtils';
 import {
     hasViolations as hasViolationsReportUtils,
     isExpenseReport,
@@ -74,6 +75,8 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
     const hasViolations = hasViolationsReportUtils(report?.reportID, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
     const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
     const [userBillingGracePeriods] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END);
+    const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
+    const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
 
     const selectPolicy = useCallback(
         (policyID?: string) => {
@@ -88,7 +91,8 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
             const {backTo} = route.params;
             Navigation.goBack(backTo);
             if (isIOUReport(reportID)) {
-                const invite = moveIOUReportToPolicyAndInviteSubmitter(report, policy, formatPhoneNumber, reportTransactions);
+                const policyReportActions = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
+                const invite = moveIOUReportToPolicyAndInviteSubmitter(report, policy, formatPhoneNumber, policyReportActions, reportTransactions);
                 if (!invite?.policyExpenseChatReportID) {
                     moveIOUReportToPolicy(report, policy, false, reportTransactions);
                 }
@@ -134,6 +138,8 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
             parentReport,
             formatPhoneNumber,
             reportTransactions,
+            allReportActions,
+            allReports,
             isReportLastVisibleArchived,
             session?.accountID,
             session?.email,

From 671c66e4561cee8dbca863dd50c9e9c6fd303980 Mon Sep 17 00:00:00 2001
From: DylanDylann <dylandylan9112@gmail.com>
Date: Thu, 2 Apr 2026 21:23:23 +0700
Subject: [PATCH 2/6] resolve comment

---
 src/hooks/useSearchBulkActions.ts    |  21 +++++-
 src/libs/ReportActionsUtils.ts       |  21 +++---
 src/libs/actions/Policy/Policy.ts    |   1 +
 tests/unit/ReportActionsUtilsTest.ts | 105 +++++++++++++++++++++++++++
 4 files changed, 138 insertions(+), 10 deletions(-)

diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts
index fd4f2f0d269d..1b0290f683b4 100644
--- a/src/hooks/useSearchBulkActions.ts
+++ b/src/hooks/useSearchBulkActions.ts
@@ -681,7 +681,26 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
                 clearSelectedTransactions();
             });
         },
-        [hash, isOffline, isDelegateAccessRestricted, selectedReports, selectedTransactions, userBillingGracePeriodEnds, ownerBillingGracePeriodEnd, amountOwed, policies, showDelegateNoAccessModal, allReports, personalPolicyID, lastPaymentMethods, allTransactions, policyIDsWithVBBA, allReportActions, formatPhoneNumber, clearSelectedTransactions],
+        [
+            hash,
+            isOffline,
+            isDelegateAccessRestricted,
+            selectedReports,
+            selectedTransactions,
+            userBillingGracePeriodEnds,
+            ownerBillingGracePeriodEnd,
+            amountOwed,
+            policies,
+            showDelegateNoAccessModal,
+            allReports,
+            personalPolicyID,
+            lastPaymentMethods,
+            allTransactions,
+            policyIDsWithVBBA,
+            allReportActions,
+            formatPhoneNumber,
+            clearSelectedTransactions,
+        ],
     );
 
     const onBulkPaySelectedRef = useRef(onBulkPaySelected);
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 015c188944ad..dd9df776260f 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -9,7 +9,7 @@ import type {ValueOf} from 'type-fest';
 import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider';
 import usePrevious from '@hooks/usePrevious';
 // eslint-disable-next-line @dword-design/import-alias/prefer-alias
-import {doesReportContainRequestsFromMultipleUsers, getReportOrDraftReport} from '@libs/ReportUtils';
+import {doesReportContainRequestsFromMultipleUsers, getReportOrDraftReport, isThread} from '@libs/ReportUtils';
 import CONST from '@src/CONST';
 import IntlStore from '@src/languages/IntlStore';
 import type {TranslationPaths} from '@src/languages/types';
@@ -4543,27 +4543,30 @@ function hasReasoning(action: OnyxInputOrEntry<ReportAction>): boolean {
  * Given all report actions and all reports, return report actions keyed by reportID
  * for reports whose policyID matches the given policyID.
  */
-function filterReportActionsByPolicyID(allReportActions: OnyxCollection<ReportActions>, allReports: OnyxCollection<Report>, policyID: string | undefined): Record<string, ReportActions> {
-    if (!allReportActions || !allReports || !policyID) {
+function filterReportActionsByPolicyID(
+    allReportActionsParam: OnyxCollection<ReportActions>,
+    allReportsPram: OnyxCollection<Report>,
+    policyID: string | undefined,
+): Record<string, ReportActions> {
+    if (!allReportActionsParam || !allReportsPram || !policyID) {
         return {};
     }
 
     const policyReportIDs = new Set<string>();
-    for (const [key, report] of Object.entries(allReports)) {
-        if (report?.policyID === policyID) {
-            const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT, '');
-            policyReportIDs.add(reportID);
+    for (const [, report] of Object.entries(allReportsPram)) {
+        if (report?.policyID === policyID && isPolicyExpenseChat(report) && !isThread(report)) {
+            policyReportIDs.add(report.reportID);
         }
     }
 
     const result: Record<string, ReportActions> = {};
-    for (const [key, actions] of Object.entries(allReportActions)) {
+    for (const [key, actions] of Object.entries(allReportActionsParam)) {
         if (!actions) {
             continue;
         }
         const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, '');
         if (policyReportIDs.has(reportID)) {
-            result[reportID] = actions;
+            result[key] = actions;
         }
     }
 
diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts
index 4f70e0b2e06b..4daac932f748 100644
--- a/src/libs/actions/Policy/Policy.ts
+++ b/src/libs/actions/Policy/Policy.ts
@@ -1544,6 +1544,7 @@ function verifySetupIntentAndRequestPolicyOwnerChange(policyID: string) {
 function createPolicyExpenseChats(
     policyID: string,
     invitedEmailsToAccountIDs: InvitedEmailsToAccountIDs,
+    // TODO: Remove optional (?) once all is updated (https://github.com/Expensify/App/issues/66578)
     reportActionsList?: OnyxCollection<ReportActions>,
     hasOutstandingChildRequest = false,
     notificationPreference: NotificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN,
diff --git a/tests/unit/ReportActionsUtilsTest.ts b/tests/unit/ReportActionsUtilsTest.ts
index 1f59950c971d..ce52d655faba 100644
--- a/tests/unit/ReportActionsUtilsTest.ts
+++ b/tests/unit/ReportActionsUtilsTest.ts
@@ -11,6 +11,7 @@ import {chatReportR14932 as mockChatReport, iouReportR14932 as mockIOUReport} fr
 import CONST from '../../src/CONST';
 import * as ReportActionsUtils from '../../src/libs/ReportActionsUtils';
 import {
+    filterReportActionsByPolicyID,
     findLastReportActions,
     getAddedCardFeedMessage,
     getAssignedCompanyCardMessage,
@@ -4676,4 +4677,108 @@ describe('ReportActionsUtils', () => {
             ).toBe(false);
         });
     });
+
+    describe('filterReportActionsByPolicyID', () => {
+        const policyID = 'policy123';
+        const otherPolicyID = 'otherPolicy';
+
+        const policyExpenseReport: Report = {
+            reportID: '1',
+            policyID,
+            chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
+            type: CONST.REPORT.TYPE.CHAT,
+            reportName: 'Expense Chat',
+        };
+
+        const otherPolicyReport: Report = {
+            reportID: '2',
+            policyID: otherPolicyID,
+            chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
+            type: CONST.REPORT.TYPE.CHAT,
+            reportName: 'Other Policy Chat',
+        };
+
+        const threadReport: Report = {
+            reportID: '3',
+            policyID,
+            chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
+            type: CONST.REPORT.TYPE.CHAT,
+            parentReportID: '1',
+            parentReportActionID: 'action1',
+            reportName: 'Thread',
+        };
+
+        const nonExpenseChatReport: Report = {
+            reportID: '4',
+            policyID,
+            chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM,
+            type: CONST.REPORT.TYPE.CHAT,
+            reportName: 'Policy Room',
+        };
+
+        const actions1: ReportActions = {action1: createRandomReportAction(1)};
+        const actions2: ReportActions = {action2: createRandomReportAction(2)};
+        const actions3: ReportActions = {action3: createRandomReportAction(3)};
+        const actions4: ReportActions = {action4: createRandomReportAction(4)};
+
+        const allReports = {
+            // eslint-disable-next-line @typescript-eslint/naming-convention
+            report_1: policyExpenseReport,
+            // eslint-disable-next-line @typescript-eslint/naming-convention
+            report_2: otherPolicyReport,
+            // eslint-disable-next-line @typescript-eslint/naming-convention
+            report_3: threadReport,
+            // eslint-disable-next-line @typescript-eslint/naming-convention
+            report_4: nonExpenseChatReport,
+        };
+
+        const allReportActions = {
+            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: actions1,
+            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2`]: actions2,
+            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}3`]: actions3,
+            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}4`]: actions4,
+        };
+
+        it('returns empty object when allReportActions is undefined', () => {
+            expect(filterReportActionsByPolicyID(undefined, allReports, policyID)).toEqual({});
+        });
+
+        it('returns empty object when allReports is undefined', () => {
+            expect(filterReportActionsByPolicyID(allReportActions, undefined, policyID)).toEqual({});
+        });
+
+        it('returns empty object when policyID is undefined', () => {
+            expect(filterReportActionsByPolicyID(allReportActions, allReports, undefined)).toEqual({});
+        });
+
+        it('returns only actions for policy expense chats matching the policyID', () => {
+            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
+            expect(result).toHaveProperty('1');
+            expect(result['1']).toBe(actions1);
+        });
+
+        it('excludes reports with a different policyID', () => {
+            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
+            expect(result).not.toHaveProperty('2');
+        });
+
+        it('excludes thread reports', () => {
+            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
+            expect(result).not.toHaveProperty('3');
+        });
+
+        it('excludes non-policy-expense-chat reports', () => {
+            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
+            expect(result).not.toHaveProperty('4');
+        });
+
+        it('skips null actions entries', () => {
+            const actionsWithNull = {
+                ...allReportActions,
+                [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: null,
+            };
+            const result = filterReportActionsByPolicyID(actionsWithNull, allReports, policyID);
+            expect(result).toEqual({});
+        });
+    });
 });

From 9eea7fe92d632dd5f6d26ca44479fd07cbd011d9 Mon Sep 17 00:00:00 2001
From: DylanDylann <dylandylan9112@gmail.com>
Date: Thu, 2 Apr 2026 21:51:07 +0700
Subject: [PATCH 3/6] resolve comment

---
 src/components/KYCWall/BaseKYCWall.tsx        |  11 +-
 .../usePolicyExpenseChatReportActions.ts      |  54 +++++++++
 src/hooks/useSearchBulkActions.ts             |   7 +-
 src/libs/ReportActionsUtils.ts                |  35 ------
 src/libs/actions/Policy/Member.ts             |   3 +-
 src/libs/actions/Policy/Policy.ts             |  11 +-
 src/pages/ReportChangeWorkspacePage.tsx       |  11 +-
 tests/unit/ReportActionsUtilsTest.ts          | 105 ------------------
 8 files changed, 77 insertions(+), 160 deletions(-)
 create mode 100644 src/hooks/usePolicyExpenseChatReportActions.ts

diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx
index a17af513f418..78ca3ab26432 100644
--- a/src/components/KYCWall/BaseKYCWall.tsx
+++ b/src/components/KYCWall/BaseKYCWall.tsx
@@ -8,6 +8,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
 import useLocalize from '@hooks/useLocalize';
 import useOnyx from '@hooks/useOnyx';
 import useParentReportAction from '@hooks/useParentReportAction';
+import usePolicyExpenseChatReportActions from '@hooks/usePolicyExpenseChatReportActions';
 import useReportTransactions from '@hooks/useReportTransactions';
 import {openPersonalBankAccountSetupView} from '@libs/actions/BankAccounts';
 import {completePaymentOnboarding, savePreferredPaymentMethod} from '@libs/actions/IOU';
@@ -19,7 +20,6 @@ import Log from '@libs/Log';
 import setNavigationActionToMicrotaskQueue from '@libs/Navigation/helpers/setNavigationActionToMicrotaskQueue';
 import Navigation from '@libs/Navigation/Navigation';
 import {hasExpensifyPaymentMethod} from '@libs/PaymentUtils';
-import {filterReportActionsByPolicyID} from '@libs/ReportActionsUtils';
 import {getBankAccountRoute, isExpenseReport as isExpenseReportReportUtils, isIOUReport} from '@libs/ReportUtils';
 import {getEligibleExistingBusinessBankAccounts, getOpenConnectedToPolicyBusinessBankAccounts} from '@libs/WorkflowUtils';
 import {createWorkspaceFromIOUPayment} from '@userActions/Policy/Policy';
@@ -74,8 +74,7 @@ function KYCWall({
     const personalDetails = usePersonalDetails();
     const employeeEmail = personalDetails?.[iouReport?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID]?.login ?? '';
     const reportTransactions = useReportTransactions(iouReport?.reportID);
-    const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
-    const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
+    const {filteredReportActions} = usePolicyExpenseChatReportActions();
     const anchorRef = useRef<HTMLDivElement | View>(null);
     const transferBalanceButtonRef = useRef<HTMLDivElement | View | null>(null);
 
@@ -141,8 +140,7 @@ function KYCWall({
                 if (iouReport && isIOUReport(iouReport)) {
                     const adminPolicy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policy?.id}`];
                     if (adminPolicy) {
-                        const policyReportActions = filterReportActionsByPolicyID(allReportActions, allReports, adminPolicy.id);
-                        const inviteResult = moveIOUReportToPolicyAndInviteSubmitter(iouReport, adminPolicy, formatPhoneNumber, policyReportActions, reportTransactions);
+                        const inviteResult = moveIOUReportToPolicyAndInviteSubmitter(iouReport, adminPolicy, formatPhoneNumber, filteredReportActions, reportTransactions);
                         if (inviteResult?.policyExpenseChatReportID) {
                             setNavigationActionToMicrotaskQueue(() => {
                                 Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(inviteResult.policyExpenseChatReportID));
@@ -217,8 +215,7 @@ function KYCWall({
             introSelected,
             formatPhoneNumber,
             reportTransactions,
-            allReportActions,
-            allReports,
+            filteredReportActions,
             lastPaymentMethod,
             isSelfTourViewed,
             betas,
diff --git a/src/hooks/usePolicyExpenseChatReportActions.ts b/src/hooks/usePolicyExpenseChatReportActions.ts
new file mode 100644
index 000000000000..9dfe41e95b53
--- /dev/null
+++ b/src/hooks/usePolicyExpenseChatReportActions.ts
@@ -0,0 +1,54 @@
+import {useCallback, useMemo} from 'react';
+import type {OnyxCollection} from 'react-native-onyx';
+import {isPolicyExpenseChat, isThread} from '@libs/ReportUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {Report, ReportActions} from '@src/types/onyx';
+import mapOnyxCollectionItems from '@src/utils/mapOnyxCollectionItems';
+import useOnyx from './useOnyx';
+
+const policyExpenseChatReportsSelector = (reports: OnyxCollection<Report>) => {
+    return mapOnyxCollectionItems(reports, (report) => {
+        if (!report || !isPolicyExpenseChat(report) || isThread(report)) {
+            return undefined;
+        }
+        return report;
+    });
+};
+
+/**
+ * Returns all reports that satisfy isPolicyExpenseChat && !isThread (via selector),
+ * along with reportActions filtered to only those matching reports.
+ */
+function usePolicyExpenseChatReportActions() {
+    const [policyExpenseChatReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {selector: policyExpenseChatReportsSelector});
+
+    const policyExpenseChatReportIDs = useMemo(() => {
+        const ids = new Set<string>();
+        for (const report of Object.values(policyExpenseChatReports ?? {})) {
+            if (report?.reportID) {
+                ids.add(report.reportID);
+            }
+        }
+        return ids;
+    }, [policyExpenseChatReports]);
+
+    const reportActionsSelector = useCallback(
+        (reportActions: OnyxCollection<ReportActions>) => {
+            const result: NonNullable<OnyxCollection<ReportActions>> = {};
+            for (const [key, actions] of Object.entries(reportActions ?? {})) {
+                const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, '');
+                if (policyExpenseChatReportIDs.has(reportID)) {
+                    result[key] = actions;
+                }
+            }
+            return result;
+        },
+        [policyExpenseChatReportIDs],
+    );
+
+    const [filteredReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {selector: reportActionsSelector}, [reportActionsSelector]);
+
+    return {policyExpenseChatReports, filteredReportActions};
+}
+
+export default usePolicyExpenseChatReportActions;
diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts
index 1b0290f683b4..240a7e6bd2e0 100644
--- a/src/hooks/useSearchBulkActions.ts
+++ b/src/hooks/useSearchBulkActions.ts
@@ -36,7 +36,6 @@ import {setNameValuePair} from '@libs/actions/User';
 import {getTransactionsAndReportsFromSearch} from '@libs/MergeTransactionUtils';
 import Navigation from '@libs/Navigation/Navigation';
 import {getConnectedIntegration, isSubmitAndClose} from '@libs/PolicyUtils';
-import {filterReportActionsByPolicyID} from '@libs/ReportActionsUtils';
 import {getSecondaryExportReportActions, isMergeActionForSelectedTransactions} from '@libs/ReportSecondaryActionUtils';
 import {
     canEditMultipleTransactions,
@@ -71,6 +70,7 @@ import useNetwork from './useNetwork';
 import useOnyx from './useOnyx';
 import usePermissions from './usePermissions';
 import usePersonalPolicy from './usePersonalPolicy';
+import usePolicyExpenseChatReportActions from './usePolicyExpenseChatReportActions';
 import useSelfDMReport from './useSelfDMReport';
 import useTheme from './useTheme';
 import useThemeStyles from './useThemeStyles';
@@ -111,6 +111,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
     const allTransactions = useAllTransactions();
     const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
     const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
+    const {filteredReportActions: policyExpenseChatReportActions} = usePolicyExpenseChatReportActions();
     const [allReportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS);
     const selfDMReport = useSelfDMReport();
     const [lastPaymentMethods] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD);
@@ -632,8 +633,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
                         );
                         return;
                     }
-                    const policyReportActions = filterReportActionsByPolicyID(allReportActions, allReports, adminPolicy.id);
-                    const invite = moveIOUReportToPolicyAndInviteSubmitter(itemReport, adminPolicy, formatPhoneNumber, policyReportActions, reportTransactions);
+                    const invite = moveIOUReportToPolicyAndInviteSubmitter(itemReport, adminPolicy, formatPhoneNumber, policyExpenseChatReportActions, reportTransactions);
                     if (!invite?.policyExpenseChatReportID) {
                         moveIOUReportToPolicy(itemReport, adminPolicy, false, reportTransactions);
                     }
@@ -698,6 +698,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
             allTransactions,
             policyIDsWithVBBA,
             allReportActions,
+            policyExpenseChatReportActions,
             formatPhoneNumber,
             clearSelectedTransactions,
         ],
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index dd9df776260f..66dc603ff99f 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -4539,40 +4539,6 @@ function hasReasoning(action: OnyxInputOrEntry<ReportAction>): boolean {
     return !!originalMessage && typeof originalMessage === 'object' && 'reasoning' in originalMessage && !!originalMessage.reasoning;
 }
 
-/**
- * Given all report actions and all reports, return report actions keyed by reportID
- * for reports whose policyID matches the given policyID.
- */
-function filterReportActionsByPolicyID(
-    allReportActionsParam: OnyxCollection<ReportActions>,
-    allReportsPram: OnyxCollection<Report>,
-    policyID: string | undefined,
-): Record<string, ReportActions> {
-    if (!allReportActionsParam || !allReportsPram || !policyID) {
-        return {};
-    }
-
-    const policyReportIDs = new Set<string>();
-    for (const [, report] of Object.entries(allReportsPram)) {
-        if (report?.policyID === policyID && isPolicyExpenseChat(report) && !isThread(report)) {
-            policyReportIDs.add(report.reportID);
-        }
-    }
-
-    const result: Record<string, ReportActions> = {};
-    for (const [key, actions] of Object.entries(allReportActionsParam)) {
-        if (!actions) {
-            continue;
-        }
-        const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, '');
-        if (policyReportIDs.has(reportID)) {
-            result[key] = actions;
-        }
-    }
-
-    return result;
-}
-
 export {
     doesReportHaveVisibleActions,
     extractLinksFromMessageHtml,
@@ -4832,7 +4798,6 @@ export {
     getReportActionActorAccountID,
     getSettlementAccountLockedMessage,
     stripFollowupListFromHtml,
-    filterReportActionsByPolicyID,
     getDynamicExternalWorkflowSubmitFailedActionMessage,
     getDynamicExternalWorkflowApproveFailedActionMessage,
 };
diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts
index e77277022878..0765f0a001c6 100644
--- a/src/libs/actions/Policy/Member.ts
+++ b/src/libs/actions/Policy/Member.ts
@@ -869,7 +869,8 @@ function buildAddMembersToWorkspaceOnyxData(
     const announceRoomChat = optimisticAnnounceChat.announceChatData;
 
     // create onyx data for policy expense chats for each new member
-    const membersChats = createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, undefined, policyExpenseChatNotificationPreference);
+    // TODO: Update to include reportActionsList later (https://github.com/Expensify/App/issues/66578)
+    const membersChats = createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, undefined, undefined, policyExpenseChatNotificationPreference);
 
     const optimisticMembersState: OnyxCollectionInputValue<PolicyEmployee> = {};
     const successMembersState: OnyxCollectionInputValue<PolicyEmployee> = {};
diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts
index 4daac932f748..0b2a8a7e2d40 100644
--- a/src/libs/actions/Policy/Policy.ts
+++ b/src/libs/actions/Policy/Policy.ts
@@ -2899,7 +2899,13 @@ function buildPolicyData(options: BuildPolicyDataOptions): OnyxData<BuildPolicyD
     }
 
     if (adminParticipant?.login) {
-        const employeeWorkspaceChat = createPolicyExpenseChats(policyID, {[adminParticipant.login]: adminParticipant.accountID ?? CONST.DEFAULT_NUMBER_ID}, hasOutstandingChildRequest);
+        // TODO: Update to include reportActionsList later (https://github.com/Expensify/App/issues/66578)
+        const employeeWorkspaceChat = createPolicyExpenseChats(
+            policyID,
+            {[adminParticipant.login]: adminParticipant.accountID ?? CONST.DEFAULT_NUMBER_ID},
+            undefined,
+            hasOutstandingChildRequest,
+        );
         params.memberData = JSON.stringify({
             accountID: Number(adminParticipant.accountID),
             email: adminParticipant.login,
@@ -3941,7 +3947,8 @@ function createWorkspaceFromIOUPayment(
     }
 
     // Create the expense chat for the employee whose IOU is being paid
-    const employeeWorkspaceChat = createPolicyExpenseChats(policyID, {[iouReportOwnerEmail]: employeeAccountID}, true);
+    // TODO: Update to include reportActionsList later (https://github.com/Expensify/App/issues/66578)
+    const employeeWorkspaceChat = createPolicyExpenseChats(policyID, {[iouReportOwnerEmail]: employeeAccountID}, undefined, true);
     const newWorkspace = {
         id: policyID,
 
diff --git a/src/pages/ReportChangeWorkspacePage.tsx b/src/pages/ReportChangeWorkspacePage.tsx
index 62f187cdccda..8d92378aebd2 100644
--- a/src/pages/ReportChangeWorkspacePage.tsx
+++ b/src/pages/ReportChangeWorkspacePage.tsx
@@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
 import useOnyx from '@hooks/useOnyx';
 import usePermissions from '@hooks/usePermissions';
+import usePolicyExpenseChatReportActions from '@hooks/usePolicyExpenseChatReportActions';
 import useReportIsArchived from '@hooks/useReportIsArchived';
 import useReportTransactions from '@hooks/useReportTransactions';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -22,7 +23,6 @@ import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavig
 import type {ReportChangeWorkspaceNavigatorParamList} from '@libs/Navigation/types';
 import {getLoginByAccountID} from '@libs/PersonalDetailsUtils';
 import {isPolicyAdmin, isPolicyMember} from '@libs/PolicyUtils';
-import {filterReportActionsByPolicyID} from '@libs/ReportActionsUtils';
 import {
     hasViolations as hasViolationsReportUtils,
     isExpenseReport,
@@ -75,8 +75,7 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
     const hasViolations = hasViolationsReportUtils(report?.reportID, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
     const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
     const [userBillingGracePeriods] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END);
-    const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
-    const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
+    const {filteredReportActions} = usePolicyExpenseChatReportActions();
 
     const selectPolicy = useCallback(
         (policyID?: string) => {
@@ -91,8 +90,7 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
             const {backTo} = route.params;
             Navigation.goBack(backTo);
             if (isIOUReport(reportID)) {
-                const policyReportActions = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
-                const invite = moveIOUReportToPolicyAndInviteSubmitter(report, policy, formatPhoneNumber, policyReportActions, reportTransactions);
+                const invite = moveIOUReportToPolicyAndInviteSubmitter(report, policy, formatPhoneNumber, filteredReportActions, reportTransactions);
                 if (!invite?.policyExpenseChatReportID) {
                     moveIOUReportToPolicy(report, policy, false, reportTransactions);
                 }
@@ -138,8 +136,7 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
             parentReport,
             formatPhoneNumber,
             reportTransactions,
-            allReportActions,
-            allReports,
+            filteredReportActions,
             isReportLastVisibleArchived,
             session?.accountID,
             session?.email,
diff --git a/tests/unit/ReportActionsUtilsTest.ts b/tests/unit/ReportActionsUtilsTest.ts
index ce52d655faba..1f59950c971d 100644
--- a/tests/unit/ReportActionsUtilsTest.ts
+++ b/tests/unit/ReportActionsUtilsTest.ts
@@ -11,7 +11,6 @@ import {chatReportR14932 as mockChatReport, iouReportR14932 as mockIOUReport} fr
 import CONST from '../../src/CONST';
 import * as ReportActionsUtils from '../../src/libs/ReportActionsUtils';
 import {
-    filterReportActionsByPolicyID,
     findLastReportActions,
     getAddedCardFeedMessage,
     getAssignedCompanyCardMessage,
@@ -4677,108 +4676,4 @@ describe('ReportActionsUtils', () => {
             ).toBe(false);
         });
     });
-
-    describe('filterReportActionsByPolicyID', () => {
-        const policyID = 'policy123';
-        const otherPolicyID = 'otherPolicy';
-
-        const policyExpenseReport: Report = {
-            reportID: '1',
-            policyID,
-            chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
-            type: CONST.REPORT.TYPE.CHAT,
-            reportName: 'Expense Chat',
-        };
-
-        const otherPolicyReport: Report = {
-            reportID: '2',
-            policyID: otherPolicyID,
-            chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
-            type: CONST.REPORT.TYPE.CHAT,
-            reportName: 'Other Policy Chat',
-        };
-
-        const threadReport: Report = {
-            reportID: '3',
-            policyID,
-            chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
-            type: CONST.REPORT.TYPE.CHAT,
-            parentReportID: '1',
-            parentReportActionID: 'action1',
-            reportName: 'Thread',
-        };
-
-        const nonExpenseChatReport: Report = {
-            reportID: '4',
-            policyID,
-            chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM,
-            type: CONST.REPORT.TYPE.CHAT,
-            reportName: 'Policy Room',
-        };
-
-        const actions1: ReportActions = {action1: createRandomReportAction(1)};
-        const actions2: ReportActions = {action2: createRandomReportAction(2)};
-        const actions3: ReportActions = {action3: createRandomReportAction(3)};
-        const actions4: ReportActions = {action4: createRandomReportAction(4)};
-
-        const allReports = {
-            // eslint-disable-next-line @typescript-eslint/naming-convention
-            report_1: policyExpenseReport,
-            // eslint-disable-next-line @typescript-eslint/naming-convention
-            report_2: otherPolicyReport,
-            // eslint-disable-next-line @typescript-eslint/naming-convention
-            report_3: threadReport,
-            // eslint-disable-next-line @typescript-eslint/naming-convention
-            report_4: nonExpenseChatReport,
-        };
-
-        const allReportActions = {
-            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: actions1,
-            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}2`]: actions2,
-            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}3`]: actions3,
-            [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}4`]: actions4,
-        };
-
-        it('returns empty object when allReportActions is undefined', () => {
-            expect(filterReportActionsByPolicyID(undefined, allReports, policyID)).toEqual({});
-        });
-
-        it('returns empty object when allReports is undefined', () => {
-            expect(filterReportActionsByPolicyID(allReportActions, undefined, policyID)).toEqual({});
-        });
-
-        it('returns empty object when policyID is undefined', () => {
-            expect(filterReportActionsByPolicyID(allReportActions, allReports, undefined)).toEqual({});
-        });
-
-        it('returns only actions for policy expense chats matching the policyID', () => {
-            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
-            expect(result).toHaveProperty('1');
-            expect(result['1']).toBe(actions1);
-        });
-
-        it('excludes reports with a different policyID', () => {
-            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
-            expect(result).not.toHaveProperty('2');
-        });
-
-        it('excludes thread reports', () => {
-            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
-            expect(result).not.toHaveProperty('3');
-        });
-
-        it('excludes non-policy-expense-chat reports', () => {
-            const result = filterReportActionsByPolicyID(allReportActions, allReports, policyID);
-            expect(result).not.toHaveProperty('4');
-        });
-
-        it('skips null actions entries', () => {
-            const actionsWithNull = {
-                ...allReportActions,
-                [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}1`]: null,
-            };
-            const result = filterReportActionsByPolicyID(actionsWithNull, allReports, policyID);
-            expect(result).toEqual({});
-        });
-    });
 });

From 87d62abb15e0fced912eb5626b97bea195ea267c Mon Sep 17 00:00:00 2001
From: DylanDylann <dylandylan9112@gmail.com>
Date: Thu, 2 Apr 2026 22:02:26 +0700
Subject: [PATCH 4/6] resolve comment

---
 src/libs/ReportActionsUtils.ts |  2 +-
 tests/actions/ReportTest.ts    | 96 +++++++++++++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 3 deletions(-)

diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 66dc603ff99f..2c4beee07940 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -9,7 +9,7 @@ import type {ValueOf} from 'type-fest';
 import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider';
 import usePrevious from '@hooks/usePrevious';
 // eslint-disable-next-line @dword-design/import-alias/prefer-alias
-import {doesReportContainRequestsFromMultipleUsers, getReportOrDraftReport, isThread} from '@libs/ReportUtils';
+import {doesReportContainRequestsFromMultipleUsers, getReportOrDraftReport} from '@libs/ReportUtils';
 import CONST from '@src/CONST';
 import IntlStore from '@src/languages/IntlStore';
 import type {TranslationPaths} from '@src/languages/types';
diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts
index 7763d49700b0..ec603705ad79 100644
--- a/tests/actions/ReportTest.ts
+++ b/tests/actions/ReportTest.ts
@@ -3583,7 +3583,7 @@ describe('actions/Report', () => {
             await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy);
 
             // When moving iou to a workspace and invite the submitter
-            Report.moveIOUReportToPolicyAndInviteSubmitter(iouReport, policy, (phone: string) => phone);
+            Report.moveIOUReportToPolicyAndInviteSubmitter(iouReport, policy, (phone: string) => phone, {});
             await waitForBatchedUpdates();
 
             // Then MOVED report action should be added to the expense report
@@ -3650,7 +3650,7 @@ describe('actions/Report', () => {
 
             // Call moveIOUReportToPolicyAndInviteSubmitter
             const formatPhoneNumber = (phoneNumber: string) => phoneNumber;
-            Report.moveIOUReportToPolicyAndInviteSubmitter(iouReport, policy, formatPhoneNumber);
+            Report.moveIOUReportToPolicyAndInviteSubmitter(iouReport, policy, formatPhoneNumber, {});
             await waitForBatchedUpdates();
 
             // Simulate network failure
@@ -3677,6 +3677,98 @@ describe('actions/Report', () => {
             // Cleanup
             mockFetch.succeed?.();
         });
+
+        it('should negate transaction amounts when reportTransactions are provided', async () => {
+            const ownerAccountID = 1;
+            const ownerEmail = 'owner@gmail.com';
+            const transactionID = 'txn123';
+            const iouReport: OnyxTypes.Report = {
+                ...createRandomReport(1, undefined),
+                type: CONST.REPORT.TYPE.IOU,
+                ownerAccountID,
+                total: 5000,
+            };
+            const policy: OnyxTypes.Policy = {...createRandomPolicy(1), role: CONST.POLICY.ROLE.ADMIN};
+            const transaction: OnyxTypes.Transaction = {
+                ...createRandomTransaction(1),
+                transactionID,
+                reportID: iouReport.reportID,
+                amount: 5000,
+                modifiedAmount: 6000,
+            };
+
+            await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
+                [ownerAccountID]: {
+                    login: ownerEmail,
+                },
+            });
+            await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, iouReport);
+            await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy);
+            await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, transaction);
+
+            // When moving IOU to a workspace with reportTransactions
+            Report.moveIOUReportToPolicyAndInviteSubmitter(iouReport, policy, (phone: string) => phone, {}, [transaction]);
+            await waitForBatchedUpdates();
+
+            // Then the transaction amounts should be negated optimistically
+            const updatedTransaction = await new Promise<OnyxEntry<OnyxTypes.Transaction>>((resolve) => {
+                const connection = Onyx.connect({
+                    key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
+                    callback: (val) => {
+                        resolve(val);
+                        Onyx.disconnect(connection);
+                    },
+                });
+            });
+            expect(updatedTransaction?.amount).toBe(-5000);
+            expect(updatedTransaction?.modifiedAmount).toBe(-6000);
+        });
+
+        it('should convert IOU report to expense report with correct policyID when reportTransactions are provided', async () => {
+            const ownerAccountID = 1;
+            const ownerEmail = 'owner@gmail.com';
+            const transactionID = 'txn456';
+            const iouReport: OnyxTypes.Report = {
+                ...createRandomReport(1, undefined),
+                type: CONST.REPORT.TYPE.IOU,
+                ownerAccountID,
+                total: 3000,
+            };
+            const policy: OnyxTypes.Policy = {...createRandomPolicy(1), role: CONST.POLICY.ROLE.ADMIN};
+            const transaction: OnyxTypes.Transaction = {
+                ...createRandomTransaction(1),
+                transactionID,
+                reportID: iouReport.reportID,
+                amount: 3000,
+            };
+
+            await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
+                [ownerAccountID]: {
+                    login: ownerEmail,
+                },
+            });
+            await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, iouReport);
+            await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`, policy);
+            await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, transaction);
+
+            // When moving IOU to a workspace with transactions
+            Report.moveIOUReportToPolicyAndInviteSubmitter(iouReport, policy, (phone: string) => phone, {}, [transaction]);
+            await waitForBatchedUpdates();
+
+            // Then the report should be converted to an expense report with the new policyID
+            const updatedReport = await new Promise<OnyxEntry<OnyxTypes.Report>>((resolve) => {
+                const connection = Onyx.connect({
+                    key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`,
+                    callback: (val) => {
+                        resolve(val);
+                        Onyx.disconnect(connection);
+                    },
+                });
+            });
+            expect(updatedReport?.type).toBe(CONST.REPORT.TYPE.EXPENSE);
+            expect(updatedReport?.policyID).toBe(policy.id);
+            expect(updatedReport?.total).toBe(-3000);
+        });
     });
 
     describe('buildOptimisticChangePolicyData', () => {

From 33092453c8c035519406c764aeadd7fd1e378f5f Mon Sep 17 00:00:00 2001
From: DylanDylann <dylandylan9112@gmail.com>
Date: Fri, 3 Apr 2026 22:39:31 +0700
Subject: [PATCH 5/6] update deps list

---
 src/hooks/useSearchBulkActions.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts
index 240a7e6bd2e0..3d668855e397 100644
--- a/src/hooks/useSearchBulkActions.ts
+++ b/src/hooks/useSearchBulkActions.ts
@@ -697,7 +697,6 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
             lastPaymentMethods,
             allTransactions,
             policyIDsWithVBBA,
-            allReportActions,
             policyExpenseChatReportActions,
             formatPhoneNumber,
             clearSelectedTransactions,

From 44fda6926b4ed386a62ad9cff16db54fd1c22141 Mon Sep 17 00:00:00 2001
From: DylanDylann <dylandylan9112@gmail.com>
Date: Fri, 3 Apr 2026 23:10:06 +0700
Subject: [PATCH 6/6] update hook name

---
 src/components/KYCWall/BaseKYCWall.tsx                        | 4 ++--
 ...portActions.ts => useAllPolicyExpenseChatReportActions.ts} | 4 ++--
 src/hooks/useSearchBulkActions.ts                             | 4 ++--
 src/pages/ReportChangeWorkspacePage.tsx                       | 4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)
 rename src/hooks/{usePolicyExpenseChatReportActions.ts => useAllPolicyExpenseChatReportActions.ts} (95%)

diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx
index bf1759f07385..531ef2b4a393 100644
--- a/src/components/KYCWall/BaseKYCWall.tsx
+++ b/src/components/KYCWall/BaseKYCWall.tsx
@@ -4,11 +4,11 @@ import {Dimensions} from 'react-native';
 import type {EmitterSubscription, View} from 'react-native';
 import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu';
 import {usePersonalDetails} from '@components/OnyxListItemProvider';
+import useAllPolicyExpenseChatReportActions from '@hooks/useAllPolicyExpenseChatReportActions';
 import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
 import useLocalize from '@hooks/useLocalize';
 import useOnyx from '@hooks/useOnyx';
 import useParentReportAction from '@hooks/useParentReportAction';
-import usePolicyExpenseChatReportActions from '@hooks/usePolicyExpenseChatReportActions';
 import useReportTransactions from '@hooks/useReportTransactions';
 import {openPersonalBankAccountSetupView} from '@libs/actions/BankAccounts';
 import {completePaymentOnboarding, savePreferredPaymentMethod} from '@libs/actions/IOU';
@@ -75,7 +75,7 @@ function KYCWall({
     const personalDetails = usePersonalDetails();
     const employeeEmail = personalDetails?.[iouReport?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID]?.login ?? '';
     const reportTransactions = useReportTransactions(iouReport?.reportID);
-    const {filteredReportActions} = usePolicyExpenseChatReportActions();
+    const {filteredReportActions} = useAllPolicyExpenseChatReportActions();
     const anchorRef = useRef<HTMLDivElement | View>(null);
     const transferBalanceButtonRef = useRef<HTMLDivElement | View | null>(null);
 
diff --git a/src/hooks/usePolicyExpenseChatReportActions.ts b/src/hooks/useAllPolicyExpenseChatReportActions.ts
similarity index 95%
rename from src/hooks/usePolicyExpenseChatReportActions.ts
rename to src/hooks/useAllPolicyExpenseChatReportActions.ts
index 9dfe41e95b53..c09945a1d79c 100644
--- a/src/hooks/usePolicyExpenseChatReportActions.ts
+++ b/src/hooks/useAllPolicyExpenseChatReportActions.ts
@@ -19,7 +19,7 @@ const policyExpenseChatReportsSelector = (reports: OnyxCollection<Report>) => {
  * Returns all reports that satisfy isPolicyExpenseChat && !isThread (via selector),
  * along with reportActions filtered to only those matching reports.
  */
-function usePolicyExpenseChatReportActions() {
+function useAllPolicyExpenseChatReportActions() {
     const [policyExpenseChatReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {selector: policyExpenseChatReportsSelector});
 
     const policyExpenseChatReportIDs = useMemo(() => {
@@ -51,4 +51,4 @@ function usePolicyExpenseChatReportActions() {
     return {policyExpenseChatReports, filteredReportActions};
 }
 
-export default usePolicyExpenseChatReportActions;
+export default useAllPolicyExpenseChatReportActions;
diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts
index 3d668855e397..ea8f049a4b31 100644
--- a/src/hooks/useSearchBulkActions.ts
+++ b/src/hooks/useSearchBulkActions.ts
@@ -59,6 +59,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
 import type {BillingGraceEndPeriod, Policy, Report, SearchResults, Transaction, TransactionViolations} from '@src/types/onyx';
 import type DeepValueOf from '@src/types/utils/DeepValueOf';
+import useAllPolicyExpenseChatReportActions from './useAllPolicyExpenseChatReportActions';
 import useAllTransactions from './useAllTransactions';
 import useBulkPayOptions from './useBulkPayOptions';
 import useConfirmModal from './useConfirmModal';
@@ -70,7 +71,6 @@ import useNetwork from './useNetwork';
 import useOnyx from './useOnyx';
 import usePermissions from './usePermissions';
 import usePersonalPolicy from './usePersonalPolicy';
-import usePolicyExpenseChatReportActions from './usePolicyExpenseChatReportActions';
 import useSelfDMReport from './useSelfDMReport';
 import useTheme from './useTheme';
 import useThemeStyles from './useThemeStyles';
@@ -111,7 +111,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) {
     const allTransactions = useAllTransactions();
     const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
     const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
-    const {filteredReportActions: policyExpenseChatReportActions} = usePolicyExpenseChatReportActions();
+    const {filteredReportActions: policyExpenseChatReportActions} = useAllPolicyExpenseChatReportActions();
     const [allReportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS);
     const selfDMReport = useSelfDMReport();
     const [lastPaymentMethods] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD);
diff --git a/src/pages/ReportChangeWorkspacePage.tsx b/src/pages/ReportChangeWorkspacePage.tsx
index 43aadd0d7297..1b055fcf981c 100644
--- a/src/pages/ReportChangeWorkspacePage.tsx
+++ b/src/pages/ReportChangeWorkspacePage.tsx
@@ -7,12 +7,12 @@ import ScreenWrapper from '@components/ScreenWrapper';
 import SelectionList from '@components/SelectionList';
 import type {WorkspaceListItemType} from '@components/SelectionList/ListItem/types';
 import UserListItem from '@components/SelectionList/ListItem/UserListItem';
+import useAllPolicyExpenseChatReportActions from '@hooks/useAllPolicyExpenseChatReportActions';
 import useDebouncedState from '@hooks/useDebouncedState';
 import useLocalize from '@hooks/useLocalize';
 import useNetwork from '@hooks/useNetwork';
 import useOnyx from '@hooks/useOnyx';
 import usePermissions from '@hooks/usePermissions';
-import usePolicyExpenseChatReportActions from '@hooks/usePolicyExpenseChatReportActions';
 import useReportIsArchived from '@hooks/useReportIsArchived';
 import useReportTransactions from '@hooks/useReportTransactions';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -75,7 +75,7 @@ function ReportChangeWorkspacePage({report, route}: ReportChangeWorkspacePagePro
     const hasViolations = hasViolationsReportUtils(report?.reportID, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
     const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
     const [userBillingGracePeriods] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END);
-    const {filteredReportActions} = usePolicyExpenseChatReportActions();
+    const {filteredReportActions} = useAllPolicyExpenseChatReportActions();
 
     const selectPolicy = useCallback(
         (policyID?: string) => {
