From 408a473dcd4d133dd91f16ecd61887abf6d99950 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Tue, 1 Sep 2026 21:07:04 +0200 Subject: [PATCH] feat(ui): add summary view with post and month grouping --- src/ui/routes/SummaryRoute.tsx | 114 ++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/src/ui/routes/SummaryRoute.tsx b/src/ui/routes/SummaryRoute.tsx index 4204051..d4a9991 100644 --- a/src/ui/routes/SummaryRoute.tsx +++ b/src/ui/routes/SummaryRoute.tsx @@ -1,3 +1,115 @@ +import { useState } from "react"; +import { Link } from "react-router"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Button } from "@/components/ui/button"; +import { useDataset } from "../hooks/useDataset.ts"; +import { datasetMonthSpan, summaryView } from "../../domain/views.ts"; +import { formatAmount, formatMoney } from "../format.ts"; + export function SummaryRoute() { - return

Summary

; + const dataset = useDataset(); + const span = datasetMonthSpan(dataset); + const [from, setFrom] = useState(span.from); + const [to, setTo] = useState(span.to); + const [groupBy, setGroupBy] = useState<"post" | "month">("post"); + + const view = summaryView(dataset, from, to); + const base = dataset.settings.baseCurrency; + const difference = Number((view.totalIncome - view.totalCharges).toFixed(2)); + + return ( +
+

Summary

+ +
+
+ + setFrom(e.target.value)} /> +
+
+ + setTo(e.target.value)} /> +
+ +
+ {(["post", "month"] as const).map((option) => ( + + ))} +
+
+ +
+
+
Income
+
{formatMoney(view.totalIncome, base)}
+
+
+
Spent
+
{formatMoney(view.totalCharges, base)}
+
+
+
Difference
+
+ {formatMoney(difference, base)} +
+
+
+ + + + + + + + + + + {groupBy === "post" + ? view.byPost.map((entry) => ( + + + + + + )) + : view.byMonth.map((entry) => ( + + + + + + ))} + +
{groupBy === "post" ? "Post" : "Month"}SpentShare
{entry.post.name}{formatAmount(entry.charges)} + {view.totalCharges === 0 + ? "—" + : `${((entry.charges / view.totalCharges) * 100).toFixed(1)}%`} +
+ + {entry.monthId} + + {formatAmount(entry.charges)} + {view.totalCharges === 0 + ? "—" + : `${((entry.charges / view.totalCharges) * 100).toFixed(1)}%`} +
+
+ ); }