From 0e4759ac1e68832eb5c370f6067ee0a3797236b1 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 23 Jun 2025 15:00:57 +0700
Subject: [PATCH 1/4] fix: next step message on unapproved expense after
 changing WS

---
 src/libs/actions/Report.ts | 62 ++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 30 deletions(-)

diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts
index 1ac9e94007ee..11712cb62f3e 100644
--- a/src/libs/actions/Report.ts
+++ b/src/libs/actions/Report.ts
@@ -5444,42 +5444,44 @@ function buildOptimisticChangePolicyData(report: Report, policyID: string, repor
     updatePolicyIdForReportAndThreads(reportID, policyID, reportIDToThreadsReportIDsMap, optimisticData, failureData);
 
     // We reopen and reassign the report if the report is open/submitted and the manager is not a member of the new policy. This is to prevent the old manager from seeing a report that they can't action on.
+    let newStatusNum = report?.statusNum;
     const isOpenOrSubmitted = isOpenExpenseReport(report) || isProcessingReport(report);
     const managerLogin = PersonalDetailsUtils.getLoginByAccountID(report.managerID ?? CONST.DEFAULT_NUMBER_ID);
     if (isOpenOrSubmitted && managerLogin && !isPolicyMember(managerLogin, policyID)) {
-        optimisticData.push(
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
-                value: {
-                    stateNum: CONST.REPORT.STATE_NUM.OPEN,
-                    statusNum: CONST.REPORT.STATUS_NUM.OPEN,
-                    managerID: getNextApproverAccountID(report, true),
-                },
-            },
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${reportID}`,
-                value: buildNextStep(report, CONST.REPORT.STATUS_NUM.OPEN),
+        newStatusNum = CONST.REPORT.STATUS_NUM.OPEN;
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: {
+                stateNum: CONST.REPORT.STATE_NUM.OPEN,
+                statusNum: CONST.REPORT.STATUS_NUM.OPEN,
+                managerID: getNextApproverAccountID(report, true),
             },
-        );
+        });
 
-        failureData.push(
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
-                value: {
-                    stateNum: report.stateNum,
-                    statusNum: report.statusNum,
-                    managerID: report.managerID,
-                },
-            },
-            {
-                onyxMethod: Onyx.METHOD.MERGE,
-                key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${reportID}`,
-                value: reportNextStep,
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+            value: {
+                stateNum: report.stateNum,
+                statusNum: report.statusNum,
+                managerID: report.managerID,
             },
-        );
+        });
+    }
+
+    if (newStatusNum) {
+        optimisticData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${reportID}`,
+            value: buildNextStep({...report, policyID}, newStatusNum),
+        });
+
+        failureData.push({
+            onyxMethod: Onyx.METHOD.MERGE,
+            key: `${ONYXKEYS.COLLECTION.NEXT_STEP}${reportID}`,
+            value: reportNextStep,
+        });
     }
 
     // 2. If this is a thread, we have to mark the parent report preview action as deleted to properly update the UI

From 3ebe39fcf91d776d62401e1b1323f5359dddcff7 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Thu, 10 Jul 2025 16:56:53 +0700
Subject: [PATCH 2/4] add test

---
 src/libs/actions/Report.ts  |  1 +
 tests/actions/ReportTest.ts | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts
index 40a864eee1a6..aa9c643df2f6 100644
--- a/src/libs/actions/Report.ts
+++ b/src/libs/actions/Report.ts
@@ -5798,6 +5798,7 @@ export {
     addPolicyReport,
     broadcastUserIsLeavingRoom,
     broadcastUserIsTyping,
+    buildOptimisticChangePolicyData,
     clearAddRoomMemberError,
     clearAvatarErrors,
     clearDeleteTransactionNavigateBackUrl,
diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts
index 8a9c196a7ed2..ab8ad7c50508 100644
--- a/tests/actions/ReportTest.ts
+++ b/tests/actions/ReportTest.ts
@@ -1754,4 +1754,23 @@ describe('actions/Report', () => {
             expect(Object.keys(selfDMReportActions ?? {}).length).toBe(3);
         });
     });
+
+    describe('buildOptimisticChangePolicyData', () => {
+        it('should build the optimistic data next step for the change policy data', async () => {
+            const report: OnyxTypes.Report = {
+                ...createRandomReport(1),
+                statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
+                type: CONST.REPORT.TYPE.EXPENSE,
+            };
+            const policyID = '1';
+            const nextStepResult = {
+                type: 'neutral',
+                icon: CONST.NEXT_STEP.ICONS.HOURGLASS,
+                message: [{text: 'Waiting for '}, {text: '', type: 'strong', clickToCopyText: undefined}, {text: ' to '}, {text: 'approve'}, {text: ' %expenses.'}],
+            };
+            const data = Report.buildOptimisticChangePolicyData(report, policyID);
+            const nextStepData = data?.optimisticData.find((item) => item.key === `${ONYXKEYS.COLLECTION.NEXT_STEP}${report.reportID}`);
+            expect(nextStepData?.value).toEqual(nextStepResult);
+        });
+    });
 });

From be4af290f0f23313efec1f18b24d6544e6eeb155 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Thu, 10 Jul 2025 17:17:27 +0700
Subject: [PATCH 3/4] fix ts

---
 tests/actions/ReportTest.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts
index ab8ad7c50508..3245d81a85a5 100644
--- a/tests/actions/ReportTest.ts
+++ b/tests/actions/ReportTest.ts
@@ -1756,7 +1756,7 @@ describe('actions/Report', () => {
     });
 
     describe('buildOptimisticChangePolicyData', () => {
-        it('should build the optimistic data next step for the change policy data', async () => {
+        it('should build the optimistic data next step for the change policy data', () => {
             const report: OnyxTypes.Report = {
                 ...createRandomReport(1),
                 statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,

From cb68573ee04caba9667502efbf7ba94a8c4d26a9 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 15 Jul 2025 03:34:23 +0700
Subject: [PATCH 4/4] add tests

---
 tests/actions/ReportTest.ts | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts
index 536ddbcdbeeb..b0c6628d0131 100644
--- a/tests/actions/ReportTest.ts
+++ b/tests/actions/ReportTest.ts
@@ -8,6 +8,7 @@ import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
 import {getOnboardingMessages} from '@libs/actions/Welcome/OnboardingFlow';
 import {WRITE_COMMANDS} from '@libs/API/types';
 import HttpUtils from '@libs/HttpUtils';
+import {buildNextStep} from '@libs/NextStepUtils';
 import {getOriginalMessage} from '@libs/ReportActionsUtils';
 import CONST from '@src/CONST';
 import OnyxUpdateManager from '@src/libs/actions/OnyxUpdateManager';
@@ -30,6 +31,10 @@ import type {MockFetch} from '../utils/TestHelper';
 import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
 import waitForNetworkPromises from '../utils/waitForNetworkPromises';
 
+jest.mock('@libs/NextStepUtils', () => ({
+    buildNextStep: jest.fn(),
+}));
+
 jest.mock('@libs/ReportUtils', () => {
     const originalModule = jest.requireActual<Report>('@libs/ReportUtils');
     return {
@@ -1755,6 +1760,19 @@ describe('actions/Report', () => {
         });
     });
 
+    describe('buildOptimisticChangePolicyData', () => {
+        it('should build the optimistic data next step for the change policy data', () => {
+            const report: OnyxTypes.Report = {
+                ...createRandomReport(1),
+                statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
+                type: CONST.REPORT.TYPE.EXPENSE,
+            };
+            const policyID = '1';
+            Report.buildOptimisticChangePolicyData(report, policyID);
+            expect(buildNextStep).toHaveBeenCalledWith(report, CONST.REPORT.STATUS_NUM.SUBMITTED);
+        });
+    });
+
     describe('searchInServer', () => {
         it('should return the same result with or without uppercase input.', () => {
             Report.searchInServer('test');
