diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 18b0f424ef6b..d6d8e8bcbec5 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -194,6 +194,7 @@ type GetReportSectionsParams = { bankAccountList: OnyxEntry; reportActions?: Record; allReportMetadata: OnyxCollection; + queryJSON?: SearchQueryJSON; }; type GetTransactionSectionsParams = { @@ -1393,6 +1394,7 @@ function buildLastExportedActionByReportIDMap(data: OnyxTypes.SearchResults['dat function shouldShowYear( data: TransactionListItemType[] | TransactionGroupListItemType[] | TaskListItemType[] | OnyxTypes.SearchResults['data'], checkOnlyReports = false, + precomputedLastExportedMap?: Map, ): ShouldShowYearResult { const result: ShouldShowYearResult = { shouldShowYearCreated: false, @@ -1450,7 +1452,7 @@ function shouldShowYear( return result; } - const lastExportedActionByReportID = buildLastExportedActionByReportIDMap(data); + const lastExportedActionByReportID = precomputedLastExportedMap ?? buildLastExportedActionByReportIDMap(data); for (const key of Object.keys(data)) { if (!checkOnlyReports && isTransactionEntry(key)) { @@ -1670,7 +1672,8 @@ function getTransactionsSections({ cardFeeds, }: GetTransactionSectionsParams): [TransactionListItemType[], number] { const shouldShowMerchant = getShouldShowMerchant(data); - const {shouldShowYearCreated, shouldShowYearSubmitted, shouldShowYearApproved, shouldShowYearPosted, shouldShowYearExported} = shouldShowYear(data); + const lastExportedActionByReportID = buildLastExportedActionByReportIDMap(data); + const {shouldShowYearCreated, shouldShowYearSubmitted, shouldShowYearApproved, shouldShowYearPosted, shouldShowYearExported} = shouldShowYear(data, false, lastExportedActionByReportID); const {shouldShowAmountInWideColumn, shouldShowTaxAmountInWideColumn} = getWideAmountIndicators(data); // Pre-filter transaction keys to avoid repeated checks @@ -1684,8 +1687,6 @@ function getTransactionsSections({ const transactionsSections: TransactionListItemType[] = []; - const lastExportedActionByReportID = buildLastExportedActionByReportIDMap(data); - // Use the provided queryJSON if available, otherwise fall back to getCurrentSearchQueryJSON() const currentQueryJSON = queryJSON ?? getCurrentSearchQueryJSON(); @@ -1850,6 +1851,7 @@ function getActions( bankAccountList: OnyxEntry, reportMetadata: OnyxEntry, reportActions: OnyxTypes.ReportAction[] = [], + precomputedTransactionsForReport?: OnyxTypes.Transaction[], ): SearchTransactionAction[] { const isTransaction = isTransactionEntry(key); const report = getReportFromKey(data, key); @@ -1888,7 +1890,7 @@ function getActions( const allActions: SearchTransactionAction[] = []; let allReportTransactions: OnyxTypes.Transaction[]; if (isReportEntry(key)) { - allReportTransactions = getTransactionsForReport(data, report.reportID); + allReportTransactions = precomputedTransactionsForReport ?? getTransactionsForReport(data, report.reportID); } else { allReportTransactions = transaction ? [transaction] : []; } @@ -1968,6 +1970,7 @@ function getTaskSections( formatPhoneNumber: LocaleContextProps['formatPhoneNumber'], archivedReportsIDList?: ArchivedReportsIDSet, ): [TaskListItemType[], number] { + const {shouldShowYearCreated} = shouldShowYear(data); const tasks = Object.keys(data) .filter(isReportEntry) // Ensure that the reports that were passed are tasks, and not some other @@ -1985,7 +1988,6 @@ function getTaskSections( const report = getReportOrDraftReport(taskItem.reportID) ?? taskItem; const parentReport = getReportOrDraftReport(taskItem.parentReportID) ?? data[`${ONYXKEYS.COLLECTION.REPORT}${taskItem.parentReportID}`]; - const {shouldShowYearCreated} = shouldShowYear(data); const reportName = StringUtils.lineBreaksToSpaces(Parser.htmlToText(taskItem.reportName)); const description = StringUtils.lineBreaksToSpaces(Parser.htmlToText(taskItem.description)); @@ -2171,8 +2173,10 @@ function getReportSections({ bankAccountList, reportActions = {}, allReportMetadata, + queryJSON, }: GetReportSectionsParams): [TransactionGroupListItemType[], number] { const shouldShowMerchant = getShouldShowMerchant(data); + const lastExportedActionByReportID = buildLastExportedActionByReportIDMap(data); const { shouldShowYearCreated: shouldShowYearCreatedTransaction, @@ -2180,22 +2184,52 @@ function getReportSections({ shouldShowYearApproved: shouldShowYearApprovedTransaction, shouldShowYearPosted: shouldShowYearPostedTransaction, shouldShowYearExported: shouldShowYearExportedTransaction, - } = shouldShowYear(data); + } = shouldShowYear(data, false, lastExportedActionByReportID); const {shouldShowAmountInWideColumn, shouldShowTaxAmountInWideColumn} = getWideAmountIndicators(data); const {moneyRequestReportActionsByTransactionID, holdReportActionsByTransactionID} = createReportActionsLookupMaps(data); // Get violations - optimize by using a Map for faster lookups const allViolations = getViolations(data); - const queryJSON = getCurrentSearchQueryJSON(); + const currentQueryJSON = queryJSON ?? getCurrentSearchQueryJSON(); const reportIDToTransactions: Record = {}; + // Build transactionsByReportID map and compute report-level year flags in a single pass for performance reasons. + const transactionsByReportID = new Map(); + let shouldShowYearCreatedReport = false; + let shouldShowYearSubmittedReport = false; + let shouldShowYearApprovedReport = false; + let shouldShowYearExportedReport = false; + const {reportKeys, transactionKeys} = Object.keys(data).reduce( (acc, key) => { if (isReportEntry(key)) { acc.reportKeys.push(key); + const item = data[key]; + if (!shouldShowYearCreatedReport && item.created && DateUtils.doesDateBelongToAPastYear(item.created)) { + shouldShowYearCreatedReport = true; + } + if (!shouldShowYearSubmittedReport && item.submitted && DateUtils.doesDateBelongToAPastYear(item.submitted)) { + shouldShowYearSubmittedReport = true; + } + if (!shouldShowYearApprovedReport && item.approved && DateUtils.doesDateBelongToAPastYear(item.approved)) { + shouldShowYearApprovedReport = true; + } + const exportedAction = lastExportedActionByReportID.get(item.reportID); + if (!shouldShowYearExportedReport && exportedAction?.created && DateUtils.doesDateBelongToAPastYear(exportedAction.created)) { + shouldShowYearExportedReport = true; + } } else if (isTransactionEntry(key)) { acc.transactionKeys.push(key); + const transaction = data[key]; + if (transaction.reportID) { + const existing = transactionsByReportID.get(transaction.reportID); + if (existing) { + existing.push(transaction); + } else { + transactionsByReportID.set(transaction.reportID, [transaction]); + } + } } return acc; }, @@ -2203,14 +2237,6 @@ function getReportSections({ ); const orderedKeys: string[] = [...reportKeys, ...transactionKeys]; - const { - shouldShowYearCreated: shouldShowYearCreatedReport, - shouldShowYearSubmitted: shouldShowYearSubmittedReport, - shouldShowYearApproved: shouldShowYearApprovedReport, - shouldShowYearExported: shouldShowYearExportedReport, - } = shouldShowYear(data, true); - - const lastExportedActionByReportID = buildLastExportedActionByReportIDMap(data); for (const key of orderedKeys) { if (isReportEntry(key) && (data[key].type === CONST.REPORT.TYPE.IOU || data[key].type === CONST.REPORT.TYPE.EXPENSE || data[key].type === CONST.REPORT.TYPE.INVOICE)) { @@ -2223,9 +2249,9 @@ function getReportSections({ let shouldShow = true; const isActionLoading = isActionLoadingSet?.has(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportItem.reportID}`); - if (queryJSON && !isActionLoading) { - if (queryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE) { - const status = queryJSON.status; + if (currentQueryJSON && !isActionLoading) { + if (currentQueryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE) { + const status = currentQueryJSON.status; if (Array.isArray(status)) { shouldShow = status.some((expenseStatus) => { @@ -2241,7 +2267,8 @@ function getReportSections({ const reportPendingAction = reportItem?.pendingAction ?? reportItem?.pendingFields?.preview; const shouldShowBlankTo = !reportItem || isOpenExpenseReport(reportItem); const reportMetadata = allReportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportItem.reportID}`] ?? {}; - const allActions = getActions(data, allViolations, key, currentSearch, currentUserEmail, currentAccountID, bankAccountList, reportMetadata, actions); + const allReportTransactions = transactionsByReportID.get(reportItem.reportID) ?? []; + const allActions = getActions(data, allViolations, key, currentSearch, currentUserEmail, currentAccountID, bankAccountList, reportMetadata, actions, allReportTransactions); const fromDetails = data.personalDetailsList?.[reportItem.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? @@ -2253,8 +2280,6 @@ function getReportSections({ const formattedTo = !shouldShowBlankTo ? formatPhoneNumber(getDisplayNameOrDefault(toDetails)) : ''; const formattedStatus = getReportStatusTranslation({stateNum: reportItem.stateNum, statusNum: reportItem.statusNum, translate}); - - const allReportTransactions = getTransactionsForReport(data, reportItem.reportID); const policyFromKey = getPolicyFromKey(data, reportItem); const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${reportItem?.policyID ?? String(CONST.DEFAULT_NUMBER_ID)}`] ?? policyFromKey; @@ -2281,6 +2306,7 @@ function getReportSections({ ); const {totalDisplaySpend, nonReimbursableSpend, reimbursableSpend} = getMoneyRequestSpendBreakdown(reportItem); + reportIDToTransactions[reportKey] = { ...reportItem, action: allActions.at(0) ?? CONST.SEARCH.ACTION_TYPES.VIEW, @@ -2374,7 +2400,6 @@ function getReportSections({ } const reportIDToTransactionsValues = Object.values(reportIDToTransactions); - return [reportIDToTransactionsValues, reportIDToTransactionsValues.length]; } @@ -2839,6 +2864,7 @@ function getSections({ bankAccountList, reportActions, allReportMetadata, + queryJSON, }); }