1
0
Fork 0
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:
Josh Brown 2024-04-29 14:56:38 +01:00 committed by GitHub
parent 93953499a6
commit 7f491f5064
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 87 additions and 28 deletions

View file

@ -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,

View file

@ -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

View file

@ -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() {

View file

@ -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

View file

@ -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 %>

View 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>

View file

@ -72,19 +72,23 @@
</ul>
</nav>
<div class="flex flex-col mt-6">
<div class="flex items-center justify-between">
<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(".accounts") %>
<%= t(".portfolio") %>
<% end %>
<span class="font-bold tracking-wide">&bull;</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 %>
<turbo-frame id="account-list" target="_top">
<% account_groups.each do |group| %>
<%= render "accounts/account_list", group: group %>
<% end %>
</turbo-frame>
</div>

View file

@ -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 %>

View file

@ -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 %>

View file

@ -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>

View file

@ -12,4 +12,5 @@ en:
accounts: Accounts
dashboard: Dashboard
new_account: New account
portfolio: Portfolio
transactions: Transactions

View file

@ -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