From dacce719dc39ba0a3cff2e31ba59a36a0d523a8c Mon Sep 17 00:00:00 2001 From: Guillem Arias Date: Thu, 14 May 2026 21:58:18 +0200 Subject: [PATCH] fix(goals): Mark complete confirm warns at sub-100% progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Behavioural audit edge case. A user clicking "Mark complete" at 80% saw the same generic confirm body as at 105% ("It leaves the Ongoing list…"). Sunk-cost-fallacy inversion + premature closure: once labelled complete, the goal anchors success on the truncated amount; future similar goals get smaller targets (regression to the lower aspiration). When `progress_percent < 100`, swap the confirm body to a specific one — "You're at 80% — $X of $Y. Marking complete records this as your achievement instead of the original target. Continue, or close this and adjust the target instead?" Doesn't block the action (some "stop short" cases are healthy — CFP literature explicitly endorses changing your mind), but makes the trade-off visible. Keep the original copy for the ≥ 100% case. `confirm_complete_body_short` is a new locale key; the kebab-menu builder picks between it and `confirm_complete_body` per-render. --- app/views/goals/show.html.erb | 10 +++++++++- config/locales/views/goals/en.yml | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/views/goals/show.html.erb b/app/views/goals/show.html.erb index 602f546d8..4dd758b1c 100644 --- a/app/views/goals/show.html.erb +++ b/app/views/goals/show.html.erb @@ -62,6 +62,14 @@ <% menu.with_item(variant: "button", text: t(".resume"), icon: "play", href: resume_goal_path(@goal), method: :patch) %> <% end %> <% if @goal.may_complete? %> + <% complete_body = if @goal.progress_percent < 100 + t(".confirm_complete_body_short", + progress: @goal.progress_percent, + saved: @goal.current_balance_money.format(precision: 0), + target: @goal.target_amount_money.format(precision: 0)) + else + t(".confirm_complete_body") + end %> <% menu.with_item( variant: "button", text: t(".complete"), @@ -70,7 +78,7 @@ method: :patch, confirm: CustomConfirm.new( title: t(".confirm_complete_title"), - body: t(".confirm_complete_body"), + body: complete_body, btn_text: t(".confirm_complete_cta") ) ) %> diff --git a/config/locales/views/goals/en.yml b/config/locales/views/goals/en.yml index ef2db243c..345a5efd1 100644 --- a/config/locales/views/goals/en.yml +++ b/config/locales/views/goals/en.yml @@ -146,6 +146,7 @@ en: adjust_target_cta: Adjust target instead 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_body_short: "You're at %{progress}% — %{saved} of %{target}. Marking complete records this as your achievement instead of the original target. Continue, or close this and adjust the target instead?" confirm_complete_cta: Mark complete confirm_archive_title: Archive this goal? confirm_archive_body: Archived goals disappear from the main list. You can restore them later.