mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-08 23:15:24 +02:00
New Design System + Codebase Refresh (#1823)
Since the very first 0.1.0-alpha.1 release, we've been moving quickly to add new features to the Maybe app. In doing so, some parts of the codebase have become outdated, unnecessary, or overly-complex as a natural result of this feature prioritization. Now that "core" Maybe is complete, we're moving into a second phase of development where we'll be working hard to improve the accuracy of existing features and build additional features on top of "core". This PR is a quick overhaul of the existing codebase aimed to: - Establish the brand new and simplified dashboard view (pictured above) - Establish and move towards the conventions introduced in Cursor rules and project design overview #1788 - Consolidate layouts and improve the performance of layout queries - Organize the core models of the Maybe domain (i.e. Account::Entry, Account::Transaction, etc.) and break out specific traits of each model into dedicated concerns for better readability - Remove stale / dead code from codebase - Remove overly complex code paths in favor of simpler ones
This commit is contained in:
parent
8539ac7dec
commit
d75be2282b
278 changed files with 3428 additions and 4354 deletions
|
@ -1,75 +1,98 @@
|
|||
<%# locals: (entry:, selectable: true, balance_trend: nil) %>
|
||||
<%# locals: (entry:, balance_trend: nil, view_ctx: "global") %>
|
||||
|
||||
<div class="grid grid-cols-12 items-center text-primary text-sm font-medium p-4 <%= @focused_record == entry ? "border border-gray-900 rounded-lg" : "" %>">
|
||||
<div class="pr-10 flex items-center gap-4 <%= balance_trend ? "col-span-6" : "col-span-8" %>">
|
||||
<% if selectable %>
|
||||
<%= check_box_tag dom_id(entry, "selection"),
|
||||
disabled: entry.entryable.transfer?,
|
||||
class: "checkbox checkbox--light",
|
||||
data: { id: entry.id, "bulk-select-target": "row", action: "bulk-select#toggleRowSelection" } %>
|
||||
<% end %>
|
||||
<% transaction = entry.entryable %>
|
||||
|
||||
<div class="max-w-full">
|
||||
<%= content_tag :div, class: ["flex items-center gap-2"] do %>
|
||||
<% if entry.entryable.merchant&.icon_url %>
|
||||
<%= image_tag entry.entryable.merchant.icon_url, class: "w-6 h-6 rounded-full", loading: "lazy" %>
|
||||
<% else %>
|
||||
<%= render "shared/circle_logo", name: entry.display_name, size: "sm" %>
|
||||
<% end %>
|
||||
<%= turbo_frame_tag dom_id(entry) do %>
|
||||
<%= turbo_frame_tag dom_id(transaction) do %>
|
||||
<div class="grid grid-cols-12 items-center text-primary text-sm font-medium p-4
|
||||
<%= @focused_record == entry || @focused_record == transaction ?
|
||||
"border border-gray-900 rounded-lg" : "" %>">
|
||||
|
||||
<div class="truncate">
|
||||
<div class="space-y-0.5">
|
||||
<div class="flex items-center gap-1">
|
||||
<% if entry.new_record? %>
|
||||
<%= content_tag :p, entry.display_name %>
|
||||
<% else %>
|
||||
<%= link_to entry.entryable.transfer? ? entry.entryable.transfer.name : entry.display_name,
|
||||
entry.entryable.transfer? ? transfer_path(entry.entryable.transfer) : account_entry_path(entry),
|
||||
data: { turbo_frame: "drawer", turbo_prefetch: false },
|
||||
class: "hover:underline hover:text-gray-800" %>
|
||||
<% end %>
|
||||
<div class="pr-10 flex items-center gap-4
|
||||
<%= balance_trend ? "col-span-6" : "col-span-8" %>">
|
||||
<%= check_box_tag dom_id(entry, "selection"),
|
||||
disabled: transaction.transfer?,
|
||||
class: "checkbox checkbox--light",
|
||||
data: {
|
||||
id: entry.id,
|
||||
"bulk-select-target": "row",
|
||||
action: "bulk-select#toggleRowSelection"
|
||||
} %>
|
||||
|
||||
<% if entry.excluded %>
|
||||
<span title="One-time <%= entry.amount.negative? ? "income" : "expense" %> (excluded from averages)">
|
||||
<%= lucide_icon "asterisk", class: "w-4 h-4 shrink-0 text-orange-500" %>
|
||||
</span>
|
||||
<% end %>
|
||||
<div class="max-w-full">
|
||||
<%= content_tag :div, class: ["flex items-center gap-2"] do %>
|
||||
<% if transaction.merchant&.icon_url %>
|
||||
<%= image_tag transaction.merchant.icon_url,
|
||||
class: "w-6 h-6 rounded-full",
|
||||
loading: "lazy" %>
|
||||
<% else %>
|
||||
<%= render "shared/circle_logo",
|
||||
name: entry.display_name,
|
||||
size: "sm" %>
|
||||
<% end %>
|
||||
|
||||
<% if entry.entryable.transfer? %>
|
||||
<%= render "account/transactions/transfer_match", entry: entry %>
|
||||
<% end %>
|
||||
<div class="truncate">
|
||||
<div class="space-y-0.5">
|
||||
<div class="flex items-center gap-1">
|
||||
<%= link_to(
|
||||
transaction.transfer? ? transaction.transfer.name : entry.display_name,
|
||||
transaction.transfer? ? transfer_path(transaction.transfer) : account_entry_path(entry),
|
||||
data: {
|
||||
turbo_frame: "drawer",
|
||||
turbo_prefetch: false
|
||||
},
|
||||
class: "hover:underline hover:text-gray-800"
|
||||
) %>
|
||||
|
||||
<% if entry.excluded %>
|
||||
<span title="One-time <%= entry.amount.negative? ? "income" : "expense" %> (excluded from averages)">
|
||||
<%= lucide_icon "asterisk", class: "w-4 h-4 shrink-0 text-orange-500" %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if transaction.transfer? %>
|
||||
<%= render "account/transactions/transfer_match", transaction: transaction %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="text-secondary text-xs font-normal">
|
||||
<% if transaction.transfer? %>
|
||||
<%= render "transfers/account_links",
|
||||
transfer: transaction.transfer,
|
||||
is_inflow: transaction.transfer_as_inflow.present? %>
|
||||
<% else %>
|
||||
<%= link_to entry.account.name,
|
||||
account_path(entry.account, tab: "transactions", focused_record_id: entry.id),
|
||||
data: { turbo_frame: "_top" },
|
||||
class: "hover:underline" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-secondary text-xs font-normal">
|
||||
<% if entry.entryable.transfer? %>
|
||||
<%= render "transfers/account_links", transfer: entry.entryable.transfer, is_inflow: entry.entryable.transfer_as_inflow.present? %>
|
||||
<% else %>
|
||||
<%= link_to entry.account.name, account_path(entry.account, tab: "transactions", focused_record_id: entry.id), data: { turbo_frame: "_top" }, class: "hover:underline" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 col-span-2">
|
||||
<%= render "account/transactions/transaction_category", transaction: transaction %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 ml-auto">
|
||||
<%= content_tag :p,
|
||||
transaction.transfer? && view_ctx == "global" ? "+/- #{format_money(entry.amount_money.abs)}" : format_money(-entry.amount_money),
|
||||
class: ["text-green-600": entry.amount.negative?] %>
|
||||
</div>
|
||||
|
||||
<% if balance_trend %>
|
||||
<div class="col-span-2 justify-self-end">
|
||||
<% if balance_trend.trend %>
|
||||
<%= tag.p format_money(balance_trend.trend.current),
|
||||
class: "font-medium text-sm text-primary" %>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "font-medium text-sm text-gray-400" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1 col-span-2">
|
||||
<%= render "account/transactions/transaction_category", entry: entry %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 ml-auto">
|
||||
<%= content_tag :p,
|
||||
format_money(-entry.amount_money),
|
||||
class: ["text-green-600": entry.amount.negative?] %>
|
||||
</div>
|
||||
|
||||
<% if balance_trend %>
|
||||
<div class="col-span-2 justify-self-end">
|
||||
<% if balance_trend.trend %>
|
||||
<%= tag.p format_money(balance_trend.trend.current), class: "font-medium text-sm text-primary" %>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "font-medium text-sm text-subdued" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<%# locals: (entry:) %>
|
||||
<%# locals: (transaction:) %>
|
||||
|
||||
<div id="<%= dom_id(entry, "category_menu") %>">
|
||||
<% if entry.account_transaction.transfer&.categorizable? || entry.account_transaction.transfer.nil? %>
|
||||
<%= render "categories/menu", transaction: entry.account_transaction %>
|
||||
<div id="<%= dom_id(transaction, "category_menu") %>">
|
||||
<% if transaction.transfer&.categorizable? || transaction.transfer.nil? %>
|
||||
<%= render "categories/menu", transaction: transaction %>
|
||||
<% else %>
|
||||
<%= render "categories/badge", category: entry.account_transaction.transfer&.payment? ? payment_category : transfer_category %>
|
||||
<%= render "categories/badge", category: transaction.transfer&.payment? ? payment_category : transfer_category %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
<%# locals: (entry:) %>
|
||||
<%# locals: (transaction:) %>
|
||||
|
||||
<div id="<%= dom_id(entry, "transfer_match") %>" class="flex items-center gap-1">
|
||||
<% if entry.account_transaction.transfer.confirmed? %>
|
||||
<span title="<%= entry.account_transaction.transfer.payment? ? "Payment" : "Transfer" %> is confirmed">
|
||||
<div id="<%= dom_id(transaction, "transfer_match") %>" class="flex items-center gap-1">
|
||||
<% if transaction.transfer.confirmed? %>
|
||||
<span title="<%= transaction.transfer.payment? ? "Payment" : "Transfer" %> is confirmed">
|
||||
<%= lucide_icon "link-2", class: "w-4 h-4 text-indigo-600" %>
|
||||
</span>
|
||||
<% elsif entry.account_transaction.transfer.pending? %>
|
||||
<% elsif transaction.transfer.pending? %>
|
||||
<span class="inline-flex items-center rounded-full bg-indigo-50 px-2 py-0.5 text-xs font-medium text-indigo-700">
|
||||
Auto-matched
|
||||
</span>
|
||||
|
||||
<%= button_to transfer_path(entry.account_transaction.transfer, transfer: { status: "confirmed" }),
|
||||
<%= button_to transfer_path(transaction.transfer, transfer: { status: "confirmed" }),
|
||||
method: :patch,
|
||||
class: "text-secondary hover:text-gray-800 flex items-center justify-center",
|
||||
class: "text-secondary hover:text-gray-800 flex items-center justify-center cursor-pointer",
|
||||
title: "Confirm match" do %>
|
||||
<%= lucide_icon "check", class: "w-4 h-4 text-indigo-400 hover:text-indigo-600" %>
|
||||
<% end %>
|
||||
|
||||
<%= button_to transfer_path(entry.account_transaction.transfer, transfer: { status: "rejected" }),
|
||||
<%= button_to transfer_path(transaction.transfer, transfer: { status: "rejected" }),
|
||||
method: :patch,
|
||||
data: { turbo: false },
|
||||
class: "text-secondary hover:text-gray-800 flex items-center justify-center",
|
||||
class: "text-secondary hover:text-gray-800 flex items-center justify-center cursor-pointer",
|
||||
title: "Reject match" do %>
|
||||
<%= lucide_icon "x", class: "w-4 h-4 text-subdued hover:text-gray-600" %>
|
||||
<% end %>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<%= turbo_frame_tag "bulk_transaction_edit_drawer" do %>
|
||||
<dialog data-controller="modal"
|
||||
data-action="click->modal#clickOutside"
|
||||
class="bg-white border border-alpha-black-25 rounded-2xl max-h-[calc(100vh-32px)] max-w-[480px] w-full shadow-xs h-full mt-4 mr-4 ml-auto">
|
||||
class="bg-white shadow-border-xs rounded-2xl max-h-[calc(100vh-32px)] max-w-[480px] w-full mt-4 mr-4 ml-auto">
|
||||
<%= styled_form_with url: bulk_update_account_transactions_path, scope: "bulk_update", class: "h-full", data: { turbo_frame: "_top" } do |form| %>
|
||||
<div class="flex h-full flex-col justify-between p-4">
|
||||
<div>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<%= turbo_frame_tag dom_id(@account, "transactions") do %>
|
||||
<div class="bg-white space-y-4 p-5 border border-alpha-black-25 rounded-xl shadow-xs">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="font-medium text-lg"><%= t(".transactions") %></h3>
|
||||
<%= link_to new_account_transaction_path(account_id: @account),
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-primary p-2 rounded-lg",
|
||||
data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-primary") %>
|
||||
<span class="text-sm"><%= t(".new") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div id="transactions" data-controller="bulk-select" data-bulk-select-resource-value="<%= t(".transaction") %>">
|
||||
<div id="transaction-selection-bar" data-bulk-select-target="selectionBar" class="flex justify-center hidden">
|
||||
<%= render "selection_bar" %>
|
||||
</div>
|
||||
|
||||
<% if @entries.empty? %>
|
||||
<p class="text-secondary py-4"><%= t(".no_transactions") %></p>
|
||||
<% else %>
|
||||
<div class="space-y-6">
|
||||
<%= entries_by_date(@entries) do |entries, _transfers| %>
|
||||
<%= render entries %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<%= render "pagination", pagy: @pagy %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
Loading…
Add table
Add a link
Reference in a new issue