mirror of
https://github.com/we-promise/sure.git
synced 2026-05-29 23:39:03 +00:00
feat(retirement): PR4c DS::SelectableCard + bucket restyle
DS::SelectableCard — a checkbox rendered as a selectable card (whole card toggles; brand-accent border + bg-surface when selected via peer-checked on the sibling). Submits like a normal checkbox, so the bucket's replace-all form is unchanged. Lookbook preview + component test. Retirement bucket now renders each account as a DS::SelectableCard (name · type · balance) instead of a bare checkbox row. Money stays privacy-sensitive.
This commit is contained in:
14
app/components/DS/selectable_card.html.erb
Normal file
14
app/components/DS/selectable_card.html.erb
Normal file
@@ -0,0 +1,14 @@
|
||||
<label class="block cursor-pointer">
|
||||
<%= check_box_tag name, value, checked, class: "peer sr-only", **opts %>
|
||||
<div class="flex items-center justify-between gap-3 rounded-xl border-2 border-secondary bg-surface-inset p-4 transition-colors peer-checked:border-primary peer-checked:bg-surface peer-focus-visible:ring-2 peer-focus-visible:ring-offset-2 peer-focus-visible:ring-gray-400">
|
||||
<div class="min-w-0">
|
||||
<p class="text-primary text-sm font-medium truncate"><%= title %></p>
|
||||
<% if subtitle %>
|
||||
<p class="text-secondary text-xs truncate"><%= subtitle %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if amount %>
|
||||
<span class="text-primary text-sm tabular-nums shrink-0 privacy-sensitive"><%= amount %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
</label>
|
||||
16
app/components/DS/selectable_card.rb
Normal file
16
app/components/DS/selectable_card.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# A checkbox rendered as a selectable card: the whole card toggles, with a
|
||||
# brand-accent border + check glyph when selected. Used for the retirement
|
||||
# bucket account picker. Submits like a normal checkbox (name[]/value).
|
||||
class DS::SelectableCard < DesignSystemComponent
|
||||
attr_reader :name, :value, :title, :subtitle, :amount, :checked, :opts
|
||||
|
||||
def initialize(name:, value:, title:, subtitle: nil, amount: nil, checked: false, **opts)
|
||||
@name = name
|
||||
@value = value
|
||||
@title = title
|
||||
@subtitle = subtitle
|
||||
@amount = amount
|
||||
@checked = checked
|
||||
@opts = opts
|
||||
end
|
||||
end
|
||||
@@ -187,12 +187,14 @@
|
||||
<%= form_with url: retirement_bucket_path, method: :patch, class: "space-y-3" do |form| %>
|
||||
<div class="space-y-2">
|
||||
<% @bucket_candidates.each do |account| %>
|
||||
<label class="flex items-center gap-2 text-sm text-primary">
|
||||
<%= check_box_tag "bucket[account_ids][]", account.id,
|
||||
@bucket_account_ids.include?(account.id) %>
|
||||
<span><%= account.name %></span>
|
||||
<span class="text-secondary text-xs privacy-sensitive"><%= account.balance_money&.format %></span>
|
||||
</label>
|
||||
<%= render DS::SelectableCard.new(
|
||||
name: "bucket[account_ids][]",
|
||||
value: account.id,
|
||||
title: account.name,
|
||||
subtitle: account.accountable_type&.underscore&.humanize,
|
||||
amount: account.balance_money&.format,
|
||||
checked: @bucket_account_ids.include?(account.id)
|
||||
) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= form.submit t("retirement.show.save_bucket"), class: "text-sm font-medium text-primary underline cursor-pointer" %>
|
||||
|
||||
25
test/components/DS/selectable_card_test.rb
Normal file
25
test/components/DS/selectable_card_test.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
require "test_helper"
|
||||
|
||||
class DS::SelectableCardTest < ViewComponent::TestCase
|
||||
test "renders a checkbox with title, subtitle, amount" do
|
||||
render_inline(DS::SelectableCard.new(
|
||||
name: "bucket[account_ids][]", value: "a1",
|
||||
title: "Brokerage", subtitle: "ETF", amount: "$100,000"
|
||||
))
|
||||
|
||||
assert_selector "input[type=checkbox][name='bucket[account_ids][]'][value='a1']", visible: false
|
||||
assert_text "Brokerage"
|
||||
assert_text "ETF"
|
||||
assert_text "$100,000"
|
||||
end
|
||||
|
||||
test "checked renders the checkbox checked" do
|
||||
render_inline(DS::SelectableCard.new(name: "n", value: "v", title: "T", checked: true))
|
||||
assert_selector "input[type=checkbox][checked]", visible: false
|
||||
end
|
||||
|
||||
test "unchecked omits the checked attribute" do
|
||||
render_inline(DS::SelectableCard.new(name: "n", value: "v", title: "T", checked: false))
|
||||
assert_no_selector "input[type=checkbox][checked]", visible: false
|
||||
end
|
||||
end
|
||||
13
test/components/previews/DS/selectable_card_preview.rb
Normal file
13
test/components/previews/DS/selectable_card_preview.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class DS::SelectableCardPreview < ViewComponent::Preview
|
||||
# @param checked toggle
|
||||
def default(checked: true)
|
||||
render DS::SelectableCard.new(
|
||||
name: "bucket[account_ids][]",
|
||||
value: "abc",
|
||||
title: "Vanguard FTSE All-World (VWCE)",
|
||||
subtitle: "ETF",
|
||||
amount: "$115,000",
|
||||
checked: checked
|
||||
)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user