feat: show committed goals in fixed costs panel
Committed goals now appear in the Fixed Costs panel on the dashboard with a "committed goal" label, and the total line uses TotalCommittedCents (fixed costs + goal contributions) instead of total monthly expenses. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2324f62721
commit
bfd5f62a7a
@ -324,7 +324,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
// disposable income = income - fixed recurring
|
// disposable income = income - fixed recurring
|
||||||
disposableIncome := thisMonthIncome - totalFixedCents
|
disposableIncome := thisMonthIncome - totalFixedCents
|
||||||
|
|
||||||
// deduct committed goal contributions from disposable
|
// deduct committed goal contributions from disposable and add to fixed costs list
|
||||||
committedGoalsCents := int64(0)
|
committedGoalsCents := int64(0)
|
||||||
if goals, err := h.store.getGoals(ctx, a.UserID); err == nil {
|
if goals, err := h.store.getGoals(ctx, a.UserID); err == nil {
|
||||||
now2 := time.Now()
|
now2 := time.Now()
|
||||||
@ -340,10 +340,17 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
if ml < 1 {
|
if ml < 1 {
|
||||||
ml = 1
|
ml = 1
|
||||||
}
|
}
|
||||||
committedGoalsCents += remaining / ml
|
monthly := remaining / ml
|
||||||
|
committedGoalsCents += monthly
|
||||||
|
recurringExpenses = append(recurringExpenses, RecurringExpense{
|
||||||
|
Category: g.Name,
|
||||||
|
MonthlyCents: monthly,
|
||||||
|
IsGoal: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
disposableIncome -= committedGoalsCents
|
disposableIncome -= committedGoalsCents
|
||||||
|
totalCommittedCents := totalFixedCents + committedGoalsCents
|
||||||
|
|
||||||
// variable spend so far this month (non-fixed categories, expenses only)
|
// variable spend so far this month (non-fixed categories, expenses only)
|
||||||
variableSpent := int64(0)
|
variableSpent := int64(0)
|
||||||
@ -450,6 +457,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
RecurringExpenses: recurringExpenses,
|
RecurringExpenses: recurringExpenses,
|
||||||
BankShouldBe: bankShouldBe,
|
BankShouldBe: bankShouldBe,
|
||||||
SafetyBufferCents: safetyBuffer,
|
SafetyBufferCents: safetyBuffer,
|
||||||
|
TotalCommittedCents: totalCommittedCents,
|
||||||
SavingsRatePct: savingsRatePct,
|
SavingsRatePct: savingsRatePct,
|
||||||
LastMonthSavingsRatePct: lastMonthSavingsRatePct,
|
LastMonthSavingsRatePct: lastMonthSavingsRatePct,
|
||||||
PortfolioValueCents: portfolioValueCents,
|
PortfolioValueCents: portfolioValueCents,
|
||||||
|
|||||||
@ -113,8 +113,9 @@ var FixedCategories = map[string]bool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RecurringExpense struct {
|
type RecurringExpense struct {
|
||||||
Category string
|
Category string
|
||||||
MonthlyCents int64
|
MonthlyCents int64
|
||||||
|
IsGoal bool // true when this entry comes from a committed goal
|
||||||
}
|
}
|
||||||
|
|
||||||
type DashboardData struct {
|
type DashboardData struct {
|
||||||
@ -140,8 +141,9 @@ type DashboardData struct {
|
|||||||
MonthSpentPct int // % of disposable already spent
|
MonthSpentPct int // % of disposable already spent
|
||||||
|
|
||||||
RecurringExpenses []RecurringExpense
|
RecurringExpenses []RecurringExpense
|
||||||
BankShouldBe int64 // sum of upcoming fixed costs + safety buffer
|
BankShouldBe int64
|
||||||
SafetyBufferCents int64
|
SafetyBufferCents int64
|
||||||
|
TotalCommittedCents int64 // sum of all fixed costs + committed goals
|
||||||
|
|
||||||
SavingsRatePct int // savings / income * 100 this month
|
SavingsRatePct int // savings / income * 100 this month
|
||||||
LastMonthSavingsRatePct int
|
LastMonthSavingsRatePct int
|
||||||
|
|||||||
@ -236,10 +236,14 @@
|
|||||||
{{$color := index $d.CategoryColors .Category}}
|
{{$color := index $d.CategoryColors .Category}}
|
||||||
<div style="display:flex; align-items:center; justify-content:space-between; padding:10px 0; border-bottom:1px solid var(--border);">
|
<div style="display:flex; align-items:center; justify-content:space-between; padding:10px 0; border-bottom:1px solid var(--border);">
|
||||||
<div style="display:flex; align-items:center; gap:10px;">
|
<div style="display:flex; align-items:center; gap:10px;">
|
||||||
{{if $color}}<span style="width:9px; height:9px; border-radius:50%; background:{{$color}}; flex-shrink:0; display:inline-block;"></span>{{end}}
|
{{if .IsGoal}}
|
||||||
|
<span style="width:9px; height:9px; border-radius:50%; background:var(--accent); flex-shrink:0; display:inline-block;"></span>
|
||||||
|
{{else if $color}}
|
||||||
|
<span style="width:9px; height:9px; border-radius:50%; background:{{$color}}; flex-shrink:0; display:inline-block;"></span>
|
||||||
|
{{end}}
|
||||||
<div>
|
<div>
|
||||||
<div style="font-size:13px; font-weight:500; color:var(--text);">{{.Category}}</div>
|
<div style="font-size:13px; font-weight:500; color:var(--text);">{{.Category}}</div>
|
||||||
<div style="font-size:11px; color:var(--text3);">committed monthly cost</div>
|
<div style="font-size:11px; color:var(--text3);">{{if .IsGoal}}committed goal{{else}}recurring expense{{end}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align:right;">
|
<div style="text-align:right;">
|
||||||
@ -249,8 +253,9 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:12px 0 0 0;">
|
<div style="display:flex; justify-content:space-between; align-items:center; padding:12px 0 0 0;">
|
||||||
<span style="font-size:13px; font-weight:500; color:var(--text);">Total fixed</span>
|
<span style="font-size:13px; font-weight:500; color:var(--text);">Total committed</span>
|
||||||
<span style="font-size:15px; font-weight:600; color:var(--red);">− €{{cents $d.BankShouldBe}}</span>
|
<span class="animate-counter" style="font-size:15px; font-weight:600; color:var(--red);"
|
||||||
|
data-target="{{$d.TotalCommittedCents}}" data-prefix="€">€0</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user