Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 1x 1x 6x 6x 6x 1x 24x 96x 96x | import { Users, Briefcase, Inbox, Megaphone, RefreshCw } from "lucide-react";
import { useLeadershipMetrics } from "../hooks/queries/useLeadershipMetrics";
import { StatCard } from "../components/analytics/StatCard";
import { Button } from "../components/ui/button";
const WINDOWS = [
{ key: "d1" as const, label: "Last 24 hours" },
{ key: "d2" as const, label: "Last 2 days" },
{ key: "d7" as const, label: "Last 7 days" },
{ key: "d30" as const, label: "Last 30 days" },
];
type SectionConfig = {
slug: "leads" | "landingLeads" | "pros" | "homeowners";
title: string;
icon: typeof Users;
color: string;
bgColor: string;
};
const SECTIONS: SectionConfig[] = [
{
slug: "leads",
title: "New leads",
icon: Inbox,
color: "text-blue-600",
bgColor: "bg-blue-50",
},
{
slug: "landingLeads",
title: "New landing-page leads",
icon: Megaphone,
color: "text-amber-600",
bgColor: "bg-amber-50",
},
{
slug: "pros",
title: "New pros",
icon: Briefcase,
color: "text-emerald-600",
bgColor: "bg-emerald-50",
},
{
slug: "homeowners",
title: "New homeowners",
icon: Users,
color: "text-purple-600",
bgColor: "bg-purple-50",
},
];
export function InternalMetricsPage() {
const { data, isLoading, isFetching, refetch, error } =
useLeadershipMetrics();
const generated = data?.generatedAt
? new Date(data.generatedAt).toLocaleString()
: null;
return (
<div className="min-h-screen bg-background p-4 sm:p-6 lg:p-8">
<div className="mx-auto max-w-6xl space-y-6">
<header className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
<div>
<h1 className="text-2xl font-bold sm:text-3xl">
Interioring — Internal Metrics
</h1>
<p
className="text-sm text-foreground-muted"
data-testid="metrics-generated-at"
>
{generated
? `Last updated ${generated}`
: "Loading…"}
</p>
</div>
<Button
variant="outline"
size="sm"
onClick={() => refetch()}
disabled={isFetching}
data-testid="metrics-refresh"
>
<RefreshCw
className={`mr-2 h-4 w-4 ${isFetching ? "animate-spin" : ""}`}
/>
Refresh
</Button>
</header>
{error ? (
<div
className="rounded border border-red-200 bg-red-50 p-4 text-sm text-red-800"
data-testid="metrics-error"
>
Failed to load metrics. Try refreshing.
</div>
) : null}
<div className="space-y-8">
{SECTIONS.map((section) => (
<section key={section.slug} className="space-y-3">
<h2 className="text-lg font-semibold sm:text-xl">
{section.title}
</h2>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4 sm:gap-4">
{WINDOWS.map((win) => {
const value =
data?.[section.slug]?.[win.key] ?? 0;
return (
<div
key={win.key}
data-testid={`stat-${section.slug}-${win.key}`}
>
<StatCard
name={win.label}
value={value}
subtext={section.title}
icon={section.icon}
color={section.color}
bgColor={section.bgColor}
isLoading={isLoading}
/>
</div>
);
})}
</div>
</section>
))}
</div>
</div>
</div>
);
}
export default InternalMetricsPage;
|