Repository navigation
[NoQA] [Insights] Draw Previous period for Spend over time - #103786
luacmartins merged 24 commits into
Conversation
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx bun ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
b744ce3 to
81e9900
Compare
…cket instead of the single-series variant
🦜 Polyglot Parrot! 🦜Squawk! Looks like you added some shiny new English strings. Allow me to parrot them back to you in other tongues: View the translation diffdiff --git a/src/languages/de.ts b/src/languages/de.ts
index 0cea6445..140d40ee 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1176,7 +1176,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'In Ausgaben anzeigen',
emptyState: {title: 'Nichts anzuzeigen', subtitle: 'Versuchen Sie, Ihre Kriterien oben anzupassen'},
noExpensesState: {title: 'Sehen Sie, wohin Ihr Geld fließt', subtitle: 'Sobald Sie Ausgaben haben, finden Sie Ausgabentrends, Top-Händler und mehr.'},
- compare: {label: 'Vergleichen', previousPeriod: 'Vorheriger Zeitraum', average: 'Durchschnitt'},
+ compare: {
+ label: 'Vergleichen',
+ previousPeriod: 'Vorheriger Zeitraum',
+ average: 'Durchschnitt',
+ dayLabel: (day?: number) => (day === undefined ? 'Tag' : `Tag ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Woche' : `Woche ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Monat' : `Monat ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Quartal' : `Quartal ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Jahr' : `Jahr ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/el.ts b/src/languages/el.ts
index 8ae8d6e7..dfc6d0af 100644
--- a/src/languages/el.ts
+++ b/src/languages/el.ts
@@ -1221,7 +1221,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'Προβολή στο Spend',
emptyState: {title: 'Τίποτα προς εμφάνιση', subtitle: 'Δοκιμάστε να προσαρμόσετε τα κριτήριά σας παραπάνω'},
noExpensesState: {title: 'Δείτε πού πηγαίνουν τα χρήματά σας', subtitle: 'Μόλις έχετε δαπάνες, θα βλέπετε τάσεις δαπανών, κορυφαίους εμπόρους και άλλα.'},
- compare: {label: 'Σύγκριση', previousPeriod: 'Προηγούμενη περίοδος', average: 'Μέσος όρος'},
+ compare: {
+ label: 'Σύγκριση',
+ previousPeriod: 'Προηγούμενη περίοδος',
+ average: 'Μέσος όρος',
+ dayLabel: (day?: number) => (day === undefined ? 'Ημέρα' : `Ημέρα ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Εβδομάδα' : `Εβδομάδα ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Μήνας' : `Μήνας ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Τρίμηνο' : `Τρίμηνο ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Έτος' : `Έτος ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Συνδρομή',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 23fc4be3..ed34a7ce 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1171,7 +1171,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'Ver en Gastos',
emptyState: {title: 'Nada que mostrar', subtitle: 'Prueba a ajustar tus criterios de arriba'},
noExpensesState: {title: 'Ve adónde va tu dinero', subtitle: 'Una vez que tengas gastos, encontrarás tendencias de gasto, principales comercios y mucho más.'},
- compare: {label: 'Comparar', previousPeriod: 'Periodo anterior', average: 'Promedio'},
+ compare: {
+ label: 'Comparar',
+ previousPeriod: 'Periodo anterior',
+ average: 'Promedio',
+ dayLabel: (day?: number) => (day === undefined ? 'Día' : `Día ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Semana' : `Semana ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Mes' : `Mes ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Trimestre' : `Trimestre ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Año' : `Año ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Suscripcion',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 7f37b163..185b9cac 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1180,7 +1180,16 @@ const translations: TranslationDeepObject<typeof en> = {
title: 'Voyez où va votre argent',
subtitle: 'Une fois que vous aurez des dépenses, vous verrez des tendances de dépenses, les principaux marchands et plus encore.',
},
- compare: {label: 'Comparer', previousPeriod: 'Période précédente', average: 'Moyenne'},
+ compare: {
+ label: 'Comparer',
+ previousPeriod: 'Période précédente',
+ average: 'Moyenne',
+ dayLabel: (day?: number) => (day === undefined ? 'Jour' : `Jour ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Semaine' : `Semaine ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Mois' : `Mois ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Trimestre' : `Trimestre ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Année' : `Année ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index bd8eb402..c587e28d 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1176,7 +1176,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'Visualizza in Spese',
emptyState: {title: 'Niente da mostrare', subtitle: 'Prova a modificare i criteri qui sopra'},
noExpensesState: {title: 'Scopri dove va il tuo denaro', subtitle: 'Una volta che avrai delle spese, troverai tendenze di spesa, principali esercenti e altro ancora.'},
- compare: {label: 'Confronta', previousPeriod: 'Periodo precedente', average: 'Media'},
+ compare: {
+ label: 'Confronta',
+ previousPeriod: 'Periodo precedente',
+ average: 'Media',
+ dayLabel: (day?: number) => (day === undefined ? 'Giorno' : `Giorno ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Settimana' : `Settimana ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Mese' : `Mese ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Trimestre' : `Trimestre ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Anno' : `Anno ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Abbonamento',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 7da59e4d..d6884724 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1164,7 +1164,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: '支出で表示',
emptyState: {title: '表示するものはありません', subtitle: '上の条件を調整してみてください'},
noExpensesState: {title: 'お金の使い道を確認する', subtitle: '経費が登録されると、支出の傾向や上位の加盟店など、さまざまな情報を確認できるようになります。'},
- compare: {label: '比較', previousPeriod: '前の期間', average: '平均'},
+ compare: {
+ label: '比較',
+ previousPeriod: '前の期間',
+ average: '平均',
+ dayLabel: (day?: number) => (day === undefined ? '日' : `${day} 日目`),
+ weekLabel: (week?: number) => (week === undefined ? '週' : `${week}週目`),
+ monthLabel: (month?: number) => (month === undefined ? '月' : `月 ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? '四半期' : `四半期 ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? '年' : `${year}年`),
+ },
},
allSettingsScreen: {
subscription: 'サブスクリプション',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index b96c6121..1409f824 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1175,7 +1175,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'Bekijken in Uitgaven',
emptyState: {title: 'Niets om weer te geven', subtitle: 'Probeer je criteria hierboven aan te passen'},
noExpensesState: {title: 'Zie waar je geld naartoe gaat', subtitle: 'Zodra je uitgaven hebt, zie je bestedingspatronen, topverkopers en meer.'},
- compare: {label: 'Vergelijken', previousPeriod: 'Vorige periode', average: 'Gemiddeld'},
+ compare: {
+ label: 'Vergelijken',
+ previousPeriod: 'Vorige periode',
+ average: 'Gemiddeld',
+ dayLabel: (day?: number) => (day === undefined ? 'Dag' : `Dag ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Week' : `Week ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Maand' : `Maand ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Kwartaal' : `Kwartaal ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Jaar' : `Jaar ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Abonnement',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index 95e7b90a..1fb1cfe6 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1197,7 +1197,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'Zobacz w Wydatkach',
emptyState: {title: 'Nic do wyświetlenia', subtitle: 'Spróbuj zmienić kryteria powyżej'},
noExpensesState: {title: 'Zobacz, na co idą twoje pieniądze', subtitle: 'Gdy będziesz mieć wydatki, zobaczysz trendy w wydawaniu, najważniejszych sprzedawców i więcej.'},
- compare: {label: 'Porównaj', previousPeriod: 'Poprzedni okres', average: 'Średnia'},
+ compare: {
+ label: 'Porównaj',
+ previousPeriod: 'Poprzedni okres',
+ average: 'Średnia',
+ dayLabel: (day?: number) => (day === undefined ? 'Dzień' : `Dzień ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Tydzień' : `Tydzień ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Miesiąc' : `Miesiąc ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Kwartał' : `Kwartał ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Rok' : `Rok ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Subskrypcja',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 0a675362..513ae2b8 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1175,7 +1175,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: 'Ver em Gastos',
emptyState: {title: 'Nada para mostrar', subtitle: 'Tente ajustar seus critérios acima'},
noExpensesState: {title: 'Veja para onde vai o seu dinheiro', subtitle: 'Quando você tiver despesas, vai encontrar tendências de gastos, principais estabelecimentos e muito mais.'},
- compare: {label: 'Comparar', previousPeriod: 'Período anterior', average: 'Média'},
+ compare: {
+ label: 'Comparar',
+ previousPeriod: 'Período anterior',
+ average: 'Média',
+ dayLabel: (day?: number) => (day === undefined ? 'Dia' : `Dia ${day}`),
+ weekLabel: (week?: number) => (week === undefined ? 'Semana' : `Semana ${week}`),
+ monthLabel: (month?: number) => (month === undefined ? 'Mês' : `Mês ${month}`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? 'Trimestre' : `Trimestre ${quarter}`),
+ yearLabel: (year?: number) => (year === undefined ? 'Ano' : `Ano ${year}`),
+ },
},
allSettingsScreen: {
subscription: 'Assinatura',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 3b4ae9ff..ce04b889 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1129,7 +1129,16 @@ const translations: TranslationDeepObject<typeof en> = {
viewOnSpend: '在支出中查看',
emptyState: {title: '没有可显示的内容', subtitle: '请尝试调整上面的条件'},
noExpensesState: {title: '查看你的资金流向', subtitle: '添加报销后,您就能查看消费趋势、主要商家等更多信息。'},
- compare: {label: '比较', previousPeriod: '上一期', average: '平均'},
+ compare: {
+ label: '比较',
+ previousPeriod: '上一期',
+ average: '平均',
+ dayLabel: (day?: number) => (day === undefined ? '天' : `第 ${day} 天`),
+ weekLabel: (week?: number) => (week === undefined ? '周' : `第 ${week} 周`),
+ monthLabel: (month?: number) => (month === undefined ? '月' : `第 ${month} 个月`),
+ quarterLabel: (quarter?: number) => (quarter === undefined ? '季度' : `第 ${quarter} 季度`),
+ yearLabel: (year?: number) => (year === undefined ? '年份' : `${year} 年`),
+ },
},
allSettingsScreen: {
subscription: '订阅',
Note You can apply these changes to your branch by copying the patch to your clipboard, then running |
|
@MelvinBot review, but only the changes on top of this other PR's branch: #103989 |
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
|
I reviewed only the 9 commits this PR adds on top of [NoQA] [Insights] Draw Average mode baseline on Spend over time ( 1. Previous-period spend disappears in buckets where the current period has no expenses. 2. Average mode lost the base PR's tooltip fallback. Changing the guard to 3. Custom ranges can be paired by calendar date instead of by position. 4. Translation nit. In What I checked
|
the backend sends all buckets, even when they're empty. we're using the lack of a bucket to determine that it doesn't exist.
yeah, good catch, fixed
very very good point, fixed
I'll have to trust Melvin on this one |
|
Also @dannymcclain added you for review. The adhoc links are above. |
|
Looking good! |
|
@mhawryluk Could you help confirm if it is the bug? Setup: Need a workspace with expenses in both months:
Steps:
Expected: The current-month line ends at today with a dashed last segment, since the period isn’t over.
|
This month covers Oct 1-31 and the backend now sends every day, with $0 for the days after today, so the axis runs to the 31st. this happens even with Compare set to None, it's not related to the previous period. and I think it's expected the last segment is solid because the line chart only dashes when the last point is in progress, and today isn't the last day of the month. but this PR: #104075 changes which line segments are dashed, it makes all current and future buckets dashed, so it will cover this scenario |
oh, I guess it's not expected, coming from this comment: #104272 (comment) |
@mhawryluk I think if that PR already covers this scenario, we can leave it to handle the fix and avoid adding the same fix to our current PR since as you said, it doesn't cause by our PR |
|
Agree with that approach. |
Here is the behavior in PR #104075, it looks good:
|
|
yeah, it looks good to me too. but it only changes where the line is dashed, we still plot empty buckets of the future, so if we wanted to change that we would need to filter them out. but I think we should do it in a follow-up, if we do decide we want to only show future buckets if they have expenses cc: @JmillsExpensify |
|
That chart with the future buckets looks good to me. cc @JmillsExpensify in case you feel differently |
|
Looks good to me too. |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppScreen.Recording.2026-10-21.at.00.32.40.movAndroid: mWeb ChromeScreen.Recording.2026-10-21.at.00.33.58.moviOS: HybridAppiOS: mWeb SafariMacOS: Chrome / SafariScreen.Recording.2026-10-21.at.00.30.02.mov |
|
🚧 luacmartins has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/luacmartins in version: 9.5.15-1 🚀
|
|
🚀 Deployed to production by https://github.com/grgia in version: 9.5.15-3 🚀
Bundle Size Analysis (Sentry): |





Explanation of Change
Spend over time now draws the previous period as a second line when Compare is set to Previous period.
Fixed Issues
$ #103768
PROPOSAL: N/A
Tests
insightsPageandinsightsComparebetas. Go to Insights and set Date to Year to date, Group by to Month and Compare to Previous period. Verify that Spend over time shows two lines: the current year, and last year in a lighter shade of the same color, with the current line drawn on top.—.Offline tests
QA Steps
No tests.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
Nagranie.z.ekranu.2026-10-16.o.13.11.35.mov