diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index a7c65df7dd03..96593cf02ebc 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1685,6 +1685,26 @@ function getUserToInviteOption({ return userToInvite; } +/** + * Check whether report has violations + */ +function shouldShowViolations(report: Report, betas: OnyxEntry, transactionViolations: OnyxCollection) { + if (!Permissions.canUseViolations(betas)) { + return false; + } + const {parentReportID, parentReportActionID} = report ?? {}; + const canGetParentReport = parentReportID && parentReportActionID && allReportActions; + if (!canGetParentReport) { + return false; + } + const parentReportActions = allReportActions ? allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? {} : {}; + const parentReportAction = parentReportActions[parentReportActionID] ?? null; + if (!parentReportAction) { + return false; + } + return ReportUtils.shouldDisplayTransactionThreadViolations(report, transactionViolations, parentReportAction); +} + /** * filter options based on specific conditions */ @@ -1791,13 +1811,7 @@ function getOptions( // Filter out all the reports that shouldn't be displayed const filteredReportOptions = options.reports.filter((option) => { const report = option.item; - - const {parentReportID, parentReportActionID} = report ?? {}; - const canGetParentReport = parentReportID && parentReportActionID && allReportActions; - const parentReportActions = allReportActions ? allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? {} : {}; - const parentReportAction = canGetParentReport ? parentReportActions[parentReportActionID] ?? null : null; - const doesReportHaveViolations = - (betas?.includes(CONST.BETAS.VIOLATIONS) && ReportUtils.doesTransactionThreadHaveViolations(report, transactionViolations, parentReportAction)) ?? false; + const doesReportHaveViolations = shouldShowViolations(report, betas, transactionViolations); return ReportUtils.shouldReportBeInOptionList({ report, @@ -2481,6 +2495,7 @@ export { getTaxRatesSection, getFirstKeyForList, getUserToInviteOption, + shouldShowViolations, }; export type {MemberForList, CategorySection, CategoryTreeSection, Options, OptionList, SearchOption, PayeePersonalDetails, Category, Tax, TaxRatesOption, Option, OptionTree}; diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 651b3185f9af..00c6fddb4f6c 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -80,40 +80,49 @@ function getOrderedReportIDs( const allReportsDictValues = Object.values(allReports ?? {}); // Filter out all the reports that shouldn't be displayed - let reportsToDisplay = allReportsDictValues.filter((report) => { + let reportsToDisplay: Array = []; + + allReportsDictValues.forEach((report) => { if (!report) { - return false; + return; } - const parentReportActionsKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`; - const parentReportActions = allReportActions?.[parentReportActionsKey]; const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`] ?? {}; - const parentReportAction = parentReportActions?.find((action) => action && action?.reportActionID === report.parentReportActionID); - const doesReportHaveViolations = !!( - betas?.includes(CONST.BETAS.VIOLATIONS) && - !!parentReportAction && - ReportUtils.doesTransactionThreadHaveViolations(report, transactionViolations, parentReportAction as OnyxEntry) - ); + const doesReportHaveViolations = OptionsListUtils.shouldShowViolations(report, betas ?? [], transactionViolations); const isHidden = report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const isFocused = report.reportID === currentReportId; const allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) ?? {}; const hasErrorsOtherThanFailedReceipt = doesReportHaveViolations || Object.values(allReportErrors).some((error) => error?.[0] !== 'report.genericSmartscanFailureMessage'); + + if (hasErrorsOtherThanFailedReceipt) { + reportsToDisplay.push({ + ...report, + hasErrorsOtherThanFailedReceipt: true, + }); + return; + } + const isSystemChat = ReportUtils.isSystemChat(report); const shouldOverrideHidden = hasErrorsOtherThanFailedReceipt || isFocused || isSystemChat || report.isPinned; + if (isHidden && !shouldOverrideHidden) { - return false; + return; } - return ReportUtils.shouldReportBeInOptionList({ - report, - currentReportId: currentReportId ?? '', - isInFocusMode, - betas, - policies: policies as OnyxCollection, - excludeEmptyChats: true, - doesReportHaveViolations, - includeSelfDM: true, - }); + if ( + ReportUtils.shouldReportBeInOptionList({ + report, + currentReportId: currentReportId ?? '', + isInFocusMode, + betas, + policies: policies as OnyxCollection, + excludeEmptyChats: true, + doesReportHaveViolations, + includeSelfDM: true, + }) + ) { + reportsToDisplay.push(report); + } }); // The LHN is split into four distinct groups, and each group is sorted a little differently. The groups will ALWAYS be in this order: @@ -129,6 +138,7 @@ function getOrderedReportIDs( const draftReports: Array> = []; const nonArchivedReports: Array> = []; const archivedReports: Array> = []; + const errorReports: Array> = []; if (currentPolicyID || policyMemberAccountIDs.length > 0) { reportsToDisplay = reportsToDisplay.filter( @@ -137,7 +147,7 @@ function getOrderedReportIDs( } // There are a few properties that need to be calculated for the report which are used when sorting reports. reportsToDisplay.forEach((reportToDisplay) => { - let report = reportToDisplay as OnyxEntry; + let report = reportToDisplay; if (report) { report = { ...report, @@ -153,6 +163,8 @@ function getOrderedReportIDs( draftReports.push(report); } else if (ReportUtils.isArchivedRoom(report)) { archivedReports.push(report); + } else if (report?.hasErrorsOtherThanFailedReceipt) { + errorReports.push(report); } else { nonArchivedReports.push(report); } @@ -160,6 +172,8 @@ function getOrderedReportIDs( // Sort each group of reports accordingly pinnedAndGBRReports.sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0)); + errorReports.sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0)); + draftReports.sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0)); if (isInDefaultMode) { @@ -180,7 +194,7 @@ function getOrderedReportIDs( // Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID. // The order the arrays are concatenated in matters and will determine the order that the groups are displayed in the sidebar. - const LHNReports = [...pinnedAndGBRReports, ...draftReports, ...nonArchivedReports, ...archivedReports].map((report) => report?.reportID ?? ''); + const LHNReports = [...pinnedAndGBRReports, ...errorReports, ...draftReports, ...nonArchivedReports, ...archivedReports].map((report) => report?.reportID ?? ''); return LHNReports; }