61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import {
|
|
BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
|
|
} from 'recharts'
|
|
import { formatCents, formatCentsAbbrev } from '@/lib/utils/currency'
|
|
|
|
interface DataPoint {
|
|
label: string
|
|
creditsCents: number
|
|
debitsCents: number
|
|
}
|
|
|
|
function ChartTooltip({ active, payload, label }: {
|
|
active?: boolean
|
|
payload?: Array<{ name: string; value: number; color: string }>
|
|
label?: string
|
|
}) {
|
|
if (!active || !payload?.length) return null
|
|
return (
|
|
<div className="rounded-md border bg-card p-3 shadow-md text-sm">
|
|
<p className="font-medium mb-1">{label}</p>
|
|
{payload.map((p) => (
|
|
<p key={p.name} style={{ color: p.color }}>
|
|
{p.name}: {formatCents(p.value)}
|
|
</p>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function CashFlowChart({ data }: { data: DataPoint[] }) {
|
|
if (data.length === 0) {
|
|
return (
|
|
<div className="flex h-[300px] items-center justify-center text-sm text-muted-foreground">
|
|
No bank transaction data yet.
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<ResponsiveContainer width="100%" height={300}>
|
|
<BarChart data={data} margin={{ top: 4, right: 16, left: 16, bottom: 0 }} barGap={4}>
|
|
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" vertical={false} />
|
|
<XAxis dataKey="label" tick={{ fontSize: 12 }} tickLine={false} axisLine={false} />
|
|
<YAxis
|
|
tickFormatter={formatCentsAbbrev}
|
|
tick={{ fontSize: 12 }}
|
|
tickLine={false}
|
|
axisLine={false}
|
|
width={64}
|
|
/>
|
|
<Tooltip content={<ChartTooltip />} />
|
|
<Legend wrapperStyle={{ fontSize: 12 }} />
|
|
<Bar dataKey="creditsCents" name="Income" fill="#22c55e" radius={[4, 4, 0, 0]} maxBarSize={40} />
|
|
<Bar dataKey="debitsCents" name="Spending" fill="#ef4444" radius={[4, 4, 0, 0]} maxBarSize={40} />
|
|
</BarChart>
|
|
</ResponsiveContainer>
|
|
)
|
|
}
|