From 635215be01c98a5675c7a9a3d05390a1d10e3ca6 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair 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 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 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 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 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); + }); + }); });