1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-25 08:09:38 +02:00

Rework account views and addition flow (#1324)

* Move accountable partials

* Split accountables into separate view partials

* Fix test

* Add form to permitted partials

* Fix failing system tests

* Update new account modal views

* New sync algorithm implementation

* Update account system test assertions to match new behavior

* Fix off by 1 date error

* Revert new balance sync algorithm

* Add missing account overviews
This commit is contained in:
Zach Gollwitzer 2024-10-18 14:37:42 -04:00 committed by GitHub
parent c7c281073f
commit e8e100e1d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
88 changed files with 763 additions and 526 deletions

View file

@ -30,7 +30,7 @@
<% group.children.sort_by(&:name).each do |account_value_node| %>
<% account = account_value_node.original %>
<%= link_to account_path(account), class: "flex items-center w-full gap-3 px-3 py-2 mb-1 hover:bg-gray-100 rounded-[10px]" do %>
<%= image_tag account_logo_url(account), class: "w-6 h-6" %>
<%= render "accounts/logo", account: account, size: "sm" %>
<div>
<p class="font-medium"><%= account_value_node.name %></p>
<% if account.subtype %>
@ -63,7 +63,7 @@
<% end %>
<%= link_to new_account_path(step: "method", type: type.name.demodulize), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
<%= lucide_icon("plus", class: "w-5 h-5") %>
<p>New <%= type.model_name.human.downcase %></p>
<%= t(".new_account", type: type.model_name.human.downcase) %>
<% end %>
</details>
<% end %>

View file

@ -1,5 +1,4 @@
<%= link_to new_account_path(
step: "method",
type: type.class.name.demodulize,
institution_id: params[:institution_id]
),

View file

@ -3,7 +3,7 @@
<%= tag.p t(".no_accounts"), class: "text-gray-900 mb-1 font-medium" %>
<%= tag.p t(".empty_message"), class: "text-gray-500 mb-4" %>
<%= link_to new_account_path, class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %>
<%= link_to new_account_path(step: "method"), class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %>
<%= lucide_icon("plus", class: "w-5 h-5") %>
<span><%= t(".new_account") %></span>
<% end %>

View file

@ -1,12 +1,14 @@
<% if local_assigns[:disabled] && disabled %>
<span class="flex items-center w-full gap-4 p-2 px-2 text-center border border-transparent rounded-lg cursor-not-allowed focus:outline-none focus:bg-gray-50 focus:border focus:border-gray-200 hover:bg-gray-50">
<%# locals: (text:, icon:, disabled: false) %>
<% if disabled %>
<span class="flex items-center w-full gap-4 p-2 px-2 text-center border border-transparent rounded-lg cursor-not-allowed focus:outline-none focus:bg-gray-50 focus:border focus:border-gray-200 text-gray-400">
<span class="flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.02)]">
<%= lucide_icon(icon, class: "text-gray-500 w-5 h-5") %>
</span>
<%= text %>
</span>
<% else %>
<%= link_to new_account_path(type: type.class.name.demodulize, institution_id: params[:institution_id]), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %>
<%= link_to new_account_path(institution_id: params[:institution_id]), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %>
<span class="flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.02)]">
<%= lucide_icon(icon, class: "text-gray-500 w-5 h-5") %>
</span>

View file

@ -2,8 +2,8 @@
<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow", data: { turbo: false } do |f| %>
<div class="grow space-y-2">
<%= f.hidden_field :accountable_type %>
<%= f.text_field :name, placeholder: t(".name_placeholder"), required: "required", label: t(".name_label"), autofocus: true %>
<%= f.select :accountable_type, Accountable::TYPES.map { |type| [type.titleize, type] }, { label: t(".accountable_type"), prompt: t(".type_prompt") }, required: true, autofocus: true %>
<%= f.text_field :name, placeholder: t(".name_placeholder"), required: "required", label: t(".name_label") %>
<% if account.new_record? %>
<%= f.hidden_field :institution_id %>
@ -13,15 +13,10 @@
<%= f.money_field :balance, label: t(".balance"), required: true, default_currency: Current.family.currency %>
<% if account.new_record? %>
<div class="flex items-center gap-2 mt-3 mb-6">
<div class="w-1/2"><%= f.date_field :start_date, label: t(".start_date"), max: Date.yesterday, min: Account::Entry.min_supported_date %></div>
<div class="w-1/2"><%= f.money_field :start_balance, label: t(".start_balance"), placeholder: 90, hide_currency: true, default_currency: Current.family.currency %></div>
</div>
<% if account.accountable %>
<%= render permitted_accountable_partial(account, "form"), f: f %>
<% end %>
<%= render "accounts/accountables/#{permitted_accountable_partial(account.accountable_type)}", f: f %>
</div>
<%= f.submit "#{account.new_record? ? "Add" : "Update"} #{account.accountable.model_name.human.downcase}" %>
<%= f.submit %>
<% end %>

View file

@ -13,7 +13,7 @@
<% end %>
<%= link_to new_account_path, class: "rounded-lg bg-gray-900 text-white flex items-center gap-1 justify-center hover:bg-gray-700 px-3 py-2", data: { turbo_frame: :modal } do %>
<%= link_to new_account_path(step: "method"), class: "rounded-lg bg-gray-900 text-white flex items-center gap-1 justify-center hover:bg-gray-700 px-3 py-2", data: { turbo_frame: :modal } do %>
<%= lucide_icon("plus", class: "w-5 h-5") %>
<p class="text-sm font-medium"><%= t(".new") %></p>
<% end %>

View file

@ -0,0 +1,14 @@
<%# locals: (account:, size: "md") %>
<% size_classes = {
"sm" => "w-6 h-6",
"md" => "w-9 h-9",
"lg" => "w-10 h-10",
"full" => "w-full h-full"
} %>
<% if account.logo.attached? %>
<%= image_tag account.logo, class: size_classes[size] %>
<% else %>
<%= circle_logo(account.name, hex: account.accountable.color, size: size) %>
<% end %>

View file

@ -0,0 +1,33 @@
<%# locals: (account:) %>
<%= contextual_menu do %>
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
<%= link_to edit_account_path(account),
data: { turbo_frame: :modal },
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %>
<span><%= t(".edit") %></span>
<% end %>
<%= link_to new_import_path,
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
<%= lucide_icon "download", class: "w-5 h-5 text-gray-500" %>
<span><%= t(".import") %></span>
<% end %>
<%= button_to account_path(account),
method: :delete,
class: "block w-full py-2 px-3 space-x-2 text-red-600 hover:bg-red-50 flex items-center rounded-lg",
data: {
turbo_confirm: {
title: t(".confirm_title"),
body: t(".confirm_body_html"),
accept: t(".confirm_accept", name: account.name)
}
} do %>
<%= lucide_icon("trash-2", class: "w-5 h-5 mr-2") %> Delete account
<% end %>
</div>
<% end %>

View file

@ -0,0 +1,8 @@
<div class="flex items-center gap-2 rounded-xl justify-between shadow-xs bg-white p-4 border border-alpha-black-25">
<p class="text-lg font-medium text-gray-900">Setup your new account</p>
<div class="flex items-center gap-2">
<%= link_to "Track balances only", new_account_valuation_path(@account), class: "btn btn--ghost", data: { turbo_frame: dom_id(@account.entries.account_valuations.new) } %>
<%= link_to "Add your first transaction", new_transaction_path(account_id: @account.id), class: "btn btn--primary", data: { turbo_frame: :modal } %>
</div>
</div>

View file

@ -1,4 +1,4 @@
<%= button_to sync_all_accounts_path, class: "btn btn--outline flex items-center gap-2", title: "Sync All" do %>
<%= button_to sync_all_accounts_path, class: "btn btn--outline flex items-center gap-2", title: t(".sync") do %>
<%= lucide_icon "refresh-cw", class: "w-5 h-5" %>
<span><%= t("accounts.sync_all.button_text") %></span>
<span><%= t(".sync") %></span>
<% end %>

View file

@ -0,0 +1,7 @@
<div class="flex items-center gap-3">
<%= render "accounts/logo", account: account %>
<div>
<h2 class="font-medium text-xl"><%= account.name %></h2>
</div>
</div>

View file

@ -0,0 +1,7 @@
<%# locals: (account:) %>
<% if account.transactions.any? %>
<%= render "accounts/accountables/transactions", account: account %>
<% else %>
<%= render "accounts/accountables/valuations", account: account %>
<% end %>

View file

@ -0,0 +1,8 @@
<%# locals: (account:, key:, is_selected:) %>
<%= link_to key.titleize,
account_path(account, tab: key),
class: [
"px-2 py-1.5 rounded-md border border-transparent",
"bg-white shadow-xs border-alpha-black-50": is_selected
] %>

View file

@ -0,0 +1,5 @@
<%# locals: (account:) %>
<%= turbo_frame_tag dom_id(account, :transactions), src: account_transactions_path(account) do %>
<%= render "account/entries/loading" %>
<% end %>

View file

@ -0,0 +1,5 @@
<%# locals: (account:) %>
<%= turbo_frame_tag dom_id(account, :valuations), src: account_valuations_path(account) do %>
<%= render "account/entries/loading" %>
<% end %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -25,3 +25,7 @@
<%= format_money(account.credit_card.annual_fee_money || Money.new(0, account.currency)) %>
<% end %>
</div>
<div class="flex justify-center py-8">
<%= link_to "Edit account details", edit_account_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
</div>

View file

@ -0,0 +1,15 @@
<%# locals: (account:, selected_tab:) %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
<%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
</div>
<div class="min-h-[800px]">
<% case selected_tab %>
<% when nil, "overview" %>
<%= render "accounts/accountables/credit_card/overview", account: account %>
<% when "transactions" %>
<%= render "accounts/accountables/transactions", account: account %>
<% end %>
</div>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_tabs", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_tabs", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -0,0 +1,28 @@
<%# locals: (account:, selected_tab:) %>
<% if account.entries.account_trades.any? || account.entries.account_transactions.any? %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<%= render "accounts/accountables/tab", account: account, key: "holdings", is_selected: selected_tab.in?([nil, "holdings"]) %>
<%= render "accounts/accountables/tab", account: account, key: "cash", is_selected: selected_tab == "cash" %>
<%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
</div>
<div class="min-h-[800px]">
<% case selected_tab %>
<% when nil, "holdings" %>
<%= turbo_frame_tag dom_id(account, :holdings), src: account_holdings_path(account) do %>
<%= render "account/entries/loading" %>
<% end %>
<% when "cash" %>
<%= turbo_frame_tag dom_id(account, :cash), src: account_cashes_path(account) do %>
<%= render "account/entries/loading" %>
<% end %>
<% when "transactions" %>
<%= turbo_frame_tag dom_id(account, :trades), src: account_trades_path(account) do %>
<%= render "account/entries/loading" %>
<% end %>
<% end %>
</div>
<% else %>
<%= render "accounts/accountables/valuations", account: account %>
<% end %>

View file

@ -1,4 +1,5 @@
<%# locals: (account:) -%>
<div data-controller="tooltip" data-tooltip-placement-value="right" data-tooltip-offset-value=10 data-tooltip-cross-axis-value=50>
<%= lucide_icon("info", class: "w-4 h-4 shrink-0 text-gray-500") %>
<div role="tooltip" data-tooltip-target="tooltip" class="tooltip bg-gray-700 text-sm p-2 rounded w-64">

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -43,3 +43,7 @@
<%= account.loan.rate_type&.titleize || t(".unknown") %>
<% end %>
</div>
<div class="flex justify-center py-8">
<%= link_to "Edit account details", edit_account_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
</div>

View file

@ -0,0 +1,15 @@
<%# locals: (account:, selected_tab:) %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
<%= render "accounts/accountables/tab", account: account, key: "value", is_selected: selected_tab == "value" %>
</div>
<div class="min-h-[800px]">
<% case selected_tab %>
<% when nil, "overview" %>
<%= render "accounts/accountables/loan/overview", account: account %>
<% when "value" %>
<%= render "accounts/accountables/valuations", account: account %>
<% end %>
</div>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/valuations", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/valuations", account: account %>

View file

@ -0,0 +1,11 @@
<div class="flex items-center gap-3">
<%= render "accounts/logo", account: account %>
<div>
<h2 class="font-medium text-xl"><%= account.name %></h2>
<% if account.property.address&.line1.present? %>
<p class="text-gray-500"><%= account.property.address %></p>
<% end %>
</div>
</div>

View file

@ -27,3 +27,7 @@
<%= account.property.area || t(".unknown") %>
<% end %>
</div>
<div class="flex justify-center py-8">
<%= link_to "Edit account details", edit_account_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
</div>

View file

@ -0,0 +1,15 @@
<%# locals: (account:, selected_tab:) %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
<%= render "accounts/accountables/tab", account: account, key: "value", is_selected: selected_tab == "value" %>
</div>
<div class="min-h-[800px]">
<% case selected_tab %>
<% when nil, "overview" %>
<%= render "accounts/accountables/property/overview", account: account %>
<% when "value" %>
<%= render "accounts/accountables/valuations", account: account %>
<% end %>
</div>

View file

@ -0,0 +1 @@
<%= render "accounts/accountables/default_header", account: account %>

View file

@ -31,3 +31,7 @@
</div>
<% end %>
</div>
<div class="flex justify-center py-8">
<%= link_to "Edit account details", edit_account_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
</div>

View file

@ -0,0 +1,15 @@
<%# locals: (account:, selected_tab:) %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
<%= render "accounts/accountables/tab", account: account, key: "value", is_selected: selected_tab == "value" %>
</div>
<div class="min-h-[800px]">
<% case selected_tab %>
<% when nil, "overview" %>
<%= render "accounts/accountables/vehicle/overview", account: account %>
<% when "value" %>
<%= render "accounts/accountables/valuations", account: account %>
<% end %>
</div>

View file

@ -20,7 +20,7 @@
<%= render "sync_all_button" %>
<%= link_to new_account_path,
<%= link_to new_account_path(step: "method"),
data: { turbo_frame: "modal" },
class: "btn btn--primary flex items-center gap-1" do %>
<%= lucide_icon("plus", class: "w-5 h-5") %>

View file

@ -1,58 +1,24 @@
<h1 class="text-3xl font-semibold font-display"><%= t(".title") %></h1>
<%= modal do %>
<div class="flex flex-col w-screen max-w-xl" data-controller="list-keyboard-navigation">
<% if @account.accountable.blank? %>
<div class="border-b border-alpha-black-25 p-4 text-gray-400">
<%= t ".select_accountable_type" %>
</div>
<div class="flex flex-col p-2 text-sm grow">
<button hidden data-controller="hotkey" data-hotkey="k,K,ArrowUp,ArrowLeft" data-action="list-keyboard-navigation#focusPrevious">Previous</button>
<button hidden data-controller="hotkey" data-hotkey="j,J,ArrowDown,ArrowRight" data-action="list-keyboard-navigation#focusNext">Next</button>
<%= render "account_type", type: Depository.new, bg_color: "bg-blue-500/5", text_color: "text-blue-500", icon: "landmark" %>
<%= render "account_type", type: Investment.new, bg_color: "bg-green-500/5", text_color: "text-green-500", icon: "line-chart" %>
<%= render "account_type", type: Crypto.new, bg_color: "bg-orange-500/5", text_color: "text-orange-500", icon: "bitcoin" %>
<%= render "account_type", type: Property.new, bg_color: "bg-pink-500/5", text_color: "text-pink-500", icon: "home" %>
<%= render "account_type", type: Vehicle.new, bg_color: "bg-cyan-500/5", text_color: "text-cyan-500", icon: "car-front" %>
<%= render "account_type", type: CreditCard.new, bg_color: "bg-violet-500/5", text_color: "text-violet-500", icon: "credit-card" %>
<%= render "account_type", type: Loan.new, bg_color: "bg-yellow-500/5", text_color: "text-yellow-500", icon: "hand-coins" %>
<%= render "account_type", type: OtherAsset.new, bg_color: "bg-green-500/5", text_color: "text-green-500", icon: "plus" %>
<%= render "account_type", type: OtherLiability.new, bg_color: "bg-red-500/5", text_color: "text-red-500", icon: "minus" %>
</div>
<div class="border-t border-alpha-black-25 p-4 text-gray-500 text-sm flex justify-between">
<div class="flex space-x-5">
<div class="flex items-center space-x-2">
<span>Select</span>
<kbd class="bg-alpha-black-50 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.1)] p-1 rounded-md flex w-5 h-5 shrink-0 grow-0 items-center justify-center"><%= lucide_icon("corner-down-left", class: "inline w-3 h-3") %></kbd>
</div>
<div class="flex items-center space-x-2">
<span>Navigate</span>
<kbd class="bg-alpha-black-50 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.1)] p-1 rounded-md flex w-5 h-5 shrink-0 grow-0 items-center justify-center"><%= lucide_icon("arrow-up", class: "inline w-3 h-3") %></kbd>
<kbd class="bg-alpha-black-50 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.1)] p-1 rounded-md flex w-5 h-5 shrink-0 grow-0 items-center justify-center"><%= lucide_icon("arrow-down", class: "inline w-3 h-3") %></kbd>
</div>
</div>
<div class="flex items-center space-x-2">
<button data-action="modal#close">Close</button>
<kbd class="bg-alpha-black-50 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.1)] p-1 rounded-md flex w-8 h-5 shrink-0 grow-0 items-center justify-center text-xs">ESC</kbd>
</div>
</div>
<% elsif params[:step] == 'method' && @account.accountable.present? %>
<% if params[:step] == 'method' %>
<div class="border-b border-alpha-black-25 p-4 text-gray-400 flex items-center space-x-3">
<%= link_to new_account_path, class: "flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 back focus:outline-gray-300 focus:outline" do %>
<%= lucide_icon("arrow-left", class: "text-gray-500 w-5 h-5") %>
<% end %>
<span>How would you like to add it?</span>
</div>
<div class="flex flex-col p-2 text-sm grow">
<button hidden data-controller="hotkey" data-hotkey="k,K,ArrowUp,ArrowLeft" data-action="list-keyboard-navigation#focusPrevious">Previous</button>
<button hidden data-controller="hotkey" data-hotkey="j,J,ArrowDown,ArrowRight" data-action="list-keyboard-navigation#focusNext">Next</button>
<%= render "entry_method", type: @account.accountable, text: "Enter account balance manually", icon: "keyboard" %>
<%= link_to new_import_path, class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %>
<%= render "entry_method", text: t(".manual_entry"), icon: "keyboard" %>
<%= link_to new_import_path(import: { type: "AccountImport" }), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %>
<span class="flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.02)]">
<%= lucide_icon("sheet", class: "text-gray-500 w-5 h-5") %>
</span>
Upload CSV
<%= t(".csv_entry") %>
<% end %>
<%= render "entry_method", type: @account.accountable, text: "Securely link bank account with data provider (coming soon)", icon: "link-2", disabled: true %>
<%= render "entry_method", text: t(".connected_entry"), icon: "link-2", disabled: true %>
</div>
<div class="border-t border-alpha-black-25 p-4 text-gray-500 text-sm flex justify-between">
<div class="flex space-x-5">
@ -73,13 +39,13 @@
</div>
<% else %>
<div class="border-b border-alpha-black-25 p-4 text-gray-800 flex items-center space-x-3">
<%= link_to new_account_path(step: "method", type: params[:type]), class: "flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 focus:outline-gray-300 focus:outline" do %>
<%= link_to new_account_path(step: "method"), class: "flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 focus:outline-gray-300 focus:outline" do %>
<%= lucide_icon("arrow-left", class: "text-gray-500 w-5 h-5") %>
<% end %>
<span>Add <%= @account.accountable.model_name.human.downcase %></span>
<span>Add account</span>
</div>
<div class="p-4 pt-1">
<div class="p-4">
<%= render "form", account: @account, url: new_account_form_url(@account) %>
</div>
<% end %>

View file

@ -1,56 +1,25 @@
<%= turbo_stream_from @account %>
<%= tag.div id: dom_id(@account), class: "space-y-4" do %>
<header class="flex justify-between items-center">
<div class="flex items-center gap-3">
<%= image_tag account_logo_url(@account), class: "w-8 h-8" %>
<div>
<h2 class="font-medium text-xl"><%= @account.name %></h2>
<% series = @account.series(period: @period) %>
<% trend = series.trend %>
<% if @account.property? && @account.property.address&.line1.present? %>
<p class="text-gray-500"><%= @account.property.address %></p>
<% end %>
</div>
</div>
<div class="flex items-center gap-3">
<%= tag.div id: dom_id(@account), class: "space-y-4" do %>
<header class="flex items-center gap-4">
<%= render permitted_accountable_partial(@account, "header"), account: @account %>
<div class="flex items-center gap-3 ml-auto">
<%= button_to sync_account_path(@account), method: :post, class: "flex items-center gap-2", title: "Sync Account" do %>
<%= lucide_icon "refresh-cw", class: "w-4 h-4 text-gray-500 hover:text-gray-400" %>
<% end %>
<%= contextual_menu do %>
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
<%= link_to edit_account_path(@account),
data: { turbo_frame: :modal },
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %>
<span><%= t(".edit") %></span>
<% end %>
<%= link_to new_import_path,
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
<%= lucide_icon "download", class: "w-5 h-5 text-gray-500" %>
<span><%= t(".import") %></span>
<% end %>
<%= button_to account_path(@account),
method: :delete,
class: "block w-full py-2 px-3 space-x-2 text-red-600 hover:bg-red-50 flex items-center rounded-lg",
data: {
turbo_confirm: {
title: t(".confirm_title"),
body: t(".confirm_body_html"),
accept: t(".confirm_accept", name: @account.name)
}
} do %>
<%= lucide_icon("trash-2", class: "w-5 h-5 mr-2") %> Delete account
<% end %>
</div>
<% end %>
<%= render "menu", account: @account %>
</div>
</header>
<% if @account.entries.empty? && @account.depository? %>
<%= render "accounts/new_account_setup_bar", account: @account %>
<% end %>
<% if @account.highest_priority_issue %>
<%= render partial: "issues/issue", locals: { issue: @account.highest_priority_issue } %>
<% end %>
@ -66,47 +35,35 @@
<%= tag.p t(".total_owed"), class: "text-sm font-medium text-gray-500" %>
<% end %>
</div>
<%= render "tooltip", account: @account if @account.investment? %>
<%= render permitted_accountable_partial(@account, "tooltip"), account: @account if @account.investment? %>
</div>
<%= tag.p format_money(@account.value), class: "text-gray-900 text-3xl font-medium" %>
<div>
<% if @series.trend.direction.flat? %>
<% if trend.direction.flat? %>
<%= tag.span t(".no_change"), class: "text-gray-500" %>
<% else %>
<%= tag.span format_money(@series.trend.value), style: "color: #{@trend.color}" %>
<%= tag.span "(#{@trend.percent}%)", style: "color: #{@trend.color}" %>
<%= tag.span format_money(trend.value), style: "color: #{trend.color}" %>
<%= tag.span "(#{trend.percent}%)", style: "color: #{trend.color}" %>
<% end %>
<%= tag.span period_label(@period), class: "text-gray-500" %>
</div>
</div>
<%= form_with url: account_path(@account), method: :get, data: { controller: "auto-submit-form" } do |form| %>
<%= period_select form: form, selected: @period.name %>
<% end %>
</div>
<div class="h-96 flex items-center justify-center text-2xl font-bold">
<%= render partial: "shared/line_chart", locals: { series: @series } %>
<%= render "shared/line_chart", series: @account.series(period: @period) %>
</div>
</div>
<% selected_tab = selected_account_tab(@account) %>
<% selected_tab_key = selected_tab[:key] %>
<% selected_tab_partial_path = selected_tab[:partial_path] %>
<% selected_tab_route = selected_tab[:route] %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<% account_tabs(@account).each do |tab| %>
<%= link_to tab[:label], tab[:path], class: ["px-2 py-1.5 rounded-md border border-transparent", "bg-white shadow-xs border-alpha-black-50": selected_tab_key == tab[:key]] %>
<% end %>
</div>
<div class="min-h-[800px]">
<% if selected_tab_route.present? %>
<%= turbo_frame_tag dom_id(@account, selected_tab_key), src: selected_tab_route do %>
<%= render "account/entries/loading" %>
<% end %>
<% else %>
<%= render selected_tab_partial_path, account: @account %>
<% end %>
<%= render permitted_accountable_partial(@account, "tabs"), account: @account, selected_tab: params[:tab] %>
</div>
<% end %>

View file

@ -41,7 +41,7 @@
<div class="flex justify-between items-center mb-5">
<h2 class="text-lg font-medium text-gray-900">Assets</h2>
<div class="flex items-center gap-2">
<%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
<%= link_to new_account_path(step: "method"), class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
<p><%= t(".new") %></p>
<% end %>
@ -66,7 +66,7 @@
<div class="flex justify-between items-center mb-5">
<h2 class="text-lg font-medium text-gray-900">Liabilities</h2>
<div class="flex items-center gap-2">
<%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
<%= link_to new_account_path(step: "method"), class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
<p><%= t(".new") %></p>
<% end %>