mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 18:48:11 +00:00
feat(warehouse): make the ops KPI cards link to their detail
The dashboard counters were static — "Trucks on-site" showed a number with no way to open the list behind it, same for the others. KpiStrip now takes an optional href per item: a cell with one becomes a link (pointer, hover tint, aria-label) and a cell without one stays exactly as before, so every existing strip is unaffected. The warehouse ops strip wires each card to its detail: trucks on-site to the Trucks on Site page, received-today and pending-inspection to the inventory board filtered to RECEIVED, items-aging to the inventory board. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { Card, Skeleton, Text } from "@mantine/core";
|
import { Card, Skeleton, Text } from "@mantine/core";
|
||||||
import type { LucideIcon } from "lucide-react";
|
import type { LucideIcon } from "lucide-react";
|
||||||
import type { ReactNode } from "react";
|
import type { ElementType, ReactNode } from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -22,6 +23,11 @@ export interface KpiItem {
|
|||||||
* (green up, red down, muted zero). E.g. today's count minus yesterday's.
|
* (green up, red down, muted zero). E.g. today's count minus yesterday's.
|
||||||
*/
|
*/
|
||||||
delta?: number;
|
delta?: number;
|
||||||
|
/**
|
||||||
|
* Optional route the cell links to — its detail view. When set the cell
|
||||||
|
* becomes clickable (pointer, hover tint); when absent it stays static.
|
||||||
|
*/
|
||||||
|
href?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface KpiStripProps {
|
export interface KpiStripProps {
|
||||||
@@ -47,13 +53,22 @@ export function KpiStrip({ items, loading = false }: KpiStripProps) {
|
|||||||
{cells.map((item, index) => {
|
{cells.map((item, index) => {
|
||||||
const Icon = item.icon;
|
const Icon = item.icon;
|
||||||
const color = item.color ?? "edr-green";
|
const color = item.color ?? "edr-green";
|
||||||
|
// A cell with an href becomes a link to its detail; without one it
|
||||||
|
// stays a plain div. Same layout classes either way.
|
||||||
|
const Cell: ElementType = item.href ? Link : "div";
|
||||||
|
const linkProps = item.href
|
||||||
|
? { to: item.href, "aria-label": `${item.label} — view detail` }
|
||||||
|
: {};
|
||||||
return (
|
return (
|
||||||
<div
|
<Cell
|
||||||
key={item.label}
|
key={item.label}
|
||||||
|
{...(linkProps as Record<string, unknown>)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-1 items-center gap-3 px-5 py-4",
|
"flex flex-1 items-center gap-3 px-5 py-4",
|
||||||
index > 0 &&
|
index > 0 &&
|
||||||
"border-t border-edr-border sm:border-l sm:border-t-0",
|
"border-t border-edr-border sm:border-l sm:border-t-0",
|
||||||
|
item.href &&
|
||||||
|
"cursor-pointer no-underline transition-colors hover:bg-gray-50 focus-visible:bg-gray-50",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{Icon ? (
|
{Icon ? (
|
||||||
@@ -102,7 +117,7 @@ export function KpiStrip({ items, loading = false }: KpiStripProps) {
|
|||||||
{item.hint ? ` · ${item.hint}` : ""}
|
{item.hint ? ` · ${item.hint}` : ""}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Cell>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,18 +23,23 @@ export function WarehouseOpsKpiStrip() {
|
|||||||
delta:
|
delta:
|
||||||
data != null ? data.receivedToday - data.receivedYesterday : undefined,
|
data != null ? data.receivedToday - data.receivedYesterday : undefined,
|
||||||
hint: "vs yesterday",
|
hint: "vs yesterday",
|
||||||
|
// The received cargo itself, on the inventory board.
|
||||||
|
href: "/dashboard/warehouse-inventory?status=RECEIVED",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Pending inspection",
|
label: "Pending inspection",
|
||||||
value: data?.pendingInspection ?? 0,
|
value: data?.pendingInspection ?? 0,
|
||||||
icon: ClipboardCheck,
|
icon: ClipboardCheck,
|
||||||
color: "yellow",
|
color: "yellow",
|
||||||
|
// Received cargo still awaiting inspection lives in the RECEIVED bucket.
|
||||||
|
href: "/dashboard/warehouse-inventory?status=RECEIVED",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Trucks on-site",
|
label: "Trucks on-site",
|
||||||
value: data?.trucksOnSite ?? 0,
|
value: data?.trucksOnSite ?? 0,
|
||||||
icon: Truck,
|
icon: Truck,
|
||||||
color: "blue",
|
color: "blue",
|
||||||
|
href: "/dashboard/trucks-on-site",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Items aging (>7d)",
|
label: "Items aging (>7d)",
|
||||||
@@ -42,6 +47,8 @@ export function WarehouseOpsKpiStrip() {
|
|||||||
icon: AlertTriangle,
|
icon: AlertTriangle,
|
||||||
color: (data?.itemsAging ?? 0) > 0 ? "red" : "edr-green",
|
color: (data?.itemsAging ?? 0) > 0 ? "red" : "edr-green",
|
||||||
hint: "In warehouse over 7 days",
|
hint: "In warehouse over 7 days",
|
||||||
|
// No aging filter on the board; the inventory list is the landing.
|
||||||
|
href: "/dashboard/warehouse-inventory",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user