"use client";
import {
Bar,
BarChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import { getEffectiveInvoiceStatus } from "~/lib/invoice-status";
import type { StoredInvoiceStatus } from "~/types/invoice";
import { useAnimationPreferences } from "~/components/providers/animation-preferences-provider";
interface Invoice {
id: string;
totalAmount: number;
issueDate: Date | string;
status: string;
dueDate: Date | string;
}
interface MonthlyMetricsChartProps {
invoices: Invoice[];
}
function MonthlyMetricsTooltip({
active,
payload,
label,
}: {
active?: boolean;
payload?: Array<{
payload: {
paidInvoices: number;
pendingInvoices: number;
overdueInvoices: number;
draftInvoices: number;
totalInvoices: number;
};
}>;
label?: string;
}) {
if (active && payload?.length) {
const data = payload[0]!.payload;
return (
{label}
Paid: {data.paidInvoices}
Pending: {data.pendingInvoices}
Overdue: {data.overdueInvoices}
Draft: {data.draftInvoices}
Total: {data.totalInvoices}
);
}
return null;
}
export function MonthlyMetricsChart({ invoices }: MonthlyMetricsChartProps) {
// Process invoice data to create monthly metrics
const monthlyData = invoices.reduce(
(acc, invoice) => {
const date = new Date(invoice.issueDate);
const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}`;
const effectiveStatus = getEffectiveInvoiceStatus(
invoice.status as StoredInvoiceStatus,
invoice.dueDate,
);
acc[monthKey] ??= {
month: monthKey,
totalInvoices: 0,
paidInvoices: 0,
pendingInvoices: 0,
overdueInvoices: 0,
draftInvoices: 0,
};
acc[monthKey].totalInvoices += 1;
switch (effectiveStatus) {
case "paid":
acc[monthKey].paidInvoices += 1;
break;
case "sent":
acc[monthKey].pendingInvoices += 1;
break;
case "overdue":
acc[monthKey].overdueInvoices += 1;
break;
case "draft":
acc[monthKey].draftInvoices += 1;
break;
}
return acc;
},
{} as Record<
string,
{
month: string;
totalInvoices: number;
paidInvoices: number;
pendingInvoices: number;
overdueInvoices: number;
draftInvoices: number;
}
>,
);
// Convert to array and sort by month
const chartData = Object.values(monthlyData)
.sort((a, b) => a.month.localeCompare(b.month))
.slice(-6) // Show last 6 months
.map((item) => ({
...item,
monthLabel: new Date(item.month + "-01").toLocaleDateString("en-US", {
month: "short",
year: "2-digit",
}),
}));
// Animation / motion preferences
const { prefersReducedMotion, animationSpeedMultiplier } =
useAnimationPreferences();
const barAnimationDuration = Math.round(
500 / (animationSpeedMultiplier || 1),
);
if (chartData.length === 0) {
return (
No metrics data available
Monthly metrics will appear here once you create invoices
);
}
return (
);
}