diff --git a/src/libs/ReportActionsUtils.js b/src/libs/ReportActionsUtils.js index b4c4009d6650..75c0cccf0dff 100644 --- a/src/libs/ReportActionsUtils.js +++ b/src/libs/ReportActionsUtils.js @@ -158,26 +158,64 @@ function getLastVisibleMessageText(reportID, actionsToMerge = {}) { } /** - * A helper method to filter out report actions keyed by sequenceNumbers. + * Checks if a reportAction is deprecated. * - * @param {Object} reportActions - * @returns {Array} + * @param {Object} reportAction + * @param {String} key + * @returns {Boolean} */ -function filterOutDeprecatedReportActions(reportActions) { +function isReportActionDeprecated(reportAction, key) { + if (!reportAction) { + return true; + } + // HACK ALERT: We're temporarily filtering out any reportActions keyed by sequenceNumber // to prevent bugs during the migration from sequenceNumber -> reportActionID - return _.filter(reportActions, (reportAction, key) => { - if (!reportAction) { - return false; - } + if (String(reportAction.sequenceNumber) === key) { + Log.info('Front-end filtered out reportAction keyed by sequenceNumber!', false, reportAction); + return true; + } - if (String(reportAction.sequenceNumber) === key) { - Log.info('Front-end filtered out reportAction keyed by sequenceNumber!', false, reportAction); - return false; - } + return false; +} - return true; - }); +/** + * Checks if a reportAction is fit for display, meaning that it's not deprecated, is of a valid + * and supported type, it's not deleted and also not closed. + * + * @param {Object} reportAction + * @param {String} key + * @returns {Boolean} + */ +function shouldReportActionBeVisible(reportAction, key) { + if (isReportActionDeprecated(reportAction, key)) { + return false; + } + + // Filter out any unsupported reportAction types + if (!_.has(CONST.REPORT.ACTIONS.TYPE, reportAction.actionName) && !_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), reportAction.actionName)) { + return false; + } + + // Ignore closed action here since we're already displaying a footer that explains why the report was closed + if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { + return false; + } + + // All other actions are displayed except deleted, non-pending actions + const isDeleted = isDeletedAction(reportAction); + const isPending = !_.isEmpty(reportAction.pendingAction); + return !isDeleted || isPending; +} + +/** + * A helper method to filter out report actions keyed by sequenceNumbers. + * + * @param {Object} reportActions + * @returns {Array} + */ +function filterOutDeprecatedReportActions(reportActions) { + return _.filter(reportActions, (reportAction, key) => !isReportActionDeprecated(reportAction, key)); } /** @@ -190,24 +228,8 @@ function filterOutDeprecatedReportActions(reportActions) { * @returns {Array} */ function getSortedReportActionsForDisplay(reportActions) { - const filteredReportActions = filterOutDeprecatedReportActions(reportActions); - const sortedReportActions = getSortedReportActions(filteredReportActions, true); - return _.filter(sortedReportActions, (reportAction) => { - // Filter out any unsupported reportAction types - if (!_.has(CONST.REPORT.ACTIONS.TYPE, reportAction.actionName) && !_.contains(_.values(CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG), reportAction.actionName)) { - return false; - } - - // Ignore closed action here since we're already displaying a footer that explains why the report was closed - if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED) { - return false; - } - - // All other actions are displayed except deleted, non-pending actions - const isDeleted = isDeletedAction(reportAction); - const isPending = !_.isEmpty(reportAction.pendingAction); - return !isDeleted || isPending; - }); + const filteredReportActions = _.filter(reportActions, (reportAction, key) => shouldReportActionBeVisible(reportAction, key)); + return getSortedReportActions(filteredReportActions, true); } /** @@ -250,6 +272,8 @@ export { getLastVisibleMessageText, getMostRecentIOURequestActionID, isDeletedAction, + shouldReportActionBeVisible, + isReportActionDeprecated, isConsecutiveActionMadeByPreviousActor, getSortedReportActionsForDisplay, getLastClosedReportAction, diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 4fddf6a35691..061bc0a837a7 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -5,6 +5,7 @@ import lodashOrderBy from 'lodash/orderBy'; import Str from 'expensify-common/lib/str'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from './ReportUtils'; +import * as ReportActionsUtils from './ReportActionsUtils'; import * as Localize from './Localize'; import CONST from '../CONST'; import * as OptionsListUtils from './OptionsListUtils'; @@ -52,6 +53,7 @@ Onyx.connect({ callback: val => betas = val, }); +const visibleReportActionItems = {}; const lastReportActions = {}; const reportActions = {}; Onyx.connect({ @@ -61,7 +63,16 @@ Onyx.connect({ return; } const reportID = CollectionUtils.extractCollectionItemID(key); - lastReportActions[reportID] = _.last(_.toArray(actions)); + + const actionsArray = _.toArray(actions); + lastReportActions[reportID] = _.last(actionsArray); + + // The report is only visible if it is the last action not deleted that + // does not match a closed or created state. + const reportActionsForDisplay = _.filter(actionsArray, (reportAction, actionKey) => (ReportActionsUtils.shouldReportActionBeVisible(reportAction, actionKey) + && (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED))); + visibleReportActionItems[reportID] = _.first(ReportActionsUtils.getSortedReportActions(reportActionsForDisplay, true)); + reportActions[key] = actions; }, }); @@ -251,10 +262,11 @@ function getOptionData(reportID) { } // If the last actor's details are not currently saved in Onyx Collection, - // then try to get that from the last report action. + // then try to get that from the last report action if that action is valid + // to get data from. let lastActorDetails = personalDetails[report.lastActorEmail] || null; - if (!lastActorDetails && lastReportActions[report.reportID] && lastReportActions[report.reportID].actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED) { - const lastActorDisplayName = lodashGet(lastReportActions[report.reportID], 'person[0].text'); + if (!lastActorDetails && visibleReportActionItems[report.reportID]) { + const lastActorDisplayName = lodashGet(visibleReportActionItems[report.reportID], 'person[0].text'); lastActorDetails = lastActorDisplayName ? { displayName: lastActorDisplayName, login: report.lastActorEmail,