1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-19 21:29:38 +02:00
Maybe/app/controllers/pages_controller.rb
Josh Pigford 3cc88f3e98
Fix changelog page crash when GitHub release notes are unavailable (#2314)
* Fix changelog page crash when GitHub release notes are unavailable

* Refactor changelog view to handle missing avatars gracefully and improve session sign-out logic in tests

* Enhance changelog view to display fallback messages for unavailable release notes and publication dates

* Update onboarding system tests to reflect UI changes and improve assertions

- Changed button labels from "Get started" to "Continue" and "Complete" to align with updated UI.
- Updated text assertions for clarity, changing "Set your preferences" to "Configure your preferences".
- Adjusted locale selection options to include language codes.
- Enhanced validation error handling in preferences form.
- Improved navigation assertions to ensure accurate path checks.
2025-05-26 19:53:25 -05:00

158 lines
5.5 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class PagesController < ApplicationController
skip_before_action :authenticate_user!, only: %i[early_access]
include Periodable
def dashboard
@balance_sheet = Current.family.balance_sheet
@accounts = Current.family.accounts.active.with_attached_logo
period_param = params[:cashflow_period]
@cashflow_period = if period_param.present?
begin
Period.from_key(period_param)
rescue Period::InvalidKeyError
Period.last_30_days
end
else
Period.last_30_days
end
family_currency = Current.family.currency
income_totals = Current.family.income_statement.income_totals(period: @cashflow_period)
expense_totals = Current.family.income_statement.expense_totals(period: @cashflow_period)
@cashflow_sankey_data = build_cashflow_sankey_data(income_totals, expense_totals, family_currency)
@breadcrumbs = [ [ "Home", root_path ], [ "Dashboard", nil ] ]
end
def changelog
@release_notes = github_provider.fetch_latest_release_notes
# Fallback if no release notes are available
if @release_notes.nil?
@release_notes = {
avatar: "https://github.com/maybe-finance.png",
username: "maybe-finance",
name: "Release notes unavailable",
published_at: Date.current,
body: "<p>Unable to fetch the latest release notes at this time. Please check back later or visit our <a href='https://github.com/maybe-finance/maybe/releases' target='_blank'>GitHub releases page</a> directly.</p>"
}
end
render layout: "settings"
end
def feedback
render layout: "settings"
end
def early_access
redirect_to root_path if self_hosted?
@invite_codes_count = InviteCode.count
@invite_code = InviteCode.order("RANDOM()").limit(1).first
render layout: false
end
private
def github_provider
Provider::Registry.get_provider(:github)
end
def build_cashflow_sankey_data(income_totals, expense_totals, currency_symbol)
nodes = []
links = []
node_indices = {} # Memoize node indices by a unique key: "type_categoryid"
# Helper to add/find node and return its index
add_node = ->(unique_key, display_name, value, percentage, color) {
node_indices[unique_key] ||= begin
nodes << { name: display_name, value: value.to_f.round(2), percentage: percentage.to_f.round(1), color: color }
nodes.size - 1
end
}
total_income_val = income_totals.total.to_f.round(2)
total_expense_val = expense_totals.total.to_f.round(2)
# --- Create Central Cash Flow Node ---
cash_flow_idx = add_node.call("cash_flow_node", "Cash Flow", total_income_val, 0, "var(--color-success)")
# --- Process Income Side (Top-level categories only) ---
income_totals.category_totals.each do |ct|
# Skip subcategories only include root income categories
next if ct.category.parent_id.present?
val = ct.total.to_f.round(2)
next if val.zero?
percentage_of_total_income = total_income_val.zero? ? 0 : (val / total_income_val * 100).round(1)
node_display_name = ct.category.name
node_color = ct.category.color.presence || Category::COLORS.sample
current_cat_idx = add_node.call(
"income_#{ct.category.id}",
node_display_name,
val,
percentage_of_total_income,
node_color
)
links << {
source: current_cat_idx,
target: cash_flow_idx,
value: val,
color: node_color,
percentage: percentage_of_total_income
}
end
# --- Process Expense Side (Top-level categories only) ---
expense_totals.category_totals.each do |ct|
# Skip subcategories only include root expense categories to keep Sankey shallow
next if ct.category.parent_id.present?
val = ct.total.to_f.round(2)
next if val.zero?
percentage_of_total_expense = total_expense_val.zero? ? 0 : (val / total_expense_val * 100).round(1)
node_display_name = ct.category.name
node_color = ct.category.color.presence || Category::UNCATEGORIZED_COLOR
current_cat_idx = add_node.call(
"expense_#{ct.category.id}",
node_display_name,
val,
percentage_of_total_expense,
node_color
)
links << {
source: cash_flow_idx,
target: current_cat_idx,
value: val,
color: node_color,
percentage: percentage_of_total_expense
}
end
# --- Process Surplus ---
leftover = (total_income_val - total_expense_val).round(2)
if leftover.positive?
percentage_of_total_income_for_surplus = total_income_val.zero? ? 0 : (leftover / total_income_val * 100).round(1)
surplus_idx = add_node.call("surplus_node", "Surplus", leftover, percentage_of_total_income_for_surplus, "var(--color-success)")
links << { source: cash_flow_idx, target: surplus_idx, value: leftover, color: "var(--color-success)", percentage: percentage_of_total_income_for_surplus }
end
# Update Cash Flow and Income node percentages (relative to total income)
if node_indices["cash_flow_node"]
nodes[node_indices["cash_flow_node"]][:percentage] = 100.0
end
# No primary income node anymore, percentages are on individual income cats relative to total_income_val
{ nodes: nodes, links: links, currency_symbol: Money::Currency.new(currency_symbol).symbol }
end
end