Files
Epicnabbo-Catalogus-Updated…/src/components/admin/stats-card.tsx
T
openhands 7a41775c7e fix: disable route prefetching app-wide to avoid spurious requests
Wrap next/link in a shared Link component that ships prefetch=false by
default, so no route is ever prefetched (viewport or hover) anymore, and
drop the DNS prefetch hint. Removes hidden background requests that were
the source of intermittent issues.
2026-08-29 19:27:13 +02:00

81 lines
1.9 KiB
TypeScript

import { Minus, TrendingDown, TrendingUp } from "lucide-react";
import Link from "@/components/link";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
interface StatsCardProps {
title: string;
value: string | number;
description?: string;
icon?: React.ReactNode;
href?: string;
/** Percentage change vs previous period. Positive = up, negative = down, undefined = no trend */
trend?: number;
}
export function StatsCard({
title,
value,
description,
icon,
href,
trend,
}: StatsCardProps) {
const content = (
<Card
className={
href
? "transition-all duration-200 hover:border-primary/50 hover:shadow-lg hover:shadow-primary/5 hover:-translate-y-0.5 cursor-pointer"
: ""
}
>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">{title}</CardTitle>
{icon && <div className="text-muted-foreground">{icon}</div>}
</CardHeader>
<CardContent>
<div className="flex items-baseline gap-2">
<div className="text-2xl font-bold">{value}</div>
{trend !== undefined && <TrendBadge value={trend} />}
</div>
{description && (
<p className="text-xs text-muted-foreground">{description}</p>
)}
</CardContent>
</Card>
);
if (href) {
return <Link href={href}>{content}</Link>;
}
return content;
}
function TrendBadge({ value }: { value: number }) {
if (value === 0) {
return (
<span className="inline-flex items-center gap-0.5 text-xs text-muted-foreground">
<Minus className="h-3 w-3" />
0%
</span>
);
}
const isUp = value > 0;
return (
<span
className={`inline-flex items-center gap-0.5 text-xs font-medium ${
isUp ? "text-[var(--admin-success)]" : "text-[var(--admin-error)]"
}`}
>
{isUp ? (
<TrendingUp className="h-3 w-3" />
) : (
<TrendingDown className="h-3 w-3" />
)}
{isUp ? "+" : ""}
{value}%
</span>
);
}