2025-12-14 16:48:07 +00:00

78 lines
2.4 KiB
TypeScript

/**
* Stats dashboard showing job counts by status.
*/
import React from "react";
import {
CheckCircle2,
Clock,
Loader2,
Search,
Sparkles,
XCircle,
} from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import type { JobStatus } from "../../shared/types";
interface StatsProps {
stats: Record<JobStatus, number>;
}
const statConfig: Array<{
key: JobStatus;
label: string;
Icon: React.ComponentType<{ className?: string }>;
}> = [
{ key: "discovered", label: "Discovered", Icon: Search },
{ key: "processing", label: "Processing", Icon: Loader2 },
{ key: "ready", label: "Ready", Icon: Sparkles },
{ key: "applied", label: "Applied", Icon: CheckCircle2 },
{ key: "rejected", label: "Rejected", Icon: XCircle },
{ key: "expired", label: "Expired", Icon: Clock },
];
export const Stats: React.FC<StatsProps> = ({ stats }) => {
const total = Object.values(stats).reduce((a, b) => a + b, 0);
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0">
<CardTitle>Overview</CardTitle>
<div className="text-sm text-muted-foreground">{total} total jobs</div>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6">
{statConfig.map(({ key, label, Icon }) => (
<Card key={key} className="bg-muted/20">
<CardContent className="p-4">
<div className="flex items-center gap-3">
<div className="flex h-9 w-9 items-center justify-center rounded-md bg-background/40 text-muted-foreground">
<Icon
className={
key === "processing"
? "h-4 w-4 animate-spin"
: "h-4 w-4"
}
/>
</div>
<div className="min-w-0">
<div className="text-2xl font-semibold tabular-nums leading-none">
{stats[key] || 0}
</div>
<div className="mt-1 truncate text-xs text-muted-foreground">
{label}
</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</CardContent>
</Card>
);
};