From 270ea2630d61330cd41e2c9be3a2230456d5ba69 Mon Sep 17 00:00:00 2001 From: Guillem Arias Date: Mon, 11 May 2026 21:05:03 +0200 Subject: [PATCH] ux(goals/show): catch-up alert anchors all three numbers + scoped scrollbar on contributions list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alert previous pass led with delta ("Behind by $750/mo") but the user still had to reconcile that with the $1,000/mo CTA — the relationship between current pace, gap, and required rate was implicit. Make every number visible in the sentence: - Title: "Save $1,000/mo to stay on track" — leads with the action + required rate. Reduces decision load: the headline is what to do. - Body: "You're saving $250/mo today — $750/mo short of the pace to finish by September 11, 2026." — current pace + gap + deadline. User can now mentally verify: $250 + $750 = $1,000. The catch-up amount in title + body + CTA is no longer disconnected from the current pace number; the body is the bridge. Adds `scrollbar` utility (defined in app/assets/tailwind/application.css as 4px gray-300 thumb) to the contributions list container. Browser- default scrollbar was rendering as a thick dark bar in light mode on some OSes; the in-house utility renders a thin gray thumb consistently across themes. --- app/views/goals/show.html.erb | 9 +++++---- config/locales/views/goals/en.yml | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/goals/show.html.erb b/app/views/goals/show.html.erb index ae4178951..9acee2f83 100644 --- a/app/views/goals/show.html.erb +++ b/app/views/goals/show.html.erb @@ -137,12 +137,13 @@ <% catch_up_money = Money.new(@goal.monthly_target_amount, @goal.currency) %> <% catch_up_delta = @goal.monthly_target_amount.to_d - @stats[:avg_monthly].to_d %> <% catch_up_delta_money = Money.new(catch_up_delta, @goal.currency) %> - <%= render DS::Alert.new(variant: "warning", title: t("goals.show.catch_up.title", delta: catch_up_delta_money.format)) do %> + <% catch_up_avg_money = Money.new(@stats[:avg_monthly], @goal.currency) %> + <%= render DS::Alert.new(variant: "warning", title: t("goals.show.catch_up.title", amount: catch_up_money.format)) do %>

<% if @goal.target_date %> - <%= t("goals.show.catch_up.body_with_date", amount: catch_up_money.format, date: I18n.l(@goal.target_date, format: :long)) %> + <%= t("goals.show.catch_up.body_with_date", avg: catch_up_avg_money.format, delta: catch_up_delta_money.format, date: I18n.l(@goal.target_date, format: :long)) %> <% else %> - <%= t("goals.show.catch_up.body", amount: catch_up_money.format) %> + <%= t("goals.show.catch_up.body", avg: catch_up_avg_money.format, delta: catch_up_delta_money.format) %> <% end %>

@@ -306,7 +307,7 @@

<%= t(".contributions_heading") %>

<%= @contributions.size %>
-
+
<%= render "contributions_list", contributions: @contributions %>
diff --git a/config/locales/views/goals/en.yml b/config/locales/views/goals/en.yml index 8afa5e65b..dae35c843 100644 --- a/config/locales/views/goals/en.yml +++ b/config/locales/views/goals/en.yml @@ -123,9 +123,9 @@ en: on_track: At your current pace, you'll reach this goal around %{date}. aria_label: "Projection chart for %{name}" catch_up: - title: "Behind by %{delta}/mo" - body_with_date: "Save %{amount}/mo to stay on track for %{date}." - body: "Save %{amount}/mo to stay on track." + title: "Save %{amount}/mo to stay on track" + body_with_date: "You're saving %{avg}/mo today — %{delta}/mo short of the pace to finish by %{date}." + body: "You're saving %{avg}/mo today — %{delta}/mo short of the required pace." cta: "Add %{amount}" confirm_complete_title: Mark this goal complete? confirm_complete_body: It leaves the Ongoing list. You can still archive or restore it later.