Invoice Activity Chart
Recharts-powered area and stacked bar chart for invoice activity.
import { InvoiceChart } from "@/registry/new-york/items/manpowerhub-invoice-chart/components/invoice-chart";
export function ManpowerhubInvoiceChartBasic() { return ( <div className="p-4"> <InvoiceChart /> </div> );}Installation
Section titled “Installation”This installation provides support for all official Shadcn icon libraries. The component is otherwise identical to the non-experimental installation.
Icon support is experimental and may not be fully stable since it uses internal Shadcn APIs.
This component relies on other items which must be installed first.
Install the following dependencies.
Copy and paste the following code into your project.
"use client";
import * as React from "react";import { Area, AreaChart, Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis,} from "recharts";import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { cn } from "@/lib/utils";
const billedData = [ { day: "Apr 21", amount: 3200 }, { day: "Apr 22", amount: 1800 }, { day: "Apr 23", amount: 4100 }, { day: "Apr 24", amount: 2900 }, { day: "Apr 25", amount: 5600 }, { day: "Apr 26", amount: 3400 }, { day: "Apr 27", amount: 2100 }, { day: "Apr 28", amount: 6200 }, { day: "Apr 29", amount: 4800 }, { day: "Apr 30", amount: 3700 }, { day: "May 1", amount: 5100 }, { day: "May 2", amount: 2600 }, { day: "May 3", amount: 4400 }, { day: "May 4", amount: 3900 }, { day: "May 5", amount: 7200 }, { day: "May 6", amount: 5500 }, { day: "May 7", amount: 4200 }, { day: "May 8", amount: 3100 }, { day: "May 9", amount: 6800 }, { day: "May 10", amount: 4600 }, { day: "May 11", amount: 5900 }, { day: "May 12", amount: 3800 }, { day: "May 13", amount: 7400 }, { day: "May 14", amount: 5200 }, { day: "May 15", amount: 4100 }, { day: "May 16", amount: 6300 }, { day: "May 17", amount: 5700 }, { day: "May 18", amount: 3300 }, { day: "May 19", amount: 8100 }, { day: "May 20", amount: 6900 },];
const statusData = [ { week: "Apr 21–27", draft: 3, pending: 2, approved: 1, sent: 2, expired: 0 }, { week: "Apr 28–May 4", draft: 2, pending: 3, approved: 2, sent: 1, expired: 1, }, { week: "May 5–11", draft: 4, pending: 1, approved: 3, sent: 3, expired: 0 }, { week: "May 12–18", draft: 1, pending: 4, approved: 2, sent: 2, expired: 1 },];
type ChartTab = "billed" | "status";
interface CustomTooltipProps { active?: boolean; payload?: { value: number }[]; label?: string;}
function BilledTooltip({ active, payload, label }: CustomTooltipProps) { if (!active || !payload?.length) return null; return ( <div className="rounded-[var(--r-md)] border border-[var(--color-border)] bg-[var(--surface-3)] px-3 py-2 text-[12px] shadow-[var(--shadow-lg)]"> <p className="mb-0.5 text-[var(--text-3)]">{label}</p> <p className="font-semibold text-[var(--text-1)]"> AED {payload[0].value.toLocaleString()} </p> </div> );}
export interface InvoiceChartProps extends React.ComponentProps<"div"> {}
function InvoiceChart({ className, ...props }: InvoiceChartProps) { const [tab, setTab] = React.useState<ChartTab>("billed");
return ( <div className={cn("", className)} {...props}> <Card> <CardHeader className="flex flex-row items-center justify-between border-b pb-3"> <div> <p className="text-[13px] font-semibold text-foreground"> Invoice activity </p> <p className="text-[11.5px] text-[var(--text-3)]">Last 30 days</p> </div> <div className="flex rounded-[var(--r-md)] border border-[var(--color-border)] p-0.5"> {(["billed", "status"] as ChartTab[]).map((t) => ( <button key={t} onClick={() => setTab(t)} className={cn( "rounded-[var(--r-sm)] px-3 py-1 text-[11.5px] font-medium capitalize transition-colors", tab === t ? "bg-[var(--surface-4)] text-foreground" : "text-[var(--text-3)] hover:text-[var(--text-2)]", )} > {t === "billed" ? "Billed" : "By status"} </button> ))} </div> </CardHeader> <CardContent className="pt-4"> {tab === "billed" ? ( <ResponsiveContainer width="100%" height={200}> <AreaChart data={billedData} margin={{ top: 4, right: 4, left: -16, bottom: 0 }} > <defs> <linearGradient id="invoice-chart-billed-grad" x1="0" y1="0" x2="0" y2="1" > <stop offset="0%" stopColor="var(--brand)" stopOpacity={0.25} /> <stop offset="100%" stopColor="var(--brand)" stopOpacity={0} /> </linearGradient> </defs> <CartesianGrid vertical={false} stroke="var(--color-border-subtle)" strokeDasharray="3 3" /> <XAxis dataKey="day" tick={{ fontSize: 10, fill: "var(--text-3)" }} tickLine={false} axisLine={false} interval={4} /> <Tooltip content={<BilledTooltip />} /> <Area type="monotone" dataKey="amount" stroke="var(--brand)" strokeWidth={2} fill="url(#invoice-chart-billed-grad)" dot={false} /> </AreaChart> </ResponsiveContainer> ) : ( <ResponsiveContainer width="100%" height={200}> <BarChart data={statusData} margin={{ top: 4, right: 4, left: -16, bottom: 0 }} barSize={28} > <CartesianGrid vertical={false} stroke="var(--color-border-subtle)" strokeDasharray="3 3" /> <XAxis dataKey="week" tick={{ fontSize: 10, fill: "var(--text-3)" }} tickLine={false} axisLine={false} /> <Tooltip contentStyle={{ background: "var(--surface-3)", border: "1px solid var(--color-border)", borderRadius: "var(--r-md)", fontSize: 12, color: "var(--text-1)", }} cursor={{ fill: "var(--surface-2)" }} /> <Bar dataKey="draft" stackId="a" fill="var(--surface-5)" radius={[0, 0, 0, 0]} /> <Bar dataKey="pending" stackId="a" fill="var(--amber)" radius={[0, 0, 0, 0]} /> <Bar dataKey="approved" stackId="a" fill="var(--brand)" radius={[0, 0, 0, 0]} /> <Bar dataKey="sent" stackId="a" fill="var(--blue)" radius={[0, 0, 0, 0]} /> <Bar dataKey="expired" stackId="a" fill="var(--red)" radius={[2, 2, 0, 0]} /> </BarChart> </ResponsiveContainer> )} {tab === "status" && ( <div className="mt-3 flex flex-wrap gap-x-4 gap-y-1.5"> {[ { key: "draft", label: "Draft", color: "var(--surface-5)" }, { key: "pending", label: "Pending", color: "var(--amber)" }, { key: "approved", label: "Approved", color: "var(--brand)" }, { key: "sent", label: "Sent", color: "var(--blue)" }, { key: "expired", label: "Expired", color: "var(--red)" }, ].map(({ key, label, color }) => ( <span key={key} className="flex items-center gap-1.5 text-[11.5px] text-[var(--text-3)]" > <span className="size-2 rounded-sm" style={{ background: color }} /> {label} </span> ))} </div> )} </CardContent> </Card> </div> );}
export { InvoiceChart };Update the import paths to match your project setup.
Install the ManpowerHub theme first, then add this component:
npx shadcn@latest add https://woxcn-registry.woxware.io/r/manpowerhub-invoice-chart.jsonDisplays a togglable chart: Billed tab shows a 30-day area chart of total billed amount; By status tab shows a stacked bar chart grouped by invoice status per week.