Files
cyclone/src/components/ActivityFeed.tsx
T

84 lines
2.4 KiB
TypeScript

import {
Banknote,
CheckCircle2,
FileText,
Pill,
UserPlus,
XCircle,
type LucideIcon,
} from "lucide-react";
import { fmt } from "@/lib/format";
import type { Activity } from "@/types";
import { cn } from "@/lib/utils";
const kindConfig: Record<
Activity["kind"],
{ icon: LucideIcon; tone: string }
> = {
claim_submitted: { icon: FileText, tone: "text-[hsl(var(--accent))]" },
claim_accepted: { icon: CheckCircle2, tone: "text-[hsl(var(--success))]" },
claim_paid: { icon: Banknote, tone: "text-[hsl(var(--success))]" },
claim_denied: { icon: XCircle, tone: "text-destructive" },
remit_received: { icon: Pill, tone: "text-[hsl(var(--warning))]" },
provider_added: { icon: UserPlus, tone: "text-foreground" },
};
export function ActivityFeed({
items,
emptyMessage = "No activity yet.",
}: {
items: Activity[];
emptyMessage?: string;
}) {
if (items.length === 0) {
return (
<div className="text-sm text-muted-foreground px-2 py-6 text-center">
{emptyMessage}
</div>
);
}
return (
<ul className="divide-y divide-border/40">
{items.map((a) => {
const cfg = kindConfig[a.kind];
const Icon = cfg.icon;
return (
<li
key={a.id}
className="flex items-start gap-3 py-3 first:pt-0 last:pb-0"
>
<div
className={cn(
"mt-0.5 h-7 w-7 shrink-0 rounded-md bg-muted/50 flex items-center justify-center",
cfg.tone
)}
>
<Icon className="h-3.5 w-3.5" strokeWidth={1.75} />
</div>
<div className="flex-1 min-w-0">
<div className="text-sm text-foreground/95 leading-snug">
{a.message}
</div>
<div className="text-[11px] text-muted-foreground mt-0.5 flex items-center gap-2">
<span>{fmt.relative(a.timestamp)}</span>
{a.npi ? (
<>
<span className="opacity-40">·</span>
<span className="num">{a.npi}</span>
</>
) : null}
{a.amount ? (
<>
<span className="opacity-40">·</span>
<span className="num">{fmt.usd(a.amount)}</span>
</>
) : null}
</div>
</div>
</li>
);
})}
</ul>
);
}