From 7954a01ed17f8219102acbdbfa3b58b3f0d1e2a8 Mon Sep 17 00:00:00 2001 From: Guillem Arias Date: Mon, 11 May 2026 16:06:29 +0200 Subject: [PATCH] feat(savings_goals/show): combo monthly-pace stat card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D7 — Merge the separate Avg-monthly and Target-pace cards into one wider "Monthly pace" card spanning 2/3 of the stat row. Shows actual $/mo + target $/mo inline, with a delta line below: - behind → "Behind by $X/mo" (text-warning) - on/ahead → "Above target pace" (text-success) - no target_date → "No required pace" Total contributions stays as a separate, smaller card at 1/3 width. The action pyramid finally points at the actionable stat — pace is visually primary, raw count secondary. --- app/views/savings_goals/show.html.erb | 35 +++++++++++++++-------- config/locales/views/savings_goals/en.yml | 3 ++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/views/savings_goals/show.html.erb b/app/views/savings_goals/show.html.erb index 41ea41528..e96301c73 100644 --- a/app/views/savings_goals/show.html.erb +++ b/app/views/savings_goals/show.html.erb @@ -202,25 +202,36 @@ <% end %> - <%# Stat row %> + <%# Stat row — combo pace card + contributions count %>
-
-

<%= t(".stats.avg_monthly") %>

-

<%= Money.new(@stats[:avg_monthly], @savings_goal.currency).format %>

-

<%= @stats[:avg_monthly_sub] %>

+ <%# Combo: Avg vs Target pace %> +
+

<%= t(".stats.monthly_pace") %>

+
+

<%= Money.new(@stats[:avg_monthly], @savings_goal.currency).format %>

+

/mo

+ <% if @savings_goal.monthly_target_amount %> +

· <%= t(".stats.target_of", amount: Money.new(@savings_goal.monthly_target_amount, @savings_goal.currency).format) %>

+ <% end %> +
+ <% if @savings_goal.monthly_target_amount %> + <% delta = @savings_goal.monthly_target_amount.to_d - @stats[:avg_monthly].to_d %> + <% if delta.positive? %> +

<%= t(".stats.behind_by", amount: Money.new(delta, @savings_goal.currency).format) %>

+ <% else %> +

<%= t(".stats.above_target_pace") %>

+ <% end %> + <% else %> +

<%= t(".stats.no_required_pace") %>

+ <% end %>
+ + <%# Total contributions %>

<%= t(".stats.total_contributions") %>

<%= @stats[:contributions_count] %>

<%= t(".stats.across_all_accounts") %>

-
-

<%= t(".stats.target_pace") %>

-

- <%= @savings_goal.monthly_target_amount ? Money.new(@savings_goal.monthly_target_amount, @savings_goal.currency).format + "/mo" : t(".stats.no_required_pace") %> -

-

<%= @stats[:monthly_target_sub] %>

-
<%# Bottom row: contributions + funding accounts %> diff --git a/config/locales/views/savings_goals/en.yml b/config/locales/views/savings_goals/en.yml index 69c49323c..e06e72b9a 100644 --- a/config/locales/views/savings_goals/en.yml +++ b/config/locales/views/savings_goals/en.yml @@ -148,6 +148,9 @@ en: no_required_pace: No required pace needs_per_month: "Needs %{amount}/mo" above_target_pace: Above target pace + monthly_pace: Monthly pace + target_of: "target %{amount}/mo" + behind_by: "Behind by %{amount}/mo" states: active: Active paused: Paused