Shipment detail · Vektos
Tasks / Shipment detail One outbound shipment: carrier and tracking, status, destination, the packages with their weights, and the tracking history.
The brief What the agent reads, word for word.
What a good answer has The page must show these texts, or the run is not done. A good answer uses these components.
Best and worst runs By design-system violations.
By context and model Mean design-system violations per run on this task.
The reference answer Written by hand, graded with zero violations, rendered by the browser check in every build. The agent never sees it.
13 TableHeader,
14 TableRow,
15 } from "@vektos/ds";
16 import { css } from "styled-system/css";
17 import data from "./fixture.json";
18
19 const { shipment, packages, events } = data;
20 const { destination } = shipment;
21
22 const STATUS: Record<string, { text: string; tone: "neutral" | "success" | "warning" }> = {
23 in_transit: { text: "In transit", tone: "warning" },
24 delivered: { text: "Delivered", tone: "success" },
25 };
26 const status = STATUS[shipment.status] ?? { text: shipment.status, tone: "neutral" };
27
28 const kg = new Intl.NumberFormat("en-GB", {
29 style: "unit",
30 unit: "kilogram",
31 maximumFractionDigits: 2,
32 });
33 const day = new Intl.DateTimeFormat("en-GB", { dateStyle: "long", timeZone: "UTC" });
34 const time = new Intl.DateTimeFormat("en-GB", {
35 dateStyle: "medium",
36 timeStyle: "short",
37 timeZone: "UTC",
38 });
39
40 const totalKg = packages.reduce((sum, item) => sum + item.weightKg, 0);
41 const history = events.toSorted((a, b) => b.at.localeCompare(a.at));
42
43 export default function ShipmentPage() {
44 return (
45 <main className={css({ display: "flex", flexDirection: "column", gap: "6", p: "6" })}>
46 <header className={css({ display: "flex", alignItems: "center", gap: "3" })}>
47 <h1 className={css({ fontSize: "xl", fontWeight: "semibold" })}>Shipment {shipment.id}</h1>
48 <Badge tone={status.tone}>{status.text}</Badge>
49 </header>
50
51 <Grid gridTemplateColumns={{ base: "1fr", md: "repeat(2, 1fr)" }} gap="4">
52 <Card>
53 <CardHeader>
54 <CardTitle>Carrier</CardTitle>
55 </CardHeader>
56 <CardBody>
57 <DataList
58 items={[
59 { label: "Carrier", value: `${shipment.carrier}, ${shipment.service}` },
60 { label: "Tracking number", value: shipment.tracking },
61 { label: "Order", value: shipment.order },
62 { label: "Shipped", value: `${time.format(new Date(shipment.shippedAt))} UTC` },
63 {
64 label: "Estimated delivery",
65 value: day.format(new Date(shipment.estimatedDelivery)),
66 },
67 ]}
68 />
69 </CardBody>
70 </Card>
71 <Card>
72 <CardHeader>
73 <CardTitle>Destination</CardTitle>
74 </CardHeader>
75 <CardBody>
76 <address className={css({ fontStyle: "normal", lineHeight: "normal" })}>
77 {destination.name}
78 <br />
79 {destination.street}
80 <br />
81 {destination.postcode} {destination.city}
82 <br />
83 {destination.country}
84 </address>
85 </CardBody>
86 </Card>
87 </Grid>
88
89 <section className={css({ display: "flex", flexDirection: "column", gap: "3" })}>
90 <h2 className={css({ fontSize: "md", fontWeight: "semibold" })}>Packages</h2>
91 <Table aria-label="Packages">
92 <TableHead>
93 <TableRow>
94 <TableHeader>Package</TableHeader>
95 <TableHeader>Dimensions</TableHeader>
96 <TableHeader numeric>Weight</TableHeader>
97 </TableRow>
98 </TableHead>
99 <TableBody>
100 {packages.map((item) => (
101 <TableRow key={item.id}>
102 <TableCell>{item.id}</TableCell>
103 <TableCell>{item.dimensionsCm} cm</TableCell>
104 <TableCell numeric>{kg.format(item.weightKg)}</TableCell>
105 </TableRow>
106 ))}
107 <TableRow>
108 <TableCell>Total weight</TableCell>
109 <TableCell>
110 {packages.length} {packages.length === 1 ? "package" : "packages"}
111 </TableCell>
112 <TableCell numeric>{kg.format(totalKg)}</TableCell>
113 </TableRow>
114 </TableBody>
115 </Table>
116 </section>
117
118 <section className={css({ display: "flex", flexDirection: "column", gap: "3" })}>
119 <h2 className={css({ fontSize: "md", fontWeight: "semibold" })}>Tracking history</h2>
120 <Table aria-label="Tracking history, newest first">
121 <TableHead>
122 <TableRow>
123 <TableHeader>Time (UTC)</TableHeader>
124 <TableHeader>Place</TableHeader>
125 <TableHeader>Event</TableHeader>
126 </TableRow>
127 </TableHead>
128 <TableBody>
129 {history.map((event) => (
130 <TableRow key={event.at}>
131 <TableCell>{time.format(new Date(event.at))}</TableCell>
132 <TableCell>{event.location}</TableCell>
133 <TableCell>{event.description}</TableCell>
134 </TableRow>
135 ))}
136 </TableBody>
137 </Table>
138 </section>
139 </main>
140 );
141 }
142