From 57b7848eec14bd671ac06124715c2b42bbcf5206 Mon Sep 17 00:00:00 2001
From: Guillem Arias
Date: Mon, 11 May 2026 21:11:42 +0200
Subject: [PATCH] ux(goals/show): catch-up CTA pre-fills + secondary "Adjust
your target" link
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The "Add $1,531.25" CTA used to open the contribution modal with an
empty amount field — label was a hint, not a default. Now passes the
catch-up amount via ?amount= and the contributions controller seeds
@contribution.amount from params. One click brings the user to the
modal already populated.
Adds a secondary text link below the primary CTA: "Or adjust your
target" → opens the edit modal (Turbo frame). Behavioural-econ choice
architecture: gives the rebaseline path explicitly so users who can't
realistically catch up don't feel forced into the contribution.
Trade-off: lets the alert respect autonomy — commit or recalibrate,
both fine. Action paralysis kept low by visual hierarchy (primary
button vs muted text link).
---
app/controllers/goal_contributions_controller.rb | 3 ++-
app/views/goals/show.html.erb | 8 ++++++--
config/locales/views/goals/en.yml | 1 +
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/app/controllers/goal_contributions_controller.rb b/app/controllers/goal_contributions_controller.rb
index da3a0353d..17cdeedca 100644
--- a/app/controllers/goal_contributions_controller.rb
+++ b/app/controllers/goal_contributions_controller.rb
@@ -7,7 +7,8 @@ class GoalContributionsController < ApplicationController
@contribution = @goal.goal_contributions.new(
contributed_at: Date.current,
currency: @goal.currency,
- source: "manual"
+ source: "manual",
+ amount: params[:amount].presence
)
end
diff --git a/app/views/goals/show.html.erb b/app/views/goals/show.html.erb
index 9acee2f83..9640d0d2f 100644
--- a/app/views/goals/show.html.erb
+++ b/app/views/goals/show.html.erb
@@ -146,15 +146,19 @@
<%= t("goals.show.catch_up.body", avg: catch_up_avg_money.format, delta: catch_up_delta_money.format) %>
<% end %>
-
+
<%= render DS::Link.new(
text: t("goals.show.catch_up.cta", amount: catch_up_money.format),
variant: "primary",
size: "sm",
- href: new_goal_contribution_path(@goal),
+ href: new_goal_contribution_path(@goal, amount: @goal.monthly_target_amount.to_f),
icon: "plus",
frame: :modal
) %>
+ <%= link_to t("goals.show.catch_up.adjust_target_cta"),
+ edit_goal_path(@goal),
+ data: { turbo_frame: :modal },
+ class: "text-xs text-secondary hover:text-primary underline-offset-2 hover:underline" %>
<% end %>
<% end %>
diff --git a/config/locales/views/goals/en.yml b/config/locales/views/goals/en.yml
index db513601e..0eea272ff 100644
--- a/config/locales/views/goals/en.yml
+++ b/config/locales/views/goals/en.yml
@@ -127,6 +127,7 @@ en:
body_with_date: "Your current pace is %{avg}/mo. You need an extra %{delta}/mo to finish by %{date}."
body: "Your current pace is %{avg}/mo. You need an extra %{delta}/mo to hit the required rate."
cta: "Add %{amount}"
+ adjust_target_cta: Or adjust your target
confirm_complete_title: Mark this goal complete?
confirm_complete_body: It leaves the Ongoing list. You can still archive or restore it later.
confirm_complete_cta: Mark complete