Files
sure/app/views/goal_contributions/new.html.erb
Guillem Arias e179abd0b3 feat(goal_contributions/new): live impact preview below amount field
Add-contribution modal previously offered zero feedback on what the
typed amount would do to goal progress. Now renders "Currently X%
saved (Y of Z)." at rest and updates on each keystroke to
"Will bring you to X% saved (Y of Z)." or "Will reach your Z target."
when the contribution would close the gap.

- New goal_contribution_preview_controller.js consumes current balance
  + target + currency + three localized template strings as Stimulus
  values. Intl.NumberFormat for currency formatting (locale-correct
  out of the box; fallback to currencyValue prefix on environments
  that don't support it).
- ERB form-level data-controller wires the values; amount input uses
  amount_data: to thread the Stimulus target / action through the
  money_field helper.
- Locale: goal_contributions.new.preview_{zero,nonzero,reached} with
  {percent}, {current}, {newTotal}, {target} placeholders.
2026-05-11 20:25:44 +02:00

47 lines
2.1 KiB
Plaintext

<%= render DS::Dialog.new do |dialog| %>
<% dialog.with_header(title: t(".heading")) %>
<% dialog.with_body do %>
<% if @contribution.errors.any? %>
<%= render "shared/form_errors", model: @contribution %>
<% end %>
<%= styled_form_with model: @contribution,
url: goal_contributions_path(@goal),
class: "space-y-3",
data: {
controller: "goal-contribution-preview",
goal_contribution_preview_current_balance_value: @goal.current_balance.to_f,
goal_contribution_preview_target_amount_value: @goal.target_amount.to_f,
goal_contribution_preview_currency_value: @goal.currency,
goal_contribution_preview_template_zero_value: t(".preview_zero"),
goal_contribution_preview_template_nonzero_value: t(".preview_nonzero"),
goal_contribution_preview_template_reached_value: t(".preview_reached")
} do |f| %>
<%= f.money_field :amount,
label: t(".amount"),
hide_currency: true,
autofocus: true,
amount_data: {
goal_contribution_preview_target: "amountInput",
action: "input->goal-contribution-preview#update"
} %>
<p class="text-xs text-secondary tabular-nums -mt-1"
data-goal-contribution-preview-target="preview"></p>
<%= f.select :account_id,
options_from_collection_for_select(@goal.linked_accounts, :id, :name, @contribution.account_id),
{ label: t(".source_account"), include_blank: t(".select_account") } %>
<%= f.date_field :contributed_at,
label: t(".contributed_at") %>
<%= f.text_area :notes, label: t(".notes"), rows: 2 %>
<div class="flex justify-end pt-2">
<%= f.submit t(".submit") %>
</div>
<% end %>
<% end %>
<% end %>