This commit is contained in:
2026-08-22 23:10:21 +00:00
parent c10c872732
commit 7100995bb1
-79
View File
@@ -1,79 +0,0 @@
import { createFileRoute, Link } from "@tanstack/react-router";
import { useQuery } from "@tanstack/react-query";
import { supabase } from "@/integrations/supabase/client";
import { Button } from "@/components/ui/button";
import { ChevronRight, FileText } from "lucide-react";
import { money } from "@/lib/reports";
export const Route = createFileRoute("/_authenticated/ledger")({
head: () => ({ meta: [{ title: "Tuition — School Portal" }] }),
component: LedgerListPage,
});
function LedgerListPage() {
const { data: students } = useQuery({
queryKey: ["students-with-balance"],
queryFn: async () => {
const { data: studs } = await supabase
.from("students")
.select("id, first_name, last_name, daily_tuition_cents");
const { data: entries } = await supabase
.from("ledger_entries")
.select("student_id, amount_cents, kind");
const balances: Record<string, number> = {};
(entries ?? []).forEach((e) => {
balances[e.student_id] =
(balances[e.student_id] ?? 0) + (e.kind === "charge" ? e.amount_cents : -e.amount_cents);
});
return (studs ?? []).map((s) => ({ ...s, balance: balances[s.id] ?? 0 }));
},
});
return (
<div className="p-8 max-w-4xl">
<h1 className="text-2xl font-semibold mb-1">Tuition ledger</h1>
<p className="text-muted-foreground text-sm mb-6">
Click a student to view and manage their ledger, or build an invoice. Students with a daily
rate are charged automatically when marked present or late.
</p>
<div className="bg-card border rounded-lg divide-y">
{(students ?? []).map((s) => (
<div key={s.id} className="flex items-center gap-3 p-3 hover:bg-muted/50">
<Link
to="/students/$id"
params={{ id: s.id }}
className="flex-1 min-w-0 flex items-center gap-2"
>
<span className="font-medium truncate">
{s.last_name}, {s.first_name}
</span>
{s.daily_tuition_cents ? (
<span className="text-xs text-muted-foreground shrink-0">
{money(s.daily_tuition_cents)}/day
</span>
) : (
<span className="text-xs text-muted-foreground shrink-0">no rate</span>
)}
</Link>
<span
className={`text-sm font-medium shrink-0 ${s.balance > 0 ? "text-destructive" : "text-green-700"}`}
>
{money(s.balance)}
</span>
<Link to="/invoice/$id" params={{ id: s.id }} className="shrink-0">
<Button size="sm" variant="outline">
<FileText className="h-4 w-4 mr-1" /> Invoice
</Button>
</Link>
<Link to="/students/$id" params={{ id: s.id }} className="shrink-0">
<ChevronRight className="h-4 w-4 text-muted-foreground" />
</Link>
</div>
))}
{students?.length === 0 && (
<div className="p-6 text-center text-sm text-muted-foreground">No students.</div>
)}
</div>
</div>
);
}