diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 438618944270..2704ceef99ff 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -23,7 +23,7 @@ import { isConciergeChatReport, isDefaultRoom, isReportMessageAttachment, sortReportsByLastVisited, isArchivedRoom, } from '../reportUtils'; import Timers from '../Timers'; -import {dangerouslyGetReportActionsMaxSequenceNumber, isReportMissingActions} from './ReportActions'; +import * as ReportActions from './ReportActions'; import Growl from '../Growl'; import {translateLocal} from '../translate'; @@ -106,7 +106,7 @@ function getUnreadActionCount(report) { // There are unread items if the last one the user has read is less // than the highest sequence number we have - const unreadActionCount = report.reportActionCount - lastReadSequenceNumber; + const unreadActionCount = report.reportActionCount - lastReadSequenceNumber - ReportActions.getDeletedCommentsCount(report.reportID, lastReadSequenceNumber); return Math.max(0, unreadActionCount); } @@ -418,7 +418,7 @@ function setLocalLastRead(reportID, lastReadSequenceNumber) { // Determine the number of unread actions by deducting the last read sequence from the total. If, for some reason, // the last read sequence is higher than the actual last sequence, let's just assume all actions are read - const unreadActionCount = Math.max(reportMaxSequenceNumber - lastReadSequenceNumber, 0); + const unreadActionCount = Math.max(reportMaxSequenceNumber - lastReadSequenceNumber - ReportActions.getDeletedCommentsCount(reportID, lastReadSequenceNumber), 0); // Update the report optimistically. Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { @@ -978,7 +978,7 @@ function fetchAllReports( // data processing by Onyx. const reportIDsWithMissingActions = _.chain(returnedReports) .map(report => report.reportID) - .filter(reportID => isReportMissingActions(reportID, reportMaxSequenceNumbers[reportID])) + .filter(reportID => ReportActions.isReportMissingActions(reportID, reportMaxSequenceNumbers[reportID])) .value(); // Once we have the reports that are missing actions we will find the intersection between the most @@ -1000,7 +1000,7 @@ function fetchAllReports( reportIDs: reportIDsToFetchActions, }); _.each(reportIDsToFetchActions, (reportID) => { - const offset = dangerouslyGetReportActionsMaxSequenceNumber(reportID, false); + const offset = ReportActions.dangerouslyGetReportActionsMaxSequenceNumber(reportID, false); fetchActions(reportID, offset); }); @@ -1117,6 +1117,15 @@ function addAction(reportID, text, file) { }); } +/** + * Get the last read sequence number for a report + * @param {String|Number} reportID + * @return {Number} + */ +function getLastReadSequenceNumber(reportID) { + return lastReadSequenceNumbers[reportID]; +} + /** * Deletes a comment from the report, basically sets it as empty string * @@ -1139,7 +1148,9 @@ function deleteReportComment(reportID, reportAction) { ], }; - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, reportActionsToMerge); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, reportActionsToMerge).then(() => { + setLocalLastRead(reportID, getLastReadSequenceNumber(reportID)); + }); // Try to delete the comment by calling the API API.Report_EditComment({ @@ -1158,8 +1169,9 @@ function deleteReportComment(reportID, reportAction) { ...reportAction, message: oldMessage, }; - - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, reportActionsToMerge); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, reportActionsToMerge).then(() => { + setLocalLastRead(reportID, getLastReadSequenceNumber(reportID)); + }); }); } @@ -1473,4 +1485,5 @@ export { setReportWithDraft, fetchActionsWithLoadingState, createPolicyRoom, + getLastReadSequenceNumber, }; diff --git a/src/libs/actions/ReportActions.js b/src/libs/actions/ReportActions.js index 74fbb2dfb83d..e80bbad61c56 100644 --- a/src/libs/actions/ReportActions.js +++ b/src/libs/actions/ReportActions.js @@ -1,7 +1,9 @@ import _ from 'underscore'; import Onyx from 'react-native-onyx'; +import lodashGet from 'lodash/get'; import ONYXKEYS from '../../ONYXKEYS'; import * as CollectionUtils from '../CollectionUtils'; +import CONST from '../../CONST'; /** * Map of the most recent non-loading sequenceNumber for a reportActions_* key in Onyx by reportID. @@ -17,6 +19,8 @@ import * as CollectionUtils from '../CollectionUtils'; * referenced and not the locally stored reportAction's max sequenceNumber. */ const reportActionsMaxSequenceNumbers = {}; +const reportActions = {}; + Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, callback: (actions, key) => { @@ -26,6 +30,7 @@ Onyx.connect({ const reportID = CollectionUtils.extractCollectionItemID(key); const actionsArray = _.toArray(actions); + reportActions[reportID] = actionsArray; const mostRecentNonLoadingActionIndex = _.findLastIndex(actionsArray, action => !action.loading); const mostRecentAction = actionsArray[mostRecentNonLoadingActionIndex]; if (!mostRecentAction || _.isUndefined(mostRecentAction.sequenceNumber)) { @@ -67,7 +72,31 @@ function isReportMissingActions(reportID, maxKnownSequenceNumber) { || reportActionsMaxSequenceNumbers[reportID] < maxKnownSequenceNumber; } +/** + * Get the count of deleted messages after a sequence number of a report + * @param {Number|String} reportID + * @param {Number} sequenceNumber + * @return {Number} + */ +function getDeletedCommentsCount(reportID, sequenceNumber) { + if (!reportActions[reportID]) { + return 0; + } + + return _.reduce(reportActions[reportID], (deletedMessages, action) => { + if (action.actionName !== CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT || action.sequenceNumber <= sequenceNumber) { + return deletedMessages; + } + + // Empty ADDCOMMENT actions typically mean they have been deleted + const message = _.first(lodashGet(action, 'message', null)); + const html = lodashGet(message, 'html', ''); + return _.isEmpty(html) ? deletedMessages + 1 : deletedMessages; + }, 0); +} + export { isReportMissingActions, dangerouslyGetReportActionsMaxSequenceNumber, + getDeletedCommentsCount, }; diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 84ee7d94afbf..0ad877de81de 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -372,7 +372,7 @@ class ReportActionsView extends React.Component { // Since we want the New marker to remain in place even if newer messages come in, we set it once on mount. // We determine the last read action by deducting the number of unread actions from the total number. // Then, we add 1 because we want the New marker displayed over the oldest unread sequence. - const oldestUnreadSequenceNumber = unreadActionCount === 0 ? 0 : (this.props.report.maxSequenceNumber - unreadActionCount) + 1; + const oldestUnreadSequenceNumber = unreadActionCount === 0 ? 0 : Report.getLastReadSequenceNumber(this.props.report.reportID) + 1; Report.setNewMarkerPosition(this.props.reportID, oldestUnreadSequenceNumber); }