* Improve spending chart mobile layout
- Name the compared month ("August 2026") instead of the generic
"Previous month" label that truncated on narrow viewports
- Keep the signed delta on one line: nowrap amounts, wrap as a unit
- On mobile widths, label x-axis ticks for the selected month only so a
longer previous month's tail tick ("Aug 31") doesn't read like a bug
- Show a compact date range ("Sep 01 - 6, 2026") on narrow viewports
* Compute comparison label and compact date range in the controller
Addresses review on #3435: moves previous_label and date_range_short out
of the partial into build_spending_trend_data, and puts the single-day
compact range behind its own i18n key instead of a hard-coded format.
* Revert accidental local-env ruby version bump
.ruby-version and Gemfile.lock were swept into the previous commit by a
git add -A from the local verification sandbox (3.4.10 vs the repo's
pinned 3.4.9, which setup-ruby cannot provision on ubuntu-24.04).
* Use the controller t() helper for compact date range translations
Project convention is t() over I18n.t for user-facing strings in
controllers (CodeRabbit review on #3435).
* Don't over-explain in comments
* Add cumulative spending chart dashboard widget
New dashboard section showing the selected month's running spending total
against the previous month's full curve on a shared day-of-month axis,
inspired by Copilot Money's Spending card.
- IncomeStatement#daily_expense_series: per-day expense totals in family
currency, same scoping as the other income statement totals (visible,
posted, budget-included transactions; report-included accounts; daily
exchange-rate conversion)
- PagesController: spending_trend section with month picker (clamped like
money_flow), cumulative series builder, delta vs. previous month
- spending-chart Stimulus controller (D3): previous month in gray, current
month in green with a today marker, gridlines with compact currency
labels, shared tooltip
- i18n (en) and model/controller tests
* Address PR review: locale-safe axis labels, currency/rate-aware cache key
- X-axis tick labels are now rendered server-side (I18n.l), one per axis
day: when the previous month is longer than the selected one it owns the
tail labels, so a tick can no longer roll past the selected month's end
(e.g. day 31 of a February view showed "Mar 3"), and labels follow the
app locale instead of D3's default English time-format locale.
- IncomeStatement#daily_expense_series cache key now includes the family
currency and the latest exchange-rate timestamp, since ExchangeRate::
Importer's upsert_all and currency changes leave entries/accounts
untouched and previously served stale chart data.
* Fix spending trend tests: empty-state month in axis test, dropped start_date key
- Axis-label test picked a month pair with no transactions, so the widget
rendered its empty state and there was no chart payload to parse; seed
spending in both months under test.
- The clamp test still asserted on the payload's removed start_date key;
assert the clamped month via the current series' first point date instead.