"use client"; import Link from "next/link"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { useOrgScorecard } from "@/hooks/use-observability"; import { Trophy, CheckCircle2, Gauge, Clock, Coins, ArrowRight, } from "lucide-react"; function pctOrNa(rate: number | null): string { return rate === null ? "n/a" : (rate * 100).toFixed(0) + "%"; } function numOrNa(value: number | null, digits = 2): string { return value === null ? "n/a" : value.toFixed(digits); } interface MetricRowProps { icon: React.ReactNode; label: string; value: string; } function MetricRow({ icon, label, value }: MetricRowProps) { return (
{icon} {label}
{value}
); } /** * Dashboard overview of the org-wide performance rollup (last 30 days). Headline * figures from useOrgScorecard with a deep-link into the full Scorecards tab. */ export function ScorecardOverviewPanel() { const { data, isLoading, isError } = useOrgScorecard(); return (
Performance Scorecards
{isError ? (
Failed to load performance metrics.
) : isLoading || !data ? (
{Array.from({ length: 5 }).map((_, i) => ( ))}
) : (
} label="Tasks completed (30d)" value={String(data.tasks_completed)} /> } label="First-pass yield" value={pctOrNa(data.first_pass_yield)} /> } label="Throughput / hr" value={numOrNa(data.effort_throughput_per_hour)} /> } label="Active effort" value={data.active_runtime_hours.toFixed(1) + "h"} /> } label="Cost" value={"$" + data.cost_usd.toFixed(2)} />
)}
); }