A studio's company card policy: a flight waits on its receipt, and a casino charge is blocked by merchant category.
registry/demos/checkpoint-spend-demo.tsx
import * as React from "react";
import { Checkpoint, type CheckpointRequest, type CheckpointRule } from "@/components/ui/checkpoint";
function Glyph({ children }: { children: React.ReactNode }) {
return (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.8"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden
>
{children}
</svg>
);
}
const card = (
<Glyph>
<rect x="3" y="5.5" width="18" height="13" rx="2.5" />
<path d="M3 10h18M7 15h4" />
</Glyph>
);
// Tinta, a design studio, and its company card policy. Merchants and people are made up.
const RULES: CheckpointRule[] = [
{
id: "merchant",
label: "Merchant",
detail: "Software, travel, meals, print",
value: "Allowed",
icon: (
<Glyph>
<path d="M4 9.5L5.5 4h13L20 9.5M4 9.5h16M4 9.5c0 1.5 1.2 2.5 2.7 2.5s2.6-1 2.6-2.5c0 1.5 1.2 2.5 2.7 2.5s2.7-1 2.7-2.5c0 1.5 1.1 2.5 2.6 2.5S20 11 20 9.5M5.5 12v8h13v-8" />
</Glyph>
),
},
{
id: "limit",
label: "Per charge",
detail: "Anything larger goes through a PO",
value: "≤ $2,000",
icon: (
<Glyph>
<path d="M4 18h16M6.5 18V11M12 18V6M17.5 18v-4" />
</Glyph>
),
},
{
id: "receipt",
label: "Receipt",
detail: "Over $75 needs one, or finance signs",
value: "> $75",
icon: (
<Glyph>
<path d="M6 3.5h12v17l-2-1.3-2 1.3-2-1.3-2 1.3-2-1.3-2 1.3z" />
<path d="M9 8h6M9 11.5h6M9 15h3.5" />
</Glyph>
),
},
{
id: "budget",
label: "Budget",
detail: "Design team, Q4",
value: "$18,400 left",
icon: (
<Glyph>
<path d="M12 3.5a8.5 8.5 0 1 0 8.5 8.5H12z" />
<path d="M15 3.8A8.5 8.5 0 0 1 20.2 9H15z" />
</Glyph>
),
},
];
const REQUESTS: CheckpointRequest[] = [
{ id: "figma", label: "FIGMA* ANNUAL", meta: "$45.00 · Lena Ortiz", icon: card },
{
id: "flight",
label: "NORDAIR 0742",
meta: "$1,386.40 · Sam Okafor, client visit in Oslo",
verdicts: { receipt: "hold" },
icon: card,
},
{
id: "casino",
label: "LUCKY STAR CASINO",
meta: "$600.00 · Sam Okafor",
verdicts: { merchant: "block" },
reason: "Gambling isn't covered",
icon: card,
},
];
export function CheckpointSpendDemo() {
return (
<div className="w-full max-w-xl rounded-[26px] border border-zinc-950/[0.08] bg-white p-1.5 shadow-[0_1px_2px_rgba(0,0,0,0.04)] dark:border-white/10 dark:bg-zinc-950">
<div className="rounded-[20px] bg-zinc-50 bg-[radial-gradient(120%_70%_at_50%_0%,rgba(10,159,92,0.08),transparent_70%)] p-4 sm:p-5 dark:bg-white/[0.03] dark:bg-[radial-gradient(120%_70%_at_50%_0%,rgba(50,213,131,0.08),transparent_70%)]">
<div className="mb-4 flex items-baseline justify-between gap-4 px-0.5">
<p className="text-[13px] font-semibold tracking-tight text-zinc-950 dark:text-zinc-100">
Card policy <span className="font-normal text-zinc-500 dark:text-zinc-400">· Tinta Studio</span>
</p>
<p className="text-[12px] text-zinc-500 tabular-nums dark:text-zinc-400">3 cards live</p>
</div>
<Checkpoint
rules={RULES}
requests={REQUESTS}
approver="Finance"
className="[--checkpoint-accent:#0a9f5c] dark:[--checkpoint-accent:#32d583]"
/>
</div>
</div>
);
}
Live preview, examples and props: https://keyframeui.com/components/checkpoint#checkpoint-spend-demo
