Skip to content
Open
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7182,6 +7182,7 @@ const CONST = {
VIEW: {
TABLE: 'table',
BAR: 'bar',
LINE: 'line',
Comment on lines 7182 to +7185

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid exposing unimplemented line chart view

Adding LINE to CONST.SEARCH.VIEW makes “Line” appear in the view picker because getViewOptions maps Object.values(CONST.SEARCH.VIEW). However, chart rendering only supports bar charts (shouldShowChartView checks view === BAR, and SearchChartView maps only BAR), so selecting “Line” will silently fall back to the table view instead of a line chart. This is a user-visible regression introduced by this commit: users can now choose a view that is not implemented. Consider keeping LINE out of the selectable views until a line chart renderer is wired up or gating it behind a feature flag.

Useful? React with 👍 / 👎.

},
SYNTAX_FILTER_KEYS: {
TYPE: 'type',
Expand Down Expand Up @@ -7398,6 +7399,7 @@ const CONST = {
TOP_SPENDERS: 'topSpenders',
TOP_CATEGORIES: 'topCategories',
TOP_MERCHANTS: 'topMerchants',
SPEND_OVER_TIME: 'spendOverTime',
},
GROUP_PREFIX: 'group_',
ANIMATION: {
Expand Down
3 changes: 2 additions & 1 deletion src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7090,7 +7090,7 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard
allMatchingItemsSelected: 'Alle passenden Elemente ausgewählt',
},
topSpenders: 'Top-Ausgaben',
view: {label: 'Ansehen', table: 'Tabelle', bar: 'Bar'},
view: {label: 'Ansehen', table: 'Tabelle', bar: 'Bar', line: 'Zeile'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'Von',
[CONST.SEARCH.GROUP_BY.CARD]: 'Karten',
Expand All @@ -7103,6 +7103,7 @@ Fordere Spesendetails wie Belege und Beschreibungen an, lege Limits und Standard
[CONST.SEARCH.GROUP_BY.YEAR]: 'Jahre',
[CONST.SEARCH.GROUP_BY.QUARTER]: 'Quartale',
},
spendOverTime: 'Ausgaben im Zeitverlauf',
},
genericErrorPage: {
title: 'Oh je, etwas ist schiefgelaufen!',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6913,6 +6913,7 @@ const translations = {
savedSearchesMenuItemTitle: 'Saved',
topCategories: 'Top categories',
topMerchants: 'Top merchants',
spendOverTime: 'Spend over time',
groupedExpenses: 'grouped expenses',
bulkActions: {
approve: 'Approve',
Expand Down Expand Up @@ -7002,6 +7003,7 @@ const translations = {
label: 'View',
table: 'Table',
bar: 'Bar',
line: 'Line',
},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'From',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6659,11 +6659,12 @@ ${amount} para ${merchant} - ${date}`,
unapprovedCard: 'Tarjeta no aprobada',
reconciliation: 'Conciliación',
topSpenders: 'Mayores gastadores',
view: {label: 'Ver', table: 'Tabla', bar: 'Barra'},
view: {label: 'Ver', table: 'Tabla', bar: 'Barra', line: 'Línea'},
saveSearch: 'Guardar búsqueda',
savedSearchesMenuItemTitle: 'Guardadas',
topCategories: 'Categorías principales',
topMerchants: 'Principales comerciantes',
spendOverTime: 'Evolución de gastos',
searchName: 'Nombre de la búsqueda',
deleteSavedSearch: 'Eliminar búsqueda guardada',
deleteSavedSearchConfirm: '¿Estás seguro de que quieres eliminar esta búsqueda?',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7102,7 +7102,7 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin
allMatchingItemsSelected: 'Tous les éléments correspondants sont sélectionnés',
},
topSpenders: 'Plus gros dépensiers',
view: {label: 'Afficher', table: 'Tableau', bar: 'Barre'},
view: {label: 'Afficher', table: 'Tableau', bar: 'Barre', line: 'Ligne'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'De',
[CONST.SEARCH.GROUP_BY.CARD]: 'Cartes',
Expand All @@ -7115,6 +7115,7 @@ Exigez des informations de dépense comme les reçus et les descriptions, défin
[CONST.SEARCH.GROUP_BY.YEAR]: 'Années',
[CONST.SEARCH.GROUP_BY.QUARTER]: 'Trimestres',
},
spendOverTime: 'Dépenses au fil du temps',
},
genericErrorPage: {
title: 'Oh oh, quelque chose s’est mal passé !',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7079,7 +7079,7 @@ Richiedi dettagli di spesa come ricevute e descrizioni, imposta limiti e valori
allMatchingItemsSelected: 'Tutti gli elementi corrispondenti selezionati',
},
topSpenders: 'Maggiori spenditori',
view: {label: 'Visualizza', table: 'Tabella', bar: 'Bar'},
view: {label: 'Visualizza', table: 'Tabella', bar: 'Bar', line: 'Riga'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'Da',
[CONST.SEARCH.GROUP_BY.CARD]: 'Carte',
Expand All @@ -7092,6 +7092,7 @@ Richiedi dettagli di spesa come ricevute e descrizioni, imposta limiti e valori
[CONST.SEARCH.GROUP_BY.YEAR]: 'Anni',
[CONST.SEARCH.GROUP_BY.QUARTER]: 'Trimestri',
},
spendOverTime: 'Spesa nel tempo',
},
genericErrorPage: {
title: 'Uh-oh, qualcosa è andato storto!',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7017,7 +7017,7 @@ ${reportName}
allMatchingItemsSelected: '一致する項目をすべて選択済み',
},
topSpenders: 'トップ支出者',
view: {label: '表示', table: 'テーブル', bar: 'バー'},
view: {label: '表示', table: 'テーブル', bar: 'バー', line: '行'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: '差出人',
[CONST.SEARCH.GROUP_BY.CARD]: 'カード',
Expand All @@ -7030,6 +7030,7 @@ ${reportName}
[CONST.SEARCH.GROUP_BY.YEAR]: '年',
[CONST.SEARCH.GROUP_BY.QUARTER]: '四半期',
},
spendOverTime: '時間別支出',
},
genericErrorPage: {
title: 'おっと、問題が発生しました!',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7062,7 +7062,7 @@ Vraag verplichte uitgavedetails zoals bonnetjes en beschrijvingen, stel limieten
allMatchingItemsSelected: 'Alle overeenkomende items geselecteerd',
},
topSpenders: 'Grootste uitgaven',
view: {label: 'Bekijken', table: 'Tabel', bar: 'Bar'},
view: {label: 'Bekijken', table: 'Tabel', bar: 'Bar', line: 'Regel'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'Van',
[CONST.SEARCH.GROUP_BY.CARD]: 'Kaarten',
Expand All @@ -7075,6 +7075,7 @@ Vraag verplichte uitgavedetails zoals bonnetjes en beschrijvingen, stel limieten
[CONST.SEARCH.GROUP_BY.YEAR]: 'Jaren',
[CONST.SEARCH.GROUP_BY.QUARTER]: 'Kwartalen',
},
spendOverTime: 'Uitgaven in de tijd',
},
genericErrorPage: {
title: 'O jee, er is iets misgegaan!',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7049,7 +7049,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i
allMatchingItemsSelected: 'Wybrano wszystkie pasujące elementy',
},
topSpenders: 'Najwięksi wydający',
view: {label: 'Zobacz', table: 'Tabela', bar: 'Pasek'},
view: {label: 'Zobacz', table: 'Tabela', bar: 'Pasek', line: 'Linia'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'Od',
[CONST.SEARCH.GROUP_BY.CARD]: 'Karty',
Expand All @@ -7062,6 +7062,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i
[CONST.SEARCH.GROUP_BY.YEAR]: 'Lata',
[CONST.SEARCH.GROUP_BY.QUARTER]: 'Kwartały',
},
spendOverTime: 'Wydatki w czasie',
},
genericErrorPage: {
title: 'Ups, coś poszło nie tak!',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7051,7 +7051,7 @@ Exija detalhes de despesas como recibos e descrições, defina limites e padrõe
allMatchingItemsSelected: 'Todos os itens correspondentes selecionados',
},
topSpenders: 'Maiores gastadores',
view: {label: 'Ver', table: 'Tabela', bar: 'Bar'},
view: {label: 'Ver', table: 'Tabela', bar: 'Bar', line: 'Linha'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: 'De',
[CONST.SEARCH.GROUP_BY.CARD]: 'Cartões',
Expand All @@ -7064,6 +7064,7 @@ Exija detalhes de despesas como recibos e descrições, defina limites e padrõe
[CONST.SEARCH.GROUP_BY.YEAR]: 'Anos',
[CONST.SEARCH.GROUP_BY.QUARTER]: 'Trimestres',
},
spendOverTime: 'Gastos ao longo do tempo',
},
genericErrorPage: {
title: 'Opa, algo deu errado!',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6896,7 +6896,7 @@ ${reportName}
allMatchingItemsSelected: '已选择所有匹配的项目',
},
topSpenders: '最高支出者',
view: {label: '查看', table: '表格', bar: '栏'},
view: {label: '查看', table: '表格', bar: '栏', line: '行'},
chartTitles: {
[CONST.SEARCH.GROUP_BY.FROM]: '来自',
[CONST.SEARCH.GROUP_BY.CARD]: '卡片',
Expand All @@ -6909,6 +6909,7 @@ ${reportName}
[CONST.SEARCH.GROUP_BY.YEAR]: '年',
[CONST.SEARCH.GROUP_BY.QUARTER]: '季度',
},
spendOverTime: '一段时间内的支出',
},
genericErrorPage: {
title: '哎呀,出错了!',
Expand Down
38 changes: 37 additions & 1 deletion src/libs/SearchUIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,33 @@ function getSuggestedSearches(
CONST.SEARCH.GROUP_BY.MERCHANT,
CONST.SEARCH.TOP_SEARCH_LIMIT,
),
[CONST.SEARCH.SEARCH_KEYS.SPEND_OVER_TIME]: {
key: CONST.SEARCH.SEARCH_KEYS.SPEND_OVER_TIME,
translationPath: 'search.spendOverTime',
type: CONST.SEARCH.DATA_TYPES.EXPENSE,
icon: 'Receipt',
searchQuery: buildQueryStringFromFilterFormValues(
{
type: CONST.SEARCH.DATA_TYPES.EXPENSE,
groupBy: CONST.SEARCH.GROUP_BY.MONTH,
dateOn: CONST.SEARCH.DATE_PRESETS.YEAR_TO_DATE,
view: CONST.SEARCH.VIEW.BAR,
},
{
sortBy: CONST.SEARCH.TABLE_COLUMNS.GROUP_MONTH,
sortOrder: CONST.SEARCH.SORT_ORDER.DESC,
},
),
get searchQueryJSON() {
return buildSearchQueryJSON(this.searchQuery);
},
get hash() {
return this.searchQueryJSON?.hash ?? CONST.DEFAULT_NUMBER_ID;
},
get similarSearchHash() {
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
},
},
};
}

Expand All @@ -776,6 +803,7 @@ function getSuggestedSearchesVisibility(
let shouldShowTopSpendersSuggestion = false;
let shouldShowTopCategoriesSuggestion = false;
let shouldShowTopMerchantsSuggestion = false;
let shouldShowSpendOverTimeSuggestion = false;

const hasCardFeed = Object.values(cardFeedsByPolicy ?? {}).some((feeds) => feeds.length > 0);

Expand Down Expand Up @@ -814,6 +842,7 @@ function getSuggestedSearchesVisibility(
const isEligibleForTopSpendersSuggestion = isPaidPolicy && (isAdmin || isAuditor || isApprover);
const isEligibleForTopCategoriesSuggestion = isPaidPolicy && policy.areCategoriesEnabled === true;
const isEligibleForTopMerchantsSuggestion = isPaidPolicy;
const isEligibleForSpendOverTimeSuggestion = isPaidPolicy && (isAdmin || isAuditor || isApprover);

shouldShowSubmitSuggestion ||= isEligibleForSubmitSuggestion;
shouldShowPaySuggestion ||= isEligibleForPaySuggestion;
Expand All @@ -826,6 +855,7 @@ function getSuggestedSearchesVisibility(
shouldShowTopSpendersSuggestion ||= isEligibleForTopSpendersSuggestion;
shouldShowTopCategoriesSuggestion ||= isEligibleForTopCategoriesSuggestion;
shouldShowTopMerchantsSuggestion ||= isEligibleForTopMerchantsSuggestion;
shouldShowSpendOverTimeSuggestion ||= isEligibleForSpendOverTimeSuggestion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ PERF-2 (docs)

The early return optimization in the .some() callback (lines ~860-872) is incomplete. It checks if all suggestions are visible to short-circuit iteration, but its missing shouldShowSpendOverTimeSuggestion from the condition.

Issue: After adding the new shouldShowSpendOverTimeSuggestion variable and tracking its state, the early return condition was not updated. This means even when all suggestions (including SPEND_OVER_TIME) are visible, the loop continues checking remaining policies unnecessarily.

Fix: Add && shouldShowSpendOverTimeSuggestion to the return statement:

return (
    shouldShowSubmitSuggestion &&
    // ... other conditions ...
    shouldShowTopMerchantsSuggestion &&
    shouldShowSpendOverTimeSuggestion  // Add this
);

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.


// We don't need to check the rest of the policies if we already determined that all suggestions should be displayed
return (
Expand Down Expand Up @@ -858,6 +888,7 @@ function getSuggestedSearchesVisibility(
[CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS]: shouldShowTopSpendersSuggestion,
[CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES]: shouldShowTopCategoriesSuggestion,
[CONST.SEARCH.SEARCH_KEYS.TOP_MERCHANTS]: shouldShowTopMerchantsSuggestion,
[CONST.SEARCH.SEARCH_KEYS.SPEND_OVER_TIME]: shouldShowSpendOverTimeSuggestion,
};
}

Expand Down Expand Up @@ -3626,7 +3657,12 @@ function createTypeMenuSections(
menuItems: [],
};

const insightsSearchKeys = [CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS, CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES, CONST.SEARCH.SEARCH_KEYS.TOP_MERCHANTS];
const insightsSearchKeys = [
CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS,
CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES,
CONST.SEARCH.SEARCH_KEYS.TOP_MERCHANTS,
CONST.SEARCH.SEARCH_KEYS.SPEND_OVER_TIME,
];

for (const key of insightsSearchKeys) {
if (!suggestedSearchesVisibility[key]) {
Expand Down
Loading
Loading