Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 11 additions & 46 deletions src/libs/actions/Report.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -1060,6 +1059,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;
Expand Down Expand Up @@ -1103,6 +1106,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);
}
}

/**
Expand All @@ -1114,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,
Expand Down Expand Up @@ -1190,4 +1154,5 @@ export {
clearIOUError,
getMaxSequenceNumber,
subscribeToNewActionEvent,
showReportActionNotification,
};
18 changes: 18 additions & 0 deletions src/libs/actions/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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, '');
Comment thread
Julesssss marked this conversation as resolved.
const reportAction = _.chain(update.value)
.values()
.compact()
.first()
.value();
Report.showReportActionNotification(reportID, reportAction);
});
}

/**
* Initialize our pusher subscription to listen for user changes
*/
Expand All @@ -271,6 +288,7 @@ function subscribeToUserEvents() {
PusherUtils.subscribeToPrivateUserChannelEvent(Pusher.TYPE.ONYX_API_UPDATE, currentUserAccountID, (pushJSON) => {
SequentialQueue.getCurrentRequest().then(() => {
Onyx.update(pushJSON);
triggerNotifications(pushJSON);
});
});

Expand Down
42 changes: 41 additions & 1 deletion tests/actions/ReportTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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
Expand Down Expand Up @@ -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);
});
});
});