From ed9759b87bd60cbb1bb3fb1ede1497d248ffa412 Mon Sep 17 00:00:00 2001 From: Guillem Arias Date: Mon, 11 May 2026 16:37:11 +0200 Subject: [PATCH] feat(savings_goals): demo variety, breadcrumb naming, ring token, list pattern, header split, tone down behind noise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Demo — extend generate_savings_goals! with three more goals to exercise status-specific UX: Wedding fund (on_track w/ 6 months of contributions matching required pace), Sabbatical (paused), Old laptop fund (archived). House downpayment gains 12 contributions so the scrollable list has real density. Total now 7 demo goals covering behind / on_track / no_date / paused / archived / reached. Breadcrumbs — set @breadcrumbs on index too (it was relying on the Rails-derived "Savings goals" label). Both views now read "Home → Savings → ..." consistently, matching the sidebar nav text and H1. Ring token — goal-card ring stroke switched from var(--color-gray-200) (a hard light color identical in both themes) to var(--budget-unallocated-fill) which is gray-50 light / gray-700 dark, matching the detail page's progress ring. Contributions list — replace the inline hover-revealed delete-X with DS::Menu kebab, matching tags/_tag.html.erb and categories/_category. Each row also gets hover:bg-surface-hover with a px-3 -mx-3 negative margin to extend the hover area across the card padding. Non-manual contributions render a 9x9 spacer so the right column stays aligned. Header sub split — drop the long "·" chain into two lines: primary fact (target / days left) in text-secondary, recency note in text-subdued underneath. Less wall-of-text. Behind noise — pill, ring, catch-up alert and projection chart already signal "behind". The Monthly-pace combo card's "Behind by $X/mo" delta no longer renders in text-warning — it switches to text-subdued so the warning palette doesn't repeat across the page. The catch-up alert stays loud because it's the primary action; the rest stays informational. CustomConfirm wired with destructive: true on the contribution delete so the confirm button gets the outline-destructive treatment. --- .../savings/goal_card_component.html.erb | 2 +- app/controllers/savings_goals_controller.rb | 4 ++ app/models/demo/generator.rb | 56 ++++++++++++++++++- .../_contributions_list.html.erb | 26 ++++++--- app/views/savings_goals/show.html.erb | 28 +++++----- config/locales/views/savings_goals/en.yml | 4 ++ .../savings_goals_controller_test.rb | 2 +- 7 files changed, 95 insertions(+), 27 deletions(-) diff --git a/app/components/savings/goal_card_component.html.erb b/app/components/savings/goal_card_component.html.erb index 03d8db1ea..97c725930 100644 --- a/app/components/savings/goal_card_component.html.erb +++ b/app/components/savings/goal_card_component.html.erb @@ -21,7 +21,7 @@ cy="<%= Savings::GoalCardComponent::RING_SIZE / 2.0 %>" r="<%= ring_radius %>" fill="none" - stroke="var(--color-gray-200)" + stroke="var(--budget-unallocated-fill)" stroke-width="<%= Savings::GoalCardComponent::RING_STROKE %>" /> 6 + @breadcrumbs = [ + [ t("breadcrumbs.home"), root_path ], + [ t("savings_goals.index.title"), nil ] + ] end def show diff --git a/app/models/demo/generator.rb b/app/models/demo/generator.rb index c285aa7f0..8b96b6dba 100644 --- a/app/models/demo/generator.rb +++ b/app/models/demo/generator.rb @@ -1287,6 +1287,30 @@ class Demo::Generator primary = eligible.first secondary = eligible[1] || primary + # Build "Wedding fund" on_track contributions: target 12 months out, + # $200/mo required, demo contributes $220/mo for last 6 months → on + # pace. + wedding_contribs = (0..5).map do |i| + { amount: 220, source: i.zero? ? "initial" : "manual", days_ago: 30 * (6 - i), account: primary } + end + + # "House downpayment" gets a fuller contribution history so the + # scrollable list has real density. + house_contribs = [ + { amount: 5_000, source: "initial", days_ago: 365, account: primary }, + { amount: 750, source: "manual", days_ago: 330, account: primary }, + { amount: 750, source: "manual", days_ago: 300, account: secondary }, + { amount: 750, source: "manual", days_ago: 270, account: primary }, + { amount: 750, source: "manual", days_ago: 240, account: primary }, + { amount: 750, source: "manual", days_ago: 210, account: secondary }, + { amount: 750, source: "manual", days_ago: 180, account: primary }, + { amount: 750, source: "manual", days_ago: 150, account: primary }, + { amount: 750, source: "manual", days_ago: 120, account: secondary }, + { amount: 750, source: "manual", days_ago: 90, account: primary }, + { amount: 750, source: "manual", days_ago: 60, account: primary }, + { amount: 750, source: "manual", days_ago: 30, account: secondary } + ] + goals = [ { name: "Vacation in Italy", @@ -1299,13 +1323,22 @@ class Demo::Generator { amount: 250, source: "manual", days_ago: 30, account: secondary } ] }, + { + name: "Wedding fund", + target: 2_400, + target_date: 6.months.from_now.to_date, + accounts: eligible.first(2), + contributions: wedding_contribs + }, { name: "Emergency fund", target: 10_000, target_date: nil, accounts: [ primary ], contributions: [ - { amount: 1_000, source: "initial", days_ago: 180, account: primary } + { amount: 1_000, source: "initial", days_ago: 180, account: primary }, + { amount: 250, source: "manual", days_ago: 60, account: primary }, + { amount: 250, source: "manual", days_ago: 30, account: primary } ] }, { @@ -1313,8 +1346,27 @@ class Demo::Generator target: 50_000, target_date: 24.months.from_now.to_date, accounts: eligible.first(2), + contributions: house_contribs + }, + { + name: "Sabbatical", + target: 15_000, + target_date: 18.months.from_now.to_date, + state: "paused", + accounts: [ primary ], contributions: [ - { amount: 5_000, source: "initial", days_ago: 365, account: primary } + { amount: 1_500, source: "initial", days_ago: 200, account: primary }, + { amount: 500, source: "manual", days_ago: 150, account: primary } + ] + }, + { + name: "Old laptop fund", + target: 1_500, + target_date: 12.months.ago.to_date, + state: "archived", + accounts: [ primary ], + contributions: [ + { amount: 400, source: "initial", days_ago: 540, account: primary } ] }, { diff --git a/app/views/savings_goals/_contributions_list.html.erb b/app/views/savings_goals/_contributions_list.html.erb index 0237b1151..ddceafad1 100644 --- a/app/views/savings_goals/_contributions_list.html.erb +++ b/app/views/savings_goals/_contributions_list.html.erb @@ -5,9 +5,9 @@

<%= t("savings_goals.show.no_contributions_yet") %>

<% else %> -