Skip to content
Merged
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
86 changes: 60 additions & 26 deletions src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@

const visibleReportActionItems: ReportActions = {};
let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
Onyx.connect({

Check warning on line 144 in src/libs/SidebarUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
allPersonalDetails = value ?? {};
Expand All @@ -149,7 +149,7 @@
});

let allReports: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 152 in src/libs/SidebarUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -157,7 +157,7 @@
},
});

Onyx.connect({

Check warning on line 160 in src/libs/SidebarUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
callback: (actions, key) => {
if (!actions || !key) {
Expand Down Expand Up @@ -369,28 +369,60 @@
const nonArchivedReports: MiniReport[] = [];
const archivedReports: MiniReport[] = [];

// There are a few properties that need to be calculated for the report which are used when sorting reports.
for (const report of Object.values(reportsToDisplay)) {
// Pre-calculate report names and other properties to avoid repeated calculations
const reportValues = Object.values(reportsToDisplay);
const precomputedReports: Array<{
miniReport: MiniReport;
isPinned: boolean;
hasErrors: boolean;
hasDraft: boolean;
isArchived: boolean;
requiresAttention: boolean;
}> = [];

// Single pass to precompute all required data
for (const report of reportValues) {
if (!report) {
continue;
}

const reportID = report.reportID;
const displayName = getReportName(report);
const miniReport: MiniReport = {
reportID,
displayName,
lastVisibleActionCreated: report.lastVisibleActionCreated,
};

const isPinned = !!report.isPinned;
const requiresAttention = !!reportAttributes?.[reportID]?.requiresAttention;
const hasErrors = !!report.hasErrorsOtherThanFailedReceipt;
const hasDraft = reportID ? !!draftReportComments?.[reportID] : false;
const hasDraft = !!reportID && !!draftReportComments?.[reportID];
const reportNameValuePairsKey = `${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`;
const rNVPs = reportNameValuePairs?.[reportNameValuePairsKey];
const isArchived = isArchivedNonExpenseReport(report, !!rNVPs?.private_isArchived);

precomputedReports.push({
miniReport,
isPinned,
hasErrors,
hasDraft,
isArchived,
requiresAttention,
});
}

const miniReport: MiniReport = {
reportID,
displayName: getReportName(report),
lastVisibleActionCreated: report.lastVisibleActionCreated,
};
// Single pass to categorize reports
for (const data of precomputedReports) {
const {miniReport, isPinned, requiresAttention, hasErrors, hasDraft, isArchived} = data;

if (isPinned || (reportID && reportAttributes?.[reportID]?.requiresAttention)) {
if (isPinned || requiresAttention) {
pinnedAndGBRReports.push(miniReport);
} else if (hasErrors) {
errorReports.push(miniReport);
} else if (hasDraft) {
draftReports.push(miniReport);
} else if (isArchivedNonExpenseReport(report, !!rNVPs?.private_isArchived)) {
} else if (isArchived) {
archivedReports.push(miniReport);
} else {
nonArchivedReports.push(miniReport);
Expand Down Expand Up @@ -429,30 +461,32 @@
} {
const {pinnedAndGBRReports, errorReports, draftReports, nonArchivedReports, archivedReports} = categories;

// Create comparison functions once to avoid recreating them in sort
const compareDisplayNames = (a: MiniReport, b: MiniReport) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0);

const compareDatesDesc = (a: MiniReport, b: MiniReport) =>
a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0;

const compareNonArchivedDefault = (a: MiniReport, b: MiniReport) => {
const compareDates = compareDatesDesc(a, b);
return compareDates !== 0 ? compareDates : compareDisplayNames(a, b);
};

// Sort each group of reports accordingly
const sortedPinnedAndGBRReports = [...pinnedAndGBRReports].sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0));
const sortedErrorReports = [...errorReports].sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0));
const sortedDraftReports = [...draftReports].sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0));
const sortedPinnedAndGBRReports = pinnedAndGBRReports.toSorted(compareDisplayNames);
const sortedErrorReports = errorReports.toSorted(compareDisplayNames);
const sortedDraftReports = draftReports.toSorted(compareDisplayNames);

let sortedNonArchivedReports: MiniReport[];
let sortedArchivedReports: MiniReport[];

if (isInDefaultMode) {
sortedNonArchivedReports = [...nonArchivedReports].sort((a, b) => {
const compareDates = a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0;
if (compareDates) {
return compareDates;
}
const compareDisplayNames = a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0;
return compareDisplayNames;
});
sortedNonArchivedReports = nonArchivedReports.toSorted(compareNonArchivedDefault);
// For archived reports ensure that most recent reports are at the top by reversing the order
sortedArchivedReports = [...archivedReports].sort((a, b) =>
a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0,
);
sortedArchivedReports = archivedReports.toSorted(compareDatesDesc);
} else {
sortedNonArchivedReports = [...nonArchivedReports].sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0));
sortedArchivedReports = [...archivedReports].sort((a, b) => (a?.displayName && b?.displayName ? localeCompare(a.displayName, b.displayName) : 0));
sortedNonArchivedReports = nonArchivedReports.toSorted(compareDisplayNames);
sortedArchivedReports = archivedReports.toSorted(compareDisplayNames);
}

return {
Expand Down
Loading