1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-24 15:49:39 +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:
Zach Gollwitzer 2025-02-21 11:57:59 -05:00 committed by GitHub
parent 8539ac7dec
commit d75be2282b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
278 changed files with 3428 additions and 4354 deletions

View file

@ -1,6 +1,4 @@
class Account::HoldingsController < ApplicationController
layout :with_sidebar
before_action :set_holding, only: %i[show destroy]
def index

View file

@ -0,0 +1,25 @@
class AccountableSparklinesController < ApplicationController
def show
@accountable = Accountable.from_type(params[:accountable_type]&.classify)
@series = Rails.cache.fetch(cache_key) do
family.accounts.active
.where(accountable_type: @accountable.name)
.balance_series(
currency: family.currency,
favorable_direction: @accountable.favorable_direction
)
end
render layout: false
end
private
def family
Current.family
end
def cache_key
family.build_cache_key("#{@accountable.name}_sparkline")
end
end

View file

@ -1,26 +1,11 @@
class AccountsController < ApplicationController
layout :with_sidebar
before_action :set_account, only: %i[sync]
before_action :set_account, only: %i[sync chart sparkline]
def index
@manual_accounts = Current.family.accounts.manual.alphabetically
@plaid_items = Current.family.plaid_items.ordered
end
@manual_accounts = family.accounts.manual.alphabetically
@plaid_items = family.plaid_items.ordered
def summary
@period = Period.from_param(params[:period])
snapshot = Current.family.snapshot(@period)
@net_worth_series = snapshot[:net_worth_series]
@asset_series = snapshot[:asset_series]
@liability_series = snapshot[:liability_series]
@accounts = Current.family.accounts.active
@account_groups = @accounts.by_group(period: @period, currency: Current.family.currency)
end
def list
@period = Period.from_param(params[:period])
render layout: false
render layout: "settings"
end
def sync
@ -32,20 +17,27 @@ class AccountsController < ApplicationController
end
def chart
@account = Current.family.accounts.find(params[:id])
render layout: "application"
end
def sparkline
render layout: false
end
def sync_all
unless Current.family.syncing?
Current.family.sync_later
unless family.syncing?
family.sync_later
end
redirect_to accounts_path
end
private
def family
Current.family
end
def set_account
@account = Current.family.accounts.find(params[:id])
@account = family.accounts.find(params[:id])
end
end

View file

@ -22,12 +22,6 @@ class ApplicationController < ActionController::Base
subscribed_at.present? && subscribed_at <= Time.current && subscribed_at > 1.hour.ago
end
def with_sidebar
return "turbo_rails/frame" if turbo_frame_request?
"with_sidebar"
end
def detect_os
user_agent = request.user_agent
@os = case user_agent

View file

@ -7,7 +7,7 @@ class BudgetCategoriesController < ApplicationController
end
def show
@recent_transactions = @budget.entries
@recent_transactions = @budget.transactions
if params[:id] == BudgetCategory.uncategorized.id
@budget_category = @budget.uncategorized_budget_category
@ -42,6 +42,7 @@ class BudgetCategoriesController < ApplicationController
end
def set_budget
@budget = Current.family.budgets.find(params[:budget_id])
start_date = Budget.param_to_date(params[:budget_month_year])
@budget = Current.family.budgets.find_by(start_date: start_date)
end
end

View file

@ -6,10 +6,6 @@ class BudgetsController < ApplicationController
end
def show
@next_budget = @budget.next_budget
@previous_budget = @budget.previous_budget
@latest_budget = Budget.find_or_bootstrap(Current.family)
render layout: with_sidebar
end
def edit
@ -21,12 +17,6 @@ class BudgetsController < ApplicationController
redirect_to budget_budget_categories_path(@budget)
end
def create
start_date = Date.parse(budget_create_params[:start_date])
@budget = Budget.find_or_bootstrap(Current.family, date: start_date)
redirect_to budget_path(@budget)
end
def picker
render partial: "budgets/picker", locals: {
family: Current.family,
@ -44,12 +34,13 @@ class BudgetsController < ApplicationController
end
def set_budget
@budget = Current.family.budgets.find(params[:id])
@budget.sync_budget_categories
start_date = Budget.param_to_date(params[:month_year])
@budget = Budget.find_or_bootstrap(Current.family, start_date: start_date)
raise ActiveRecord::RecordNotFound unless @budget
end
def redirect_to_current_month_budget
current_budget = Budget.find_or_bootstrap(Current.family)
current_budget = Budget.find_or_bootstrap(Current.family, start_date: Date.current)
redirect_to budget_path(current_budget)
end
end

View file

@ -1,12 +1,12 @@
class CategoriesController < ApplicationController
layout :with_sidebar
before_action :set_category, only: %i[edit update destroy]
before_action :set_categories, only: %i[update edit]
before_action :set_transaction, only: :create
def index
@categories = Current.family.categories.alphabetically
render layout: "settings"
end
def new

View file

@ -1,6 +1,4 @@
class Category::DeletionsController < ApplicationController
layout :with_sidebar
before_action :set_category
before_action :set_replacement_category, only: :create

View file

@ -4,7 +4,6 @@ module AccountableResource
included do
include ScrollFocusable
layout :with_sidebar
before_action :set_account, only: [ :show, :edit, :update, :destroy ]
before_action :set_link_token, only: :new
end

View file

@ -13,9 +13,7 @@ module AutoSync
def family_needs_auto_sync?
return false unless Current.family.present?
return false unless Current.family.accounts.any?
Current.family.last_synced_at.blank? ||
Current.family.last_synced_at.to_date < Date.current
(Current.family.last_synced_at&.to_date || 1.day.ago) < Date.current
end
end

View file

@ -2,7 +2,6 @@ module EntryableResource
extend ActiveSupport::Concern
included do
layout :with_sidebar
before_action :set_entry, only: %i[show update destroy]
end

View file

@ -1,11 +0,0 @@
class Help::ArticlesController < ApplicationController
layout :with_sidebar
def show
@article = Help::Article.find(params[:id])
unless @article
head :not_found
end
end
end

View file

@ -10,7 +10,7 @@ class ImportsController < ApplicationController
def index
@imports = Current.family.imports
render layout: with_sidebar
render layout: "settings"
end
def new

View file

@ -1,10 +1,10 @@
class MerchantsController < ApplicationController
layout :with_sidebar
before_action :set_merchant, only: %i[edit update destroy]
def index
@merchants = Current.family.merchants.alphabetically
render layout: "settings"
end
def new

View file

@ -47,7 +47,7 @@ class MfaController < ApplicationController
if action_name.in?(%w[verify verify_code])
"auth"
else
"with_sidebar"
"settings"
end
end
end

View file

@ -1,5 +1,4 @@
class OnboardingsController < ApplicationController
layout "application"
before_action :set_user
before_action :load_invitation

View file

@ -1,40 +1,20 @@
class PagesController < ApplicationController
skip_before_action :authenticate_user!, only: %i[early_access]
layout :with_sidebar, except: %i[early_access]
def dashboard
@period = Period.from_param(params[:period])
snapshot = Current.family.snapshot(@period)
@net_worth_series = snapshot[:net_worth_series]
@asset_series = snapshot[:asset_series]
@liability_series = snapshot[:liability_series]
snapshot_transactions = Current.family.snapshot_transactions
@income_series = snapshot_transactions[:income_series]
@spending_series = snapshot_transactions[:spending_series]
@savings_rate_series = snapshot_transactions[:savings_rate_series]
snapshot_account_transactions = Current.family.snapshot_account_transactions
@top_spenders = snapshot_account_transactions[:top_spenders]
@top_earners = snapshot_account_transactions[:top_earners]
@top_savers = snapshot_account_transactions[:top_savers]
@accounts = Current.family.accounts.active
@account_groups = @accounts.by_group(period: @period, currency: Current.family.currency)
@transaction_entries = Current.family.entries.incomes_and_expenses.limit(6).reverse_chronological
# TODO: Placeholders for trendlines
placeholder_series_data = 10.times.map do |i|
{ date: Date.current - i.days, value: Money.new(0, Current.family.currency) }
end
@investing_series = TimeSeries.new(placeholder_series_data)
@period = Period.from_key(params[:period], fallback: true)
@balance_sheet = Current.family.balance_sheet
@accounts = Current.family.accounts.active.with_attached_logo
end
def changelog
@release_notes = Provider::Github.new.fetch_latest_release_notes
render layout: "settings"
end
def feedback
render layout: "settings"
end
def early_access

View file

@ -1,4 +1,6 @@
class Settings::BillingsController < SettingsController
class Settings::BillingsController < ApplicationController
layout "settings"
def show
@user = Current.user
end

View file

@ -1,4 +1,6 @@
class Settings::HostingsController < SettingsController
class Settings::HostingsController < ApplicationController
layout "settings"
before_action :raise_if_not_self_hosted
def show

View file

@ -1,4 +1,6 @@
class Settings::PreferencesController < SettingsController
class Settings::PreferencesController < ApplicationController
layout "settings"
def show
@user = Current.user
end

View file

@ -1,4 +1,6 @@
class Settings::ProfilesController < SettingsController
class Settings::ProfilesController < ApplicationController
layout "settings"
def show
@user = Current.user
@users = Current.family.users.order(:created_at)

View file

@ -1,4 +1,6 @@
class Settings::SecuritiesController < SettingsController
class Settings::SecuritiesController < ApplicationController
layout "settings"
def show
end
end

View file

@ -1,3 +0,0 @@
class SettingsController < ApplicationController
layout :with_sidebar
end

View file

@ -1,6 +1,4 @@
class Tag::DeletionsController < ApplicationController
layout :with_sidebar
before_action :set_tag
before_action :set_replacement_tag, only: :create

View file

@ -1,10 +1,10 @@
class TagsController < ApplicationController
layout :with_sidebar
before_action :set_tag, only: %i[edit update destroy]
def index
@tags = Current.family.tags.alphabetically
render layout: "settings"
end
def new

View file

@ -1,34 +1,26 @@
class TransactionsController < ApplicationController
include ScrollFocusable
layout :with_sidebar
before_action :store_params!, only: :index
def index
@q = search_params
search_query = Current.family.transactions.search(@q).active
transactions_query = Current.family.transactions.active.search(@q)
set_focused_record(search_query, params[:focused_record_id], default_per_page: 50)
set_focused_record(transactions_query, params[:focused_record_id], default_per_page: 50)
@pagy, @transaction_entries = pagy(
search_query.reverse_chronological.preload(
:account,
entryable: [
:category, :merchant, :tags,
:transfer_as_inflow,
transfer_as_outflow: {
inflow_transaction: { entry: :account },
outflow_transaction: { entry: :account }
}
]
),
@pagy, @transactions = pagy(
transactions_query.includes(
{ entry: :account },
:category, :merchant, :tags,
transfer_as_outflow: { inflow_transaction: { entry: :account } },
transfer_as_inflow: { outflow_transaction: { entry: :account } }
).reverse_chronological,
limit: params[:per_page].presence || default_params[:per_page],
params: ->(params) { params.except(:focused_record_id) }
)
@transfers = @transaction_entries.map { |entry| entry.entryable.transfer_as_outflow }.compact
@totals = search_query.stats(Current.family.currency)
@totals = Current.family.income_statement.totals(transactions_scope: transactions_query)
end
def clear_filter

View file

@ -1,6 +1,4 @@
class TransfersController < ApplicationController
layout :with_sidebar
before_action :set_transfer, only: %i[destroy show update]
def new

View file

@ -19,7 +19,10 @@ class UsersController < ApplicationController
@user.update!(user_params.except(:redirect_to, :delete_profile_image))
@user.profile_image.purge if should_purge_profile_image?
handle_redirect(t(".success"))
respond_to do |format|
format.html { handle_redirect(t(".success")) }
format.json { head :ok }
end
end
end
@ -57,7 +60,7 @@ class UsersController < ApplicationController
def user_params
params.require(:user).permit(
:first_name, :last_name, :email, :profile_image, :redirect_to, :delete_profile_image, :onboarded_at,
:first_name, :last_name, :email, :profile_image, :redirect_to, :delete_profile_image, :onboarded_at, :show_sidebar,
family_attributes: [ :name, :currency, :country, :locale, :date_format, :timezone, :id, :data_enrichment_enabled ]
)
end