mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 13:19:39 +02:00
Add trends to sidebar account list (#697)
This commit is contained in:
parent
93953499a6
commit
7f491f5064
12 changed files with 87 additions and 28 deletions
|
@ -14,6 +14,9 @@ class AccountsController < ApplicationController
|
|||
@account_groups = Current.family.accounts.by_group(period: @period, currency: Current.family.currency)
|
||||
end
|
||||
|
||||
def list
|
||||
end
|
||||
|
||||
def new
|
||||
@account = Account.new(
|
||||
balance: nil,
|
||||
|
|
|
@ -27,8 +27,8 @@ module ApplicationHelper
|
|||
render partial: "shared/modal", locals: { content: content }
|
||||
end
|
||||
|
||||
def account_groups
|
||||
assets, liabilities = Current.family.accounts.by_group(currency: Current.family.currency, period: Period.last_30_days).values_at(:assets, :liabilities)
|
||||
def account_groups(period: nil)
|
||||
assets, liabilities = Current.family.accounts.by_group(currency: Current.family.currency, period: period || Period.last_30_days).values_at(:assets, :liabilities)
|
||||
[ assets.children, liabilities.children ].flatten
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import * as d3 from "d3"
|
|||
export default class extends Controller {
|
||||
static values = {
|
||||
data: Object,
|
||||
strokeWidth: { type: Number, default: 2 },
|
||||
useLabels: { type: Boolean, default: true },
|
||||
useTooltip: { type: Boolean, default: true },
|
||||
usePercentSign: Boolean
|
||||
|
@ -128,7 +129,7 @@ export default class extends Controller {
|
|||
.attr("d", this.#d3Line)
|
||||
.attr("stroke-linejoin", "round")
|
||||
.attr("stroke-linecap", "round")
|
||||
.attr("stroke-width", 2)
|
||||
.attr("stroke-width", this.strokeWidthValue)
|
||||
}
|
||||
|
||||
#installTrendlineSplit() {
|
||||
|
|
|
@ -39,8 +39,8 @@ class TimeSeries::Trend
|
|||
elsif previous.zero?
|
||||
Float::INFINITY
|
||||
else
|
||||
change = (current_amount - previous_amount).abs
|
||||
base = previous_amount.abs.to_f
|
||||
change = (current_amount - previous_amount)
|
||||
base = previous_amount.to_f
|
||||
|
||||
(change / base * 100).round(1).to_f
|
||||
end
|
||||
|
|
|
@ -8,20 +8,58 @@
|
|||
<div class="text-left"><%= type.model_name.human %></div>
|
||||
<div class="ml-auto flex flex-col items-end">
|
||||
<p class="text-right"><%= format_money group.sum %></p>
|
||||
<div class="flex items-center gap-1">
|
||||
<%=
|
||||
tag.div(
|
||||
id: "#{group.name}_sparkline",
|
||||
class: "h-3 w-8 ml-auto",
|
||||
data: {
|
||||
controller: "time-series-chart",
|
||||
"time-series-chart-data-value": group.series.to_json,
|
||||
"time-series-chart-stroke-width-value": 1,
|
||||
"time-series-chart-use-labels-value": false,
|
||||
"time-series-chart-use-tooltip-value": false
|
||||
}
|
||||
)
|
||||
%>
|
||||
<% styles = trend_styles(group.series.trend) %>
|
||||
<span class="text-xs <%= styles[:text_class] %>"><%= sprintf("%+.2f", group.series.trend.percent) %>%</span>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
<% group.children.each do |account_value_node| %>
|
||||
<%= link_to account_path(account_value_node.original), class: "flex items-center w-full gap-3 px-2 py-3 mb-1 hover:bg-gray-100 rounded-[10px]" do %>
|
||||
<% 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" %>
|
||||
<div>
|
||||
<p class="font-medium"><%= account_value_node.name %></p>
|
||||
<% if account_value_node.original.subtype %>
|
||||
<p class="text-xs text-gray-500"><%= account_value_node.original.subtype&.humanize %></p>
|
||||
<% if account.subtype %>
|
||||
<p class="text-xs text-gray-500"><%= account.subtype&.humanize %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<p class="ml-auto font-medium"><%= format_money account_value_node.original.balance_money %></p>
|
||||
<div class="flex flex-col ml-auto font-medium text-right">
|
||||
<p><%= format_money account.balance_money %></p>
|
||||
<div class="flex items-center gap-1">
|
||||
<%=
|
||||
tag.div(
|
||||
id: dom_id(account, :list_sparkline),
|
||||
class: "h-3 w-8 ml-auto",
|
||||
data: {
|
||||
controller: "time-series-chart",
|
||||
"time-series-chart-data-value": account_value_node.series.to_json,
|
||||
"time-series-chart-stroke-width-value": 1,
|
||||
"time-series-chart-use-labels-value": false,
|
||||
"time-series-chart-use-tooltip-value": false
|
||||
}
|
||||
)
|
||||
%>
|
||||
<% styles = trend_styles(account_value_node.series.trend) %>
|
||||
<span class="text-xs <%= styles[:text_class] %>"><%= sprintf("%+.2f", account_value_node.series.trend.percent) %>%</span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= link_to new_account_path(step: "method", type: type.name.demodulize), class: "flex items-center gap-4 px-2 py-3 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= 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>
|
||||
<% end %>
|
||||
|
|
5
app/views/accounts/list.html.erb
Normal file
5
app/views/accounts/list.html.erb
Normal file
|
@ -0,0 +1,5 @@
|
|||
<turbo-frame id="account-list" target="_top">
|
||||
<% account_groups(period: @period).each do |group| %>
|
||||
<%= render "accounts/account_list", group: group %>
|
||||
<% end %>
|
||||
</turbo-frame>
|
|
@ -72,19 +72,23 @@
|
|||
</ul>
|
||||
</nav>
|
||||
<div class="flex flex-col mt-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<%= link_to accounts_path, class: "text-xs uppercase text-gray-500 font-bold tracking-wide" do %>
|
||||
<%= t(".accounts") %>
|
||||
<% end %>
|
||||
<div class="flex items-center justify-between px-3 py-2 mb-2">
|
||||
<div class="flex items-center gap-2 text-xs uppercase text-gray-500">
|
||||
<%= link_to accounts_path, class: "text-xs uppercase text-gray-500 font-bold tracking-wide" do %>
|
||||
<%= t(".portfolio") %>
|
||||
<% end %>
|
||||
<span class="font-bold tracking-wide">•</span>
|
||||
<%= form_with url: list_accounts_path, method: :get, class: "flex items-center gap-4", data: { controller: "auto-submit-form", turbo_frame: "account-list" } do %>
|
||||
<%= render partial: "shared/period_select", locals: { button_class: "flex items-center gap-1 w-full cursor-pointer font-bold tracking-wide" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= link_to new_account_path, class: "block hover:bg-gray-100 p-2 text-sm font-semibold text-gray-900 flex items-center rounded", title: t(".new_account"), data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= link_to new_account_path, class: "flex items-center gap-4 px-2 py-3 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><%= t(".new_account") %></p>
|
||||
<% end %>
|
||||
<% account_groups.each do |group| %>
|
||||
<%= render "accounts/account_list", group: group %>
|
||||
<% end %>
|
||||
<turbo-frame id="account-list" target="_top">
|
||||
<% account_groups.each do |group| %>
|
||||
<%= render "accounts/account_list", group: group %>
|
||||
<% end %>
|
||||
</turbo-frame>
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<div id="notification-tray" class="fixed z-50 space-y-1 top-6 right-6"></div>
|
||||
<%= safe_join(flash.map { |type, message| notification(message, type: type) }) %>
|
||||
<div class="flex h-full">
|
||||
<div class="p-6 pb-20 w-80 shrink-0 h-full overflow-y-auto">
|
||||
<div class="p-6 pb-20 w-[368px] shrink-0 h-full overflow-y-auto">
|
||||
<% if content_for?(:sidebar) %>
|
||||
<%= yield :sidebar %>
|
||||
<% else %>
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
<%# locals: (value: 'last_30_days') -%>
|
||||
<%# locals: (value: 'last_30_days', button_class: '') -%>
|
||||
<% options = [["7D", "last_7_days"], ["1M", "last_30_days"], ["1Y", "last_365_days"], ["All", "all"]] %>
|
||||
<div data-controller="select" data-select-active-class="bg-alpha-black-50" class="relative" data-select-selected-value="<%= value %>">
|
||||
<button type="button" data-select-target="button" class="flex items-center gap-1 w-full border border-alpha-black-100 shadow-xs rounded-lg text-sm p-2 cursor-pointer">
|
||||
<span data-select-target="buttonText" class="text-gray-900 text-sm"><%= options.find { |option| option[1] == value }[0] %></span>
|
||||
<%=
|
||||
tag.button(
|
||||
type: "button",
|
||||
data: { "select-target": "button" },
|
||||
class: button_class.presence || "flex items-center gap-1 w-full border border-alpha-black-100 shadow-xs rounded-lg text-sm p-2 cursor-pointer text-gray-900 text-sm"
|
||||
) do
|
||||
%>
|
||||
<span data-select-target="buttonText"><%= options.find { |option| option[1] == value }[0] %></span>
|
||||
<%= lucide_icon("chevron-down", class: "w-5 h-5 text-gray-500") %>
|
||||
</button>
|
||||
<% end %>
|
||||
<input type="hidden" name="period" data-select-target="input" data-auto-submit-form-target="auto">
|
||||
<ul data-select-target="list" class="hidden absolute z-10 top-10 right-0 border border-alpha-black-25 bg-white rounded-lg shadow-xs">
|
||||
<ul data-select-target="list" class="hidden absolute z-10 top-[100%] right-0 border border-alpha-black-25 bg-white rounded-lg shadow-xs">
|
||||
<% options.each do |label, value| %>
|
||||
<li tabindex="0" data-select-target="option" data-action="click->select#selectOption" data-value="<%= value %>" class="text-sm text-gray-900 rounded-lg cursor-pointer hover:bg-alpha-black-50 px-5 py-1">
|
||||
<%= label %>
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
<span>No change</span>
|
||||
<% else %>
|
||||
<span><%= styles[:symbol] %><%= trend.value.is_a?(Money) ? format_money(trend.value.abs) : trend.value.abs.round(2) %></span>
|
||||
<span>(<%= lucide_icon(styles[:icon], class: "w-4 h-4 align-text-bottom inline") %><%= trend.percent %>%)</span>
|
||||
<span>(<%= lucide_icon(styles[:icon], class: "w-4 h-4 align-text-bottom inline") %><%= trend.percent.abs %>%)</span>
|
||||
<% end %>
|
||||
</p>
|
||||
|
|
|
@ -12,4 +12,5 @@ en:
|
|||
accounts: Accounts
|
||||
dashboard: Dashboard
|
||||
new_account: New account
|
||||
portfolio: Portfolio
|
||||
transactions: Transactions
|
||||
|
|
|
@ -34,6 +34,7 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :accounts, shallow: true do
|
||||
get :summary, on: :collection
|
||||
get :list, on: :collection
|
||||
post :sync, on: :member
|
||||
resource :logo, only: %i[show], module: :accounts
|
||||
resources :valuations
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue