An interactive demonstration of field technician performance comparisons. Explore ranking lists, radar attribute charts, and daily heatmap metrics.
Tech Leaderboard Laboratory
Track technician metrics, compare performance via radar visualizations, and analyze weekly matrices.
Click a row to see full metrics
1
Marcus Rivera
Jobs
47
Rating
4.9
Revenue
$18.4k
Avg Completion Time
1.4h
First-Time Fix Rate
94%
Callback Rate
2.1%
Utilization Rate
96%
2
Sandra Okafor
Jobs
43
Rating
4.7
Revenue
$16.9k
Avg Completion Time
1.6h
First-Time Fix Rate
90%
Callback Rate
3.5%
Utilization Rate
91%
3
James Whitfield
Jobs
51
Rating
4.4
Revenue
$15.6k
Avg Completion Time
1.9h
First-Time Fix Rate
82%
Callback Rate
5.9%
Utilization Rate
98%
4
Priya Nair
Jobs
38
Rating
4.8
Revenue
$14.2k
Avg Completion Time
1.5h
First-Time Fix Rate
88%
Callback Rate
4%
Utilization Rate
84%
5
Derek Tompkins
Jobs
40
Rating
4.2
Revenue
$13.8k
Avg Completion Time
2.1h
First-Time Fix Rate
79%
Callback Rate
7.2%
Utilization Rate
88%
6
Leila Hennessy
Jobs
33
Rating
4.0
Revenue
$11.3k
Avg Completion Time
2.3h
First-Time Fix Rate
75%
Callback Rate
8.8%
Utilization Rate
77%
7
Carlos Mendez
Jobs
29
Rating
3.7
Revenue
$9.4k
Avg Completion Time
2.6h
First-Time Fix Rate
70%
Callback Rate
11.4%
Utilization Rate
70%
8
Brenda Chu
Jobs
25
Rating
3.4
Revenue
$7.8k
Avg Completion Time
2.9h
First-Time Fix Rate
64%
Callback Rate
14.2%
Utilization Rate
63%
Gold
Silver
Bronze
Needs Attention
Variant1_RankedLeaderboard.tsx (Widget Implementation)
import { useState } from "react";
import {
Paper,
Group,
Stack,
Text,
Title,
Avatar,
Badge,
SegmentedControl,
Collapse,
Divider,
Box,
SimpleGrid,
} from "@mantine/core";
import {
HiArrowUp,
HiArrowDown,
HiMinus,
HiStar,
HiChevronDown,
HiChevronUp,
} from "react-icons/hi2";
import type { TechPerformance } from "./types";
import { sampleTechs } from "./sampleData";
// Medal / accent colors
const GOLD = "#FFD700";
const SILVER = "#C0C0C0";
const BRONZE = "#CD7F32";
const WARNING_BG = "#fff5f5";
function rankAccent(rank: number): string {
if (rank === 1) return GOLD;
if (rank === 2) return SILVER;
if (rank === 3) return BRONZE;
return "transparent";
}
function RankChange({ change }: { change: TechPerformance["rankChange"] }) {
if (change === "up") {
return <HiArrowUp size={14} color="#40c057" />;
}
if (change === "down") {
return <HiArrowDown size={14} color="#fa5252" />;
}
return <HiMinus size={14} color="#adb5bd" />;
}
function StarRating({ score }: { score: number }) {
const full = Math.round(score);
return (
<Group gap={1} align="center">
{Array.from({ length: 5 }).map((_, i) => (
<HiStar key={i} size={12} color={i < full ? "#fab005" : "#dee2e6"} />
))}
<Text size="xs" c="dimmed" ml={2}>
{score.toFixed(1)}
</Text>
</Group>
);
}
function formatRevenue(val: number): string {
if (val >= 1000) return `$${(val / 1000).toFixed(1)}k`;
return `$${val}`;
}
function MetricCell({ label, value }: { label: string; value: string }) {
return (
<Box>
<Text size="xs" c="dimmed" fw={500}>
{label}
</Text>
<Text size="sm" fw={600}>
{value}
</Text>
</Box>
);
}
function TechRow({
tech,
expanded,
onToggle,
}: {
tech: TechPerformance;
expanded: boolean;
onToggle: () => void;
}) {
const accent = rankAccent(tech.rank);
const isWarning = tech.rank >= sampleTechs.length - 1;
return (
<Box
style={{
borderRadius: 8,
backgroundColor: isWarning ? WARNING_BG : "transparent",
border: `1px solid ${isWarning ? "#ffa8a8" : "#e9ecef"}`,
overflow: "hidden",
cursor: "pointer",
}}
onClick={onToggle}
>
{/* Main row */}
<Group px="md" py="sm" gap="sm" wrap="nowrap" justify="space-between" align="center">
{/* Left: rank badge + avatar + name */}
<Group gap="sm" wrap="nowrap" style={{ flex: 1, minWidth: 0 }}>
{/* Rank number with medal accent */}
<Box
style={{
width: 32,
height: 32,
borderRadius: 6,
backgroundColor: accent === "transparent" ? "#f1f3f5" : accent,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
}}
>
<Text
size="sm"
fw={800}
style={{
color:
accent === "transparent" ? "#495057" : tech.rank === 1 ? "#7a5c00" : "#4a4a4a",
}}
>
{tech.rank}
</Text>
</Box>
{/* Trend arrow */}
<Box style={{ flexShrink: 0 }}>
<RankChange change={tech.rankChange} />
</Box>
{/* Avatar */}
<Avatar
size="sm"
radius="xl"
color={tech.rank <= 3 ? "yellow" : "blue"}
variant="filled"
style={{ flexShrink: 0 }}
>
{tech.initials}
</Avatar>
{/* Name */}
<Text size="sm" fw={600} truncate>
{tech.name}
</Text>
{isWarning && (
<Badge size="xs" color="red" variant="light" style={{ flexShrink: 0 }}>
Needs Attention
</Badge>
)}
</Group>
{/* Right: inline stats */}
<Group gap="lg" wrap="nowrap" style={{ flexShrink: 0 }}>
<Stack gap={0} align="center" style={{ minWidth: 40 }}>
<Text size="xs" c="dimmed">
Jobs
</Text>
<Text size="sm" fw={700}>
{tech.jobsCompleted}
</Text>
</Stack>
<Stack gap={2} align="flex-start" style={{ minWidth: 80 }}>
<Text size="xs" c="dimmed">
Rating
</Text>
<StarRating score={tech.customerSatisfaction} />
</Stack>
<Stack gap={0} align="center" style={{ minWidth: 54 }}>
<Text size="xs" c="dimmed">
Revenue
</Text>
<Text size="sm" fw={700} c="teal">
{formatRevenue(tech.revenueGenerated)}
</Text>
</Stack>
<Box style={{ color: "#adb5bd" }}>
{expanded ? <HiChevronUp size={16} /> : <HiChevronDown size={16} />}
</Box>
</Group>
</Group>
{/* Expanded details */}
<Collapse expanded={expanded}>
<Divider />
<Box px="md" py="sm" bg="gray.0">
<SimpleGrid cols={{ base: 2, xs: 3, sm: 4 }} spacing="sm">
<MetricCell label="Avg Completion Time" value={`${tech.avgCompletionTime}h`} />
<MetricCell label="First-Time Fix Rate" value={`${tech.firstTimeFixRate}%`} />
<MetricCell label="Callback Rate" value={`${tech.callbackRate}%`} />
<MetricCell label="Utilization Rate" value={`${tech.utilizationRate}%`} />
</SimpleGrid>
</Box>
</Collapse>
</Box>
);
}
interface Variant1Props {
techs?: TechPerformance[];
}
export function Variant1_RankedLeaderboard({ techs = sampleTechs }: Variant1Props) {
const [period, setPeriod] = useState<string>("week");
const [expandedId, setExpandedId] = useState<string | null>(null);
const sorted = [...techs].sort((a, b) => a.rank - b.rank);
const toggle = (id: string) => {
setExpandedId((prev) => (prev === id ? null : id));
};
return (
<Paper withBorder shadow="sm" radius="md" p="md">
{/* Header */}
<Group justify="space-between" mb="md" align="center">
<div>
<Title order={4} fw={700}>
Performance Leaderboard
</Title>
<Text size="xs" c="dimmed">
Click a row to see full metrics
</Text>
</div>
<SegmentedControl
size="xs"
value={period}
onChange={setPeriod}
data={[
{ label: "This Week", value: "week" },
{ label: "This Month", value: "month" },
]}
/>
</Group>
{/* Rows */}
<Stack gap="xs">
{sorted.map((tech) => (
<TechRow
key={tech.id}
tech={tech}
expanded={expandedId === tech.id}
onToggle={() => toggle(tech.id)}
/>
))}
</Stack>
{/* Legend */}
<Group gap="lg" mt="md" justify="flex-end">
<Group gap={4}>
<Box
style={{
width: 10,
height: 10,
borderRadius: 2,
backgroundColor: GOLD,
display: "inline-block",
}}
/>
<Text size="xs" c="dimmed">
Gold
</Text>
</Group>
<Group gap={4}>
<Box
style={{
width: 10,
height: 10,
borderRadius: 2,
backgroundColor: SILVER,
display: "inline-block",
}}
/>
<Text size="xs" c="dimmed">
Silver
</Text>
</Group>
<Group gap={4}>
<Box
style={{
width: 10,
height: 10,
borderRadius: 2,
backgroundColor: BRONZE,
display: "inline-block",
}}
/>
<Text size="xs" c="dimmed">
Bronze
</Text>
</Group>
<Group gap={4}>
<Box
style={{
width: 10,
height: 10,
borderRadius: 2,
backgroundColor: "#ffa8a8",
display: "inline-block",
}}
/>
<Text size="xs" c="dimmed">
Needs Attention
</Text>
</Group>
</Group>
</Paper>
);
}