mirror of
https://github.com/we-promise/sure.git
synced 2026-05-30 07:49:01 +00:00
Correctness: - GoalPledge#matches? rejects outflows on transfer pledges so a +$200 purchase no longer satisfies a $200 deposit pledge after .abs - GoalsController#sync_linked_accounts! saves through the goal so currency/depository/family validations actually run on update - AlreadyClaimedError replaces empty RecordInvalid in resolve_with! and reconciler rescues the dedicated class - SweepExpiredGoalPledgesJob wraps each expire! in a per-record rescue - Assistant::Function::CreateGoal disambiguates duplicate account names and returns an absolute URL via mailer host config - Family#savings_inflow_velocity defensively scopes from the family's accounts (was Account.joins(:goal_accounts).where(goal_id: ...)) - GoalPledgesController#set_goal preloads linked_accounts + providers to drop the N+1 on any_connected_account? - Stepper subtitle update walks to the enclosing dialog before querySelector so two stepper instances don't fight over one header - categories/_form.html.erb data-action targets color-icon-picker, not the non-existent "category" controller UX / visual: - Projection chart drops preserveAspectRatio="none" and pins endDate at today for past-due goals so the today marker stays in-domain - _color_picker / categories form swap non-standard border-1 for border - Goals index search input uses ring-alpha-black-100 (was raw gray-500) Refactors: - Goal#header_summary extracts the multi-line ERB header block - Goal#catch_up_delta_money sums open_pledges in SQL - Goal#projection_summary uses I18n.l for the on-track month label - Account#default_pledge_kind moves the manual/transfer decision out of GoalPledgesController - GoalPledge::Reconciler iterates ordered (created_at, id) so first-claim wins is deterministic under non-sequential PKs - Goals::FundingAccountsBreakdownComponent + Goals::AccountStackComponent use clamp(0..) instead of Float::INFINITY / [x, 0].max - Goals::StatusPillComponent#label provides a titleize fallback - Goal projection chart skips the redundant initial _draw and reuses the snapped point in the past branch (no double-bisect) - Goal pledge preview drops maximumFractionDigits: 0 so USD/EUR show cents while JPY/KRW stay whole-unit - Demo generator captures the Wedding fund goal in the seed loop instead of looking it up by hardcoded name Tests: - GoalPledgeTest: outflow rejection - GoalsControllerTest: cross-currency attachment rejected on update - SweepExpiredGoalPledgesJobTest: cancelled coverage + per-record rescue - GoalTest: pledge_action_label_key flips to manual_save without an unconditional guard
28 lines
794 B
Ruby
28 lines
794 B
Ruby
class Goals::AccountStackComponent < ApplicationComponent
|
|
def initialize(accounts:, max: 3, color_map: nil)
|
|
@accounts = accounts
|
|
@max = max
|
|
@color_map = color_map || {}
|
|
end
|
|
|
|
def shown
|
|
@accounts.first(@max)
|
|
end
|
|
|
|
def extra_count
|
|
(@accounts.size - @max).clamp(0..)
|
|
end
|
|
|
|
def initial_for(account)
|
|
account.name.to_s.strip.first&.upcase || "?"
|
|
end
|
|
|
|
# Color for this account, sourced from the per-goal color map when the
|
|
# caller provided one (so the stack on the index card matches the funding
|
|
# widget on the show page). Falls back to the name-hashed palette pick
|
|
# for backward compatibility with any caller that didn't pass `color_map:`.
|
|
def color_for(account)
|
|
@color_map[account.id] || Goals::AvatarComponent.color_for(account.name)
|
|
end
|
|
end
|