mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-24 07:39:39 +02:00
Add nice formatting for subtypes on account list (#2138)
* Add nice formatting for subtypes on account list * Fix rubocop linting errors * Implement better mapping * Fix rubocop linting * Add short and long versions of subtypes * Simplify subtype reference Co-authored-by: Zach Gollwitzer <zach.gollwitzer@gmail.com> Signed-off-by: Alex Hatzenbuhler <hatz@hey.com> * Simplify reference logic, add a small test * Fix test * Fix tests --------- Signed-off-by: Alex Hatzenbuhler <hatz@hey.com> Co-authored-by: Zach Gollwitzer <zach.gollwitzer@gmail.com>
This commit is contained in:
parent
db34f6d7a2
commit
47aeaf8cea
12 changed files with 83 additions and 30 deletions
|
@ -155,6 +155,16 @@ class Account < ApplicationRecord
|
|||
first_valuation&.amount_money || balance_money
|
||||
end
|
||||
|
||||
# Get short version of the subtype label
|
||||
def short_subtype_label
|
||||
accountable_class.short_subtype_label_for(subtype) || accountable_class.display_name
|
||||
end
|
||||
|
||||
# Get long version of the subtype label
|
||||
def long_subtype_label
|
||||
accountable_class.long_subtype_label_for(subtype) || accountable_class.display_name
|
||||
end
|
||||
|
||||
private
|
||||
def sync_balances
|
||||
strategy = linked? ? :reverse : :forward
|
||||
|
|
|
@ -59,6 +59,7 @@ class BalanceSheet
|
|||
account.define_singleton_method(:weight) do
|
||||
classification_total.zero? ? 0 : account.converted_balance / classification_total.to_d * 100
|
||||
end
|
||||
|
||||
account
|
||||
end.sort_by(&:weight).reverse
|
||||
)
|
||||
|
|
|
@ -3,6 +3,9 @@ module Accountable
|
|||
|
||||
TYPES = %w[Depository Investment Crypto Property Vehicle OtherAsset CreditCard Loan OtherLiability]
|
||||
|
||||
# Define empty hash to ensure all accountables have this defined
|
||||
SUBTYPES = {}.freeze
|
||||
|
||||
def self.from_type(type)
|
||||
return nil unless TYPES.include?(type)
|
||||
type.constantize
|
||||
|
@ -27,6 +30,24 @@ module Accountable
|
|||
raise NotImplementedError, "Accountable must implement #color"
|
||||
end
|
||||
|
||||
# Given a subtype, look up the label for this accountable type
|
||||
def subtype_label_for(subtype, format: :short)
|
||||
return nil if subtype.nil?
|
||||
|
||||
label_type = format == :long ? :long : :short
|
||||
self::SUBTYPES[subtype]&.fetch(label_type, nil)
|
||||
end
|
||||
|
||||
# Convenience method for getting the short label
|
||||
def short_subtype_label_for(subtype)
|
||||
subtype_label_for(subtype, format: :short)
|
||||
end
|
||||
|
||||
# Convenience method for getting the long label
|
||||
def long_subtype_label_for(subtype)
|
||||
subtype_label_for(subtype, format: :long)
|
||||
end
|
||||
|
||||
def favorable_direction
|
||||
classification == "asset" ? "up" : "down"
|
||||
end
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
class Depository < ApplicationRecord
|
||||
include Accountable
|
||||
|
||||
SUBTYPES = [
|
||||
[ "Checking", "checking" ],
|
||||
[ "Savings", "savings" ]
|
||||
].freeze
|
||||
SUBTYPES = {
|
||||
"checking" => { short: "Checking", long: "Checking" },
|
||||
"savings" => { short: "Savings", long: "Savings" }
|
||||
}.freeze
|
||||
|
||||
class << self
|
||||
def display_name
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
class Investment < ApplicationRecord
|
||||
include Accountable
|
||||
|
||||
SUBTYPES = [
|
||||
[ "Brokerage", "brokerage" ],
|
||||
[ "Pension", "pension" ],
|
||||
[ "Retirement", "retirement" ],
|
||||
[ "401(k)", "401k" ],
|
||||
[ "Traditional 401(k)", "traditional_401k" ],
|
||||
[ "Roth 401(k)", "roth_401k" ],
|
||||
[ "529 Plan", "529_plan" ],
|
||||
[ "Health Savings Account", "hsa" ],
|
||||
[ "Mutual Fund", "mutual_fund" ],
|
||||
[ "Traditional IRA", "traditional_ira" ],
|
||||
[ "Roth IRA", "roth_ira" ],
|
||||
[ "Angel", "angel" ]
|
||||
].freeze
|
||||
SUBTYPES = {
|
||||
"brokerage" => { short: "Brokerage", long: "Brokerage" },
|
||||
"pension" => { short: "Pension", long: "Pension" },
|
||||
"retirement" => { short: "Retirement", long: "Retirement" },
|
||||
"401k" => { short: "401(k)", long: "401(k)" },
|
||||
"traditional_401k" => { short: "Traditional 401(k)", long: "Traditional 401(k)" },
|
||||
"roth_401k" => { short: "Roth 401(k)", long: "Roth 401(k)" },
|
||||
"529_plan" => { short: "529 Plan", long: "529 Plan" },
|
||||
"hsa" => { short: "HSA", long: "Health Savings Account" },
|
||||
"mutual_fund" => { short: "Mutual Fund", long: "Mutual Fund" },
|
||||
"traditional_ira" => { short: "Traditional IRA", long: "Traditional IRA" },
|
||||
"roth_ira" => { short: "Roth IRA", long: "Roth IRA" },
|
||||
"angel" => { short: "Angel", long: "Angel" }
|
||||
}.freeze
|
||||
|
||||
class << self
|
||||
def color
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
class Property < ApplicationRecord
|
||||
include Accountable
|
||||
|
||||
SUBTYPES = [
|
||||
[ "Single Family Home", "single_family_home" ],
|
||||
[ "Multi-Family Home", "multi_family_home" ],
|
||||
[ "Condominium", "condominium" ],
|
||||
[ "Townhouse", "townhouse" ],
|
||||
[ "Investment Property", "investment_property" ],
|
||||
[ "Second Home", "second_home" ]
|
||||
]
|
||||
SUBTYPES = {
|
||||
"single_family_home" => { short: "Single Family Home", long: "Single Family Home" },
|
||||
"multi_family_home" => { short: "Multi-Family Home", long: "Multi-Family Home" },
|
||||
"condominium" => { short: "Condo", long: "Condominium" },
|
||||
"townhouse" => { short: "Townhouse", long: "Townhouse" },
|
||||
"investment_property" => { short: "Investment Property", long: "Investment Property" },
|
||||
"second_home" => { short: "Second Home", long: "Second Home" }
|
||||
}.freeze
|
||||
|
||||
has_one :address, as: :addressable, dependent: :destroy
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
</p>
|
||||
<% else %>
|
||||
<%= link_to account.name, account, class: [(account.is_active ? "text-primary" : "text-subdued"), "text-sm font-medium hover:underline"], data: { turbo_frame: "_top" } %>
|
||||
<% if account.long_subtype_label %>
|
||||
<p class="text-sm text-secondary truncate"><%= account.long_subtype_label %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
<div class="min-w-0 grow">
|
||||
<%= tag.p account.name, class: "text-sm text-primary font-medium mb-0.5 truncate" %>
|
||||
<%= tag.p account.subtype&.humanize.presence || account_group.name, class: "text-sm text-secondary truncate" %>
|
||||
<%= tag.p account.short_subtype_label, class: "text-sm text-secondary truncate" %>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto text-right grow h-10">
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
<%= render "accounts/form", account: account, url: url do |form| %>
|
||||
<%= form.select :subtype,
|
||||
Depository::SUBTYPES,
|
||||
Depository::SUBTYPES.map { |k, v| [v[:long], k] },
|
||||
{ label: true, prompt: t("depositories.form.subtype_prompt"), include_blank: t("depositories.form.none") } %>
|
||||
<% end %>
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
<%= render "accounts/form", account: account, url: url do |form| %>
|
||||
<%= form.select :subtype,
|
||||
Investment::SUBTYPES,
|
||||
Investment::SUBTYPES.map { |k, v| [v[:long], k] },
|
||||
{ label: true, prompt: t("investments.form.subtype_prompt"), include_blank: t("investments.form.none") } %>
|
||||
<% end %>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<%= render "accounts/form", account: account, url: url do |form| %>
|
||||
<%= form.select :subtype,
|
||||
Property::SUBTYPES,
|
||||
Property::SUBTYPES.map { |k, v| [v[:long], k] },
|
||||
{ label: true, prompt: t("properties.form.subtype_prompt"), include_blank: t("properties.form.none") } %>
|
||||
|
||||
<hr class="my-4">
|
||||
|
|
|
@ -13,4 +13,22 @@ class AccountTest < ActiveSupport::TestCase
|
|||
@account.destroy
|
||||
end
|
||||
end
|
||||
|
||||
test "gets short/long subtype label" do
|
||||
account = @family.accounts.create!(
|
||||
name: "Test Investment",
|
||||
balance: 1000,
|
||||
currency: "USD",
|
||||
subtype: "hsa",
|
||||
accountable: Investment.new
|
||||
)
|
||||
|
||||
assert_equal "HSA", account.short_subtype_label
|
||||
assert_equal "Health Savings Account", account.long_subtype_label
|
||||
|
||||
# Test with nil subtype
|
||||
account.update!(subtype: nil)
|
||||
assert_equal "Investments", account.short_subtype_label
|
||||
assert_equal "Investments", account.long_subtype_label
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue