feat: add month breakdown and session backups
Continuous Integration / lint-and-test (push) Successful in 17s
Continuous Integration / docker-build-and-push (push) Successful in 35s

Allow recurring costs and confirmations to remain unassigned when created from a purchase without a post. Add browser backup retention and restore controls, with coverage and documentation updates.
This commit is contained in:
Lucas Winther committed 2026-10-01 04:01:49 +02:00
1 parent 019517e6e9
commit 7cccd7a41a
32 files changed
+640 -41

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
import type { MonthViewModel } from "../domain/views.ts";
export type MonthPieMode = "spending" | "allocation";
export interface MonthPieSlice {
id: string;
label: string;
amount: number;
}
/** Chart data comes from the same folded figures as the month table. */
export function monthPieData(view: MonthViewModel, mode: MonthPieMode) {
const items: MonthPieSlice[] = view.rows.map(({ post, figures }) => ({
id: post.id,
label: post.name,
amount: mode === "spending" ? figures.charges : figures.allocation,
}));
if (mode === "spending" && view.looseCharges !== 0) {
items.push({ id: "unassigned", label: "Unassigned", amount: view.looseCharges });
}
const byAmount = (a: MonthPieSlice, b: MonthPieSlice) => b.amount - a.amount || a.label.localeCompare(b.label);
const positive = items.filter((item) => item.amount > 0).sort(byAmount);
const adjustments = items.filter((item) => item.amount < 0).sort((a, b) => a.amount - b.amount);
return {
positive,
adjustments,
positiveTotal: positive.reduce((sum, item) => sum + item.amount, 0),
netTotal: mode === "spending" ? view.totalCharges : view.totalAllocation,
};
}