From 635215be01c98a5675c7a9a3d05390a1d10e3ca6 Mon Sep 17 00:00:00 2001
From: Andrew Rosiclair <arosiclair@expensify.com>
Date: Tue, 10 Jan 2023 16:34:41 -0500
Subject: [PATCH 1/5] scan for report action notifications

---
 src/libs/actions/Report.js |  1 +
 src/libs/actions/User.js   | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index 8842098c6fa2..6c3aa731facb 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -1190,4 +1190,5 @@ export {
     clearIOUError,
     getMaxSequenceNumber,
     subscribeToNewActionEvent,
+    showReportActionNotification,
 };
diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js
index 532e7bb04c65..784a23a51320 100644
--- a/src/libs/actions/User.js
+++ b/src/libs/actions/User.js
@@ -17,6 +17,7 @@ import * as Localize from '../Localize';
 import * as Link from './Link';
 import * as SequentialQueue from '../Network/SequentialQueue';
 import PusherUtils from '../PusherUtils';
+import * as Report from './Report';
 
 let currentUserAccountID = '';
 Onyx.connect({
@@ -256,6 +257,22 @@ function deletePaypalMeAddress() {
     Growl.show(Localize.translateLocal('paymentsPage.deletePayPalSuccess'), CONST.GROWL.SUCCESS, 3000);
 }
 
+function triggerNotifications(onyxUpdates) {
+    _.each(onyxUpdates, (update) => {
+        if (!update.shouldNotify) {
+            return;
+        }
+
+        const reportID = update.key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, '');
+        const reportAction = _.chain(update.value)
+            .values()
+            .compact()
+            .first()
+            .value();
+        Report.showReportActionNotification(reportID, reportAction);
+    });
+}
+
 /**
  * Initialize our pusher subscription to listen for user changes
  */
@@ -271,6 +288,7 @@ function subscribeToUserEvents() {
     PusherUtils.subscribeToPrivateUserChannelEvent(Pusher.TYPE.ONYX_API_UPDATE, currentUserAccountID, (pushJSON) => {
         SequentialQueue.getCurrentRequest().then(() => {
             Onyx.update(pushJSON);
+            triggerNotifications(pushJSON);
         });
     });
 

From baced433f3108a10d120cc83d9ca153c1e9efdeb Mon Sep 17 00:00:00 2001
From: Andrew Rosiclair <arosiclair@expensify.com>
Date: Tue, 10 Jan 2023 16:37:04 -0500
Subject: [PATCH 2/5] don't notify for deleted report actions

---
 src/libs/actions/Report.js | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index 6c3aa731facb..18fa0b6d8290 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -1060,6 +1060,10 @@ function subscribeToNewActionEvent(reportID, callback) {
  * @param {Object} action
  */
 function showReportActionNotification(reportID, action) {
+    if (ReportActionsUtils.isDeletedAction(action)) {
+        return;
+    }
+
     if (!ActiveClientManager.isClientTheLeader()) {
         Log.info('[LOCAL_NOTIFICATION] Skipping notification because this client is not the leader');
         return;
@@ -1152,7 +1156,7 @@ Onyx.connect({
                 newActionSubscriber.callback(isFromCurrentUser, action.reportActionID);
             }
 
-            showReportActionNotification(reportID, action);
+            // showReportActionNotification(reportID, action);
             handledReportActions[reportID] = handledReportActions[reportID] || {};
             handledReportActions[reportID][action.sequenceNumber] = true;
         });

From a775120da59d508bbc12f0fec2f148d549f521d4 Mon Sep 17 00:00:00 2001
From: Andrew Rosiclair <arosiclair@expensify.com>
Date: Tue, 10 Jan 2023 16:38:28 -0500
Subject: [PATCH 3/5] notify ReportActionsView

---
 src/libs/actions/Report.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index 18fa0b6d8290..0d119ced1c30 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -1107,6 +1107,12 @@ function showReportActionNotification(reportID, action) {
             Navigation.navigate(ROUTES.getReportRoute(reportID));
         },
     });
+
+    // Notify the ReportActionsView that a new comment has arrived
+    if (reportID === newActionSubscriber.reportID) {
+        const isFromCurrentUser = action.actorAccountID === currentUserAccountID;
+        newActionSubscriber.callback(isFromCurrentUser, action.reportActionID);
+    }
 }
 
 /**

From f35382563a05816c7c0a1e29434cee19da0de7bc Mon Sep 17 00:00:00 2001
From: Andrew Rosiclair <arosiclair@expensify.com>
Date: Tue, 10 Jan 2023 16:40:08 -0500
Subject: [PATCH 4/5] remove old report action handling

---
 src/libs/actions/Report.js | 46 --------------------------------------
 1 file changed, 46 deletions(-)

diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index 0d119ced1c30..dbcc06fbb0de 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -1,5 +1,4 @@
 import {Linking} from 'react-native';
-import moment from 'moment';
 import _ from 'underscore';
 import lodashGet from 'lodash/get';
 import ExpensiMark from 'expensify-common/lib/ExpensiMark';
@@ -1124,51 +1123,6 @@ function clearIOUError(reportID) {
     Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {errorFields: {iou: null}});
 }
 
-// We are using this map to ensure actions are only handled once
-const handledReportActions = {};
-Onyx.connect({
-    key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
-    initWithStoredValues: false,
-    callback: (actions, key) => {
-        // reportID can be derived from the Onyx key
-        const reportID = key.split('_')[1];
-        if (!reportID) {
-            return;
-        }
-
-        _.each(actions, (action) => {
-            if (lodashGet(handledReportActions, [reportID, action.sequenceNumber])) {
-                return;
-            }
-
-            if (ReportActionsUtils.isDeletedAction(action)) {
-                return;
-            }
-
-            if (!action.created) {
-                return;
-            }
-
-            // If we are past the deadline to notify for this comment don't do it
-            if (moment.utc(moment(action.created).unix() * 1000).isBefore(moment.utc().subtract(10, 'seconds'))) {
-                handledReportActions[reportID] = handledReportActions[reportID] || {};
-                handledReportActions[reportID][action.sequenceNumber] = true;
-                return;
-            }
-
-            // Notify the ReportActionsView that a new comment has arrived
-            if (reportID === newActionSubscriber.reportID) {
-                const isFromCurrentUser = action.actorAccountID === currentUserAccountID;
-                newActionSubscriber.callback(isFromCurrentUser, action.reportActionID);
-            }
-
-            // showReportActionNotification(reportID, action);
-            handledReportActions[reportID] = handledReportActions[reportID] || {};
-            handledReportActions[reportID][action.sequenceNumber] = true;
-        });
-    },
-});
-
 export {
     addComment,
     addAttachment,

From 9cfec573468114476968b588242fa8531f35e086 Mon Sep 17 00:00:00 2001
From: Andrew Rosiclair <arosiclair@expensify.com>
Date: Wed, 11 Jan 2023 16:04:35 -0500
Subject: [PATCH 5/5] add a test for showing notifications for report action
 updates with shouldNotify

---
 tests/actions/ReportTest.js | 42 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js
index 0ab2f7f2f63a..0918dda3ec40 100644
--- a/tests/actions/ReportTest.js
+++ b/tests/actions/ReportTest.js
@@ -3,7 +3,7 @@ import Onyx from 'react-native-onyx';
 import lodashGet from 'lodash/get';
 import moment from 'moment';
 import {
-    beforeEach, beforeAll, afterEach, jest, describe, it, expect,
+    beforeEach, beforeAll, afterEach, describe, it, expect,
 } from '@jest/globals';
 import ONYXKEYS from '../../src/ONYXKEYS';
 import * as Pusher from '../../src/libs/Pusher/pusher';
@@ -19,6 +19,15 @@ import * as User from '../../src/libs/actions/User';
 import * as ReportUtils from '../../src/libs/ReportUtils';
 import DateUtils from '../../src/libs/DateUtils';
 
+jest.mock('../../src/libs/actions/Report', () => {
+    const originalModule = jest.requireActual('../../src/libs/actions/Report');
+
+    return {
+        ...originalModule,
+        showReportActionNotification: jest.fn(),
+    };
+});
+
 describe('actions/Report', () => {
     beforeAll(() => {
         // When using the Pusher mock the act of calling Pusher.isSubscribed will create a
@@ -470,4 +479,35 @@ describe('actions/Report', () => {
         expectedOutput = 'Comment www.google.com  [www.facebook.com](https://www.facebook.com)';
         expect(newCommentMarkdown).toBe(expectedOutput);
     });
+
+    it('should show a notification for report action updates with shouldNotify', () => {
+        const TEST_USER_ACCOUNT_ID = 1;
+        const REPORT_ID = 1;
+        const REPORT_ACTION = {};
+
+        // Setup user and pusher listeners
+        return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID)
+            .then(() => {
+                User.subscribeToUserEvents();
+                return waitForPromisesToResolve();
+            })
+            .then(() => {
+                // Simulate a Pusher Onyx update with a report action with shouldNotify
+                const channel = Pusher.getChannel(`${CONST.PUSHER.PRIVATE_USER_CHANNEL_PREFIX}${TEST_USER_ACCOUNT_ID}${CONFIG.PUSHER.SUFFIX}`);
+                channel.emit(Pusher.TYPE.ONYX_API_UPDATE, [
+                    {
+                        onyxMethod: CONST.ONYX.METHOD.MERGE,
+                        key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${REPORT_ID}`,
+                        value: {
+                            1: REPORT_ACTION,
+                        },
+                        shouldNotify: true,
+                    },
+                ]);
+                return waitForPromisesToResolve();
+            }).then(() => {
+                // Ensure we show a notification for this new report action
+                expect(Report.showReportActionNotification).toBeCalledWith(String(REPORT_ID), REPORT_ACTION);
+            });
+    });
 });
