mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 14:31:25 +00:00
* Add budget rollover: copy from previous month When navigating to an uninitialized budget month, show a prompt offering to copy amounts from the most recent initialized budget. Copies budgeted_spending, expected_income, and all matching category allocations. Also fixes over-allocation warning showing on uninitialized budgets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Redirect copy_previous to categories wizard for review Matches the normal budget setup flow (edit → categories → show) so users can review/tweak copied allocations before confirming. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Address code review: eager-load categories, guard against overwrite - Add .includes(:budget_categories) to most_recent_initialized_budget to avoid N+1 when copy_from! iterates source categories - Guard copy_previous action against overwriting already-initialized budgets (prevents crafted POST from clobbering existing data) - Add i18n key for already_initialized flash message Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add invariant guards to copy_from! for defensive safety Validate that source budget belongs to the same family and precedes the target budget before copying. Protects against misuse from other callers beyond the controller. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix button overflow on small screens in copy previous prompt Stack buttons vertically on mobile, side-by-side on sm+ breakpoint. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
70 lines
2.6 KiB
Plaintext
70 lines
2.6 KiB
Plaintext
<div class="pb-6 lg:pb-12">
|
|
<%= render "budgets/budget_header",
|
|
budget: @budget,
|
|
previous_budget: @previous_budget,
|
|
next_budget: @next_budget,
|
|
latest_budget: @latest_budget %>
|
|
|
|
<div class="space-y-4">
|
|
<%# Top Section: Donut and Summary side by side %>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<%# Budget Donut %>
|
|
<div class="h-[300px] bg-container rounded-xl shadow-border-xs p-8">
|
|
<% if !@budget.initialized? && @source_budget.present? %>
|
|
<%= render "budgets/copy_previous_prompt", budget: @budget, source_budget: @source_budget %>
|
|
<% elsif @budget.initialized? && @budget.available_to_allocate.negative? %>
|
|
<%= render "budgets/over_allocation_warning", budget: @budget %>
|
|
<% else %>
|
|
<%= render "budgets/budget_donut", budget: @budget %>
|
|
<% end %>
|
|
</div>
|
|
|
|
<%# Actuals Summary %>
|
|
<% if @budget.initialized? && @budget.available_to_allocate.positive? %>
|
|
<%= render DS::Tabs.new(active_tab: params[:tab].presence || "budgeted") do |tabs| %>
|
|
<% tabs.with_nav do |nav| %>
|
|
<% nav.with_btn(id: "budgeted", label: t("budgets.show.tabs.budgeted")) %>
|
|
<% nav.with_btn(id: "actuals", label: t("budgets.show.tabs.actual")) %>
|
|
<% end %>
|
|
|
|
<% tabs.with_panel(tab_id: "budgeted") do %>
|
|
<div class="bg-container rounded-xl shadow-border-xs">
|
|
<%= render "budgets/budgeted_summary", budget: @budget %>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% tabs.with_panel(tab_id: "actuals") do %>
|
|
<div class="bg-container rounded-xl shadow-border-xs">
|
|
<%= render "budgets/actuals_summary", budget: @budget %>
|
|
</div>
|
|
<% end %>
|
|
<% end %>
|
|
<% else %>
|
|
<div class="bg-container rounded-xl shadow-border-xs">
|
|
<%= render "budgets/actuals_summary", budget: @budget %>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<%# Bottom Section: Categories full width %>
|
|
<div class="w-full bg-container rounded-xl shadow-border-xs p-4">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h2 class="text-lg font-medium">Categories</h2>
|
|
|
|
<% if @budget.initialized? %>
|
|
<%= render DS::Link.new(
|
|
text: "Edit",
|
|
variant: "secondary",
|
|
icon: "settings-2",
|
|
href: budget_budget_categories_path(@budget)
|
|
) %>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div class="bg-container-inset rounded-xl p-1">
|
|
<%= render "budgets/budget_categories", budget: @budget %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|