From a4cde09d48b2722f0e47b972e7b3f5287c32e1ef Mon Sep 17 00:00:00 2001 From: nmemmert <67961292+nmemmert@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:33:36 -0400 Subject: [PATCH] Add exclude from budget tracking option per account Accounts (e.g. mortgage) can be toggled to exclude from budget tracking: - Their transactions don't reduce envelope spending - Their balance is excluded from Available to Budget - Account card shows "excluded from budget" badge when enabled Co-Authored-By: Claude Sonnet 4.6 --- src/app/page.tsx | 15 +++++++++------ src/components/AccountManagement.tsx | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index e294547..87b7046 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -30,6 +30,7 @@ interface Account { accountNumber?: string; color: string; isActive: boolean; + excludeFromBudget?: boolean; defaultPaycheckAmount?: number; } @@ -144,13 +145,15 @@ export default function BudgetDashboard() { // ── Derived helpers ────────────────────────────────────────────────────────── - const calculateEnvelopeSpending = useCallback((envs: Envelope[], txns: Transaction[]): Envelope[] => - envs.map(envelope => { + const calculateEnvelopeSpending = useCallback((envs: Envelope[], txns: Transaction[], accs?: Account[]): Envelope[] => { + const excludedIds = new Set((accs ?? accounts).filter(a => a.excludeFromBudget).map(a => a.id)); + return envs.map(envelope => { const spent = txns - .filter(t => t.envelopeId === envelope.id && t.amount < 0) + .filter(t => t.envelopeId === envelope.id && t.amount < 0 && !excludedIds.has(t.accountId)) .reduce((sum, t) => sum + Math.abs(t.amount), 0); return { ...envelope, spent }; - }), []); + }); + }, [accounts]); const calculateAccountBalances = useCallback((accs: Account[], txns: Transaction[]): Account[] => { const map = new Map(); @@ -929,10 +932,10 @@ export default function BudgetDashboard() { return e.allocated + incomeAlloc > 0 && e.spent > e.allocated + incomeAlloc; }); - // Available to budget = all asset accounts minus total envelope allocations + // Available to budget = all asset accounts (excluding budget-excluded ones) minus total envelope allocations const LIABILITY_TYPES = ['credit_card', 'mortgage', 'loan']; const liquidBalance = accounts - .filter(a => !LIABILITY_TYPES.includes(a.type)) + .filter(a => !LIABILITY_TYPES.includes(a.type) && !a.excludeFromBudget) .reduce((s, a) => s + a.balance, 0); const totalAllocated = envelopes.reduce((s, e) => s + e.allocated, 0); const availableToBudget = liquidBalance - totalAllocated; diff --git a/src/components/AccountManagement.tsx b/src/components/AccountManagement.tsx index 19a9833..f1d2429 100644 --- a/src/components/AccountManagement.tsx +++ b/src/components/AccountManagement.tsx @@ -12,6 +12,7 @@ interface Account { accountNumber?: string; color: string; isActive: boolean; + excludeFromBudget?: boolean; } interface AccountManagementProps { @@ -187,6 +188,9 @@ export default function AccountManagement({ accounts, onAccountAdd, onAccountUpd

{account.isActive ? 'Active' : 'Inactive'}

+ {account.excludeFromBudget && ( + excluded from budget + )}
@@ -316,6 +320,20 @@ export default function AccountManagement({ accounts, onAccountAdd, onAccountUpd
+
+ setFormData(prev => ({ ...prev, excludeFromBudget: e.target.checked }))} + className="mr-2 mt-0.5" + /> + +
+