diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 24471b7f0140..6dcc863715d1 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1740,6 +1740,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 */ @@ -1847,13 +1867,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, @@ -2581,6 +2595,7 @@ export { getFirstKeyForList, canCreateOptimisticPersonalDetailOption, 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 ee2807a94c7c..d48404349057 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -82,41 +82,48 @@ 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.shouldDisplayTransactionThreadViolations(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] !== Localize.translateLocal('iou.error.genericSmartscanFailureMessage')); + if (ReportUtils.isOneTransactionThread(report.reportID, report.parentReportID ?? '0')) { + return; + } + 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 ?? '-1', - isInFocusMode, - betas, - policies: policies as OnyxCollection, - excludeEmptyChats: true, - doesReportHaveViolations, - includeSelfDM: true, - }); + if ( + ReportUtils.shouldReportBeInOptionList({ + report, + currentReportId: currentReportId ?? '-1', + 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: @@ -128,10 +135,12 @@ function getOrderedReportIDs( // 4. Archived reports // - Sorted by lastVisibleActionCreated in default (most recent) view mode // - Sorted by reportDisplayName in GSD (focus) view mode + const pinnedAndGBRReports: MiniReport[] = []; const draftReports: MiniReport[] = []; const nonArchivedReports: MiniReport[] = []; const archivedReports: MiniReport[] = []; + const errorReports: MiniReport[] = []; if (currentPolicyID || policyMemberAccountIDs.length > 0) { reportsToDisplay = reportsToDisplay.filter( @@ -140,7 +149,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) => { - const report = reportToDisplay as OnyxEntry; + const report = reportToDisplay; const miniReport: MiniReport = { reportID: report?.reportID, displayName: ReportUtils.getReportName(report), @@ -155,6 +164,8 @@ function getOrderedReportIDs( draftReports.push(miniReport); } else if (ReportUtils.isArchivedRoom(report)) { archivedReports.push(miniReport); + } else if (report?.hasErrorsOtherThanFailedReceipt) { + errorReports.push(miniReport); } else { nonArchivedReports.push(miniReport); } @@ -162,6 +173,7 @@ 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) { @@ -182,7 +194,9 @@ 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 ?? '-1'); + + const LHNReports = [...pinnedAndGBRReports, ...errorReports, ...draftReports, ...nonArchivedReports, ...archivedReports].map((report) => report?.reportID ?? '-1'); + return LHNReports; }