diff --git a/app/models/budget.rb b/app/models/budget.rb
index 560a5f17..134258ca 100644
--- a/app/models/budget.rb
+++ b/app/models/budget.rb
@@ -133,10 +133,10 @@ class Budget < ApplicationRecord
end
# =============================================================================
- # Budget allocations: How much user has budgeted for all categories combined
+ # Budget allocations: How much user has budgeted for all parent categories combined
# =============================================================================
def allocated_spending
- budget_categories.sum(:budgeted_spending)
+ budget_categories.reject { |bc| bc.subcategory? }.sum(&:budgeted_spending)
end
def allocated_percent
diff --git a/app/models/budget_category.rb b/app/models/budget_category.rb
index a57a3a97..5109198d 100644
--- a/app/models/budget_category.rb
+++ b/app/models/budget_category.rb
@@ -79,4 +79,29 @@ class BudgetCategory < ApplicationRecord
segments
end
+
+ def siblings
+ budget.budget_categories.select { |bc| bc.category.parent_id == category.parent_id && bc.id != id }
+ end
+
+ def max_allocation
+ return nil unless subcategory?
+
+ parent_budget = budget.budget_categories.find { |bc| bc.category.id == category.parent_id }&.budgeted_spending
+ siblings_budget = siblings.sum(&:budgeted_spending)
+
+ [ parent_budget - siblings_budget, 0 ].max
+ end
+
+ def subcategories
+ return BudgetCategory.none unless category.parent_id.nil?
+
+ budget.budget_categories
+ .joins(:category)
+ .where(categories: { parent_id: category.id })
+ end
+
+ def subcategory?
+ category.parent_id.present?
+ end
end
diff --git a/app/views/budget_categories/_budget_category_form.html.erb b/app/views/budget_categories/_budget_category_form.html.erb
index 770d6293..08fd70e0 100644
--- a/app/views/budget_categories/_budget_category_form.html.erb
+++ b/app/views/budget_categories/_budget_category_form.html.erb
@@ -2,7 +2,7 @@
<% currency = Money::Currency.new(budget_category.budget.currency) %>
-
+
class="w-full flex gap-3">
@@ -22,6 +22,7 @@
step: currency.step,
id: dom_id(budget_category, :budgeted_spending),
min: 0,
+ max: budget_category.max_allocation,
data: { auto_submit_form_target: "auto" } %>
diff --git a/app/views/budget_categories/_confirm_button.html.erb b/app/views/budget_categories/_confirm_button.html.erb
new file mode 100644
index 00000000..53c52533
--- /dev/null
+++ b/app/views/budget_categories/_confirm_button.html.erb
@@ -0,0 +1,11 @@
+
+ <% if budget.allocations_valid? %>
+ <%= link_to "Confirm",
+ budget_path(budget),
+ class: "block btn btn--primary w-full text-center" %>
+ <% else %>
+
+ Confirm
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/budget_categories/_uncategorized_budget_category_form.html.erb b/app/views/budget_categories/_uncategorized_budget_category_form.html.erb
index 4e586379..f26a9f80 100644
--- a/app/views/budget_categories/_uncategorized_budget_category_form.html.erb
+++ b/app/views/budget_categories/_uncategorized_budget_category_form.html.erb
@@ -2,7 +2,7 @@
<% budget_category = budget.uncategorized_budget_category %>
-
diff --git a/app/views/budget_categories/update.turbo_stream.erb b/app/views/budget_categories/update.turbo_stream.erb
index 31a70c51..34313156 100644
--- a/app/views/budget_categories/update.turbo_stream.erb
+++ b/app/views/budget_categories/update.turbo_stream.erb
@@ -1 +1,19 @@
<%= turbo_stream.replace dom_id(@budget, :allocation_progress), partial: "budget_categories/allocation_progress", locals: { budget: @budget } %>
+
+<%= turbo_stream.replace dom_id(@budget, :uncategorized_budget_category_form), partial: "budget_categories/uncategorized_budget_category_form", locals: { budget: @budget } %>
+
+<%= turbo_stream.replace dom_id(@budget, :confirm_button), partial: "budget_categories/confirm_button", locals: { budget: @budget } %>
+
+
+<% if @budget_category.subcategory? %>
+ <%# Update sibling subcategories when a subcategory changes %>
+ <% @budget_category.siblings.each do |sibling| %>
+ <%= turbo_stream.update dom_id(sibling, :form), partial: "budget_categories/budget_category_form", locals: { budget_category: sibling } %>
+ <% end %>
+
+<% else %>
+ <%# Update all subcategories when a parent category changes %>
+ <% @budget_category.subcategories.each do |subcategory| %>
+ <%= turbo_stream.update dom_id(subcategory, :form), partial: "budget_categories/budget_category_form", locals: { budget_category: subcategory } %>
+ <% end %>
+<% end %>
\ No newline at end of file