mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-04 21:15:19 +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
102
app/models/account/chartable.rb
Normal file
102
app/models/account/chartable.rb
Normal file
|
@ -0,0 +1,102 @@
|
|||
module Account::Chartable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def balance_series(currency:, period: Period.last_30_days, favorable_direction: "up")
|
||||
balances = Account::Balance.find_by_sql([
|
||||
balance_series_query,
|
||||
{
|
||||
start_date: period.start_date,
|
||||
end_date: period.end_date,
|
||||
interval: period.interval,
|
||||
target_currency: currency
|
||||
}
|
||||
])
|
||||
|
||||
balances = gapfill_balances(balances)
|
||||
|
||||
values = [ nil, *balances ].each_cons(2).map do |prev, curr|
|
||||
Series::Value.new(
|
||||
date: curr.date,
|
||||
date_formatted: I18n.l(curr.date, format: :long),
|
||||
trend: Trend.new(
|
||||
current: Money.new(curr.balance, currency),
|
||||
previous: prev.nil? ? nil : Money.new(prev.balance, currency),
|
||||
favorable_direction: favorable_direction
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
Series.new(
|
||||
start_date: period.start_date,
|
||||
end_date: period.end_date,
|
||||
interval: period.interval,
|
||||
trend: Trend.new(
|
||||
current: Money.new(balances.last&.balance || 0, currency),
|
||||
previous: Money.new(balances.first&.balance || 0, currency),
|
||||
favorable_direction: favorable_direction
|
||||
),
|
||||
values: values
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
def balance_series_query
|
||||
<<~SQL
|
||||
WITH dates as (
|
||||
SELECT generate_series(DATE :start_date, DATE :end_date, :interval::interval)::date as date
|
||||
UNION DISTINCT
|
||||
SELECT CURRENT_DATE -- Ensures we always end on current date, regardless of interval
|
||||
)
|
||||
SELECT
|
||||
d.date,
|
||||
SUM(CASE WHEN accounts.classification = 'asset' THEN ab.balance ELSE -ab.balance END * COALESCE(er.rate, 1)) as balance,
|
||||
COUNT(CASE WHEN accounts.currency <> :target_currency AND er.rate IS NULL THEN 1 END) as missing_rates
|
||||
FROM dates d
|
||||
LEFT JOIN accounts ON accounts.id IN (#{all.select(:id).to_sql})
|
||||
LEFT JOIN account_balances ab ON (
|
||||
ab.date = d.date AND
|
||||
ab.currency = accounts.currency AND
|
||||
ab.account_id = accounts.id
|
||||
)
|
||||
LEFT JOIN exchange_rates er ON (
|
||||
er.date = ab.date AND
|
||||
er.from_currency = accounts.currency AND
|
||||
er.to_currency = :target_currency
|
||||
)
|
||||
GROUP BY d.date
|
||||
ORDER BY d.date
|
||||
SQL
|
||||
end
|
||||
|
||||
def gapfill_balances(balances)
|
||||
gapfilled = []
|
||||
|
||||
prev_balance = nil
|
||||
|
||||
[ nil, *balances ].each_cons(2).each_with_index do |(prev, curr), index|
|
||||
if index == 0 && curr.balance.nil?
|
||||
curr.balance = 0 # Ensure all series start with a non-nil balance
|
||||
elsif curr.balance.nil?
|
||||
curr.balance = prev.balance
|
||||
end
|
||||
|
||||
gapfilled << curr
|
||||
end
|
||||
|
||||
gapfilled
|
||||
end
|
||||
end
|
||||
|
||||
def favorable_direction
|
||||
classification == "asset" ? "up" : "down"
|
||||
end
|
||||
|
||||
def balance_series(period: Period.last_30_days)
|
||||
self.class.where(id: self.id).balance_series(
|
||||
currency: currency,
|
||||
period: period,
|
||||
favorable_direction: favorable_direction
|
||||
)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue