import { HorizontalBarChart } from "@/components/charts/HorizontalBarChart"; import { useMoney } from "@/hooks/useMoney"; import { cn } from "@/lib/utils"; import type { Category } from "@/lib/categories"; export interface CategoryDatum { name: Category; value: number; pct: number; } const getName = (d: CategoryDatum) => d.name; const getValue = (d: CategoryDatum) => d.value; /** * Spending by category as a sorted horizontal bar chart. * * Deliberately NOT the donut this app used to carry (which was never rendered * anywhere anyway). Two reasons: * - Part-to-whole across ~20 long-named categories is a bar chart's job; a pie * makes the reader compare angles and truncates its own labels. * - The donut assigned colors by `index % 6` AFTER sorting by value, so a * category's color changed whenever the ranking changed and repeated every * 7th slice. Bar length already encodes magnitude, so one hue is correct and * colour never lies about identity. */ export function SpendByCategoryChart({ data, onSelect, selected, }: { data: CategoryDatum[]; onSelect?: (category: Category) => void; selected?: Category | null; }) { const { money, compact } = useMoney(); if (data.length === 0) { return
No spending in this period.
; } return ({d.name}
{money(d.value)} ยท {d.pct.toFixed(1)}% of spend
{onSelect &&Click to see transactions
} > )} /> ); } /** The same numbers as an accessible table, the chart's non-visual equivalent. */ export function SpendByCategoryTable({ data }: { data: CategoryDatum[] }) { const { money } = useMoney(); return (| Category | Spent | Share |
|---|---|---|
| {d.name} | {money(d.value)} | {d.pct.toFixed(1)}% |