wAREHOUSE kPI strips

This commit is contained in:
Hagernesh
2026-07-13 13:38:28 +00:00
parent 452355e292
commit a542a13893
11 changed files with 120 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import { AlertTriangle, ClipboardCheck, PackageCheck, Truck } from "lucide-react";
import { KpiStrip } from "@/components/page";
import { useWarehouseOpsStats } from "@/hooks/useWarehouses";
/**
* At-a-glance warehouse ops KPIs (received today, pending inspection, trucks
* on-site, items aging). Drop-in for any warehouse ops page header.
*/
export function WarehouseOpsKpiStrip() {
const { data, isLoading } = useWarehouseOpsStats();
return (
<KpiStrip
loading={isLoading}
items={[
{
label: "Received today",
value: data?.receivedToday ?? 0,
icon: PackageCheck,
color: "edr-green",
},
{
label: "Pending inspection",
value: data?.pendingInspection ?? 0,
icon: ClipboardCheck,
color: "yellow",
},
{
label: "Trucks on-site",
value: data?.trucksOnSite ?? 0,
icon: Truck,
color: "blue",
},
{
label: "Items aging (>7d)",
value: data?.itemsAging ?? 0,
icon: AlertTriangle,
color: (data?.itemsAging ?? 0) > 0 ? "red" : "edr-green",
hint: "In warehouse over 7 days",
},
]}
/>
);
}

View File

@@ -30,3 +30,4 @@ export { WarehouseDashboardCharts } from './WarehouseDashboardCharts';
export { InspectionReportModal } from './InspectionReportModal';
export { FeePreviewModal } from './FeePreviewModal';
export { ZoneOccupancyHeatmap } from './ZoneOccupancyHeatmap';
export { WarehouseOpsKpiStrip } from './WarehouseOpsKpiStrip';

View File

@@ -486,6 +486,7 @@ export const URL_CONSTANTS = {
MOVE: (id: string) => `/warehouse-inventory/${id}/move`,
RESERVE: "/warehouse-inventory/reserve",
ARRIVAL_QUEUE: "/warehouse-inventory/arrival-queue",
OPS_STATS: "/warehouse-inventory/ops-stats",
ZONE_OCCUPANCY: (yardId?: string) =>
yardId
? `/warehouse-inventory/zone-occupancy?yardId=${yardId}`

View File

@@ -144,6 +144,14 @@ export function useZoneOccupancy(yardId?: string) {
});
}
/** At-a-glance warehouse ops counters for the KPI strip. */
export function useWarehouseOpsStats() {
return useQuery({
queryKey: ['warehouse-inventory', 'ops-stats'],
queryFn: () => warehouseService.opsStats().then((r) => r.data),
});
}
export function useCreateZone() {
const qc = useQueryClient();
return useMutation({

View File

@@ -15,6 +15,7 @@ import { ChevronDown, ChevronRight, PackageOpen, Truck } from 'lucide-react';
import { PageContainer, PageHeader } from '@/components/page';
import {
VisualEmptyState,
WarehouseOpsKpiStrip,
formatDate,
formatNumber,
} from '@/components/warehouses';
@@ -291,6 +292,8 @@ export default function ArrivalQueuePage() {
breadcrumbs={[{ label: 'Arrival queue' }]}
/>
<WarehouseOpsKpiStrip />
<Card withBorder radius="md" padding="lg">
<Group justify="space-between" mb="md">
<Stack gap={2}>

View File

@@ -29,6 +29,7 @@ import {
ActivityTimeline,
InventoryMovementHistoryTable,
VisualEmptyState,
WarehouseOpsKpiStrip,
formatDate,
formatNumber,
} from '@/components/warehouses';
@@ -292,6 +293,8 @@ export default function ExportDjiboutiUnloadingQueuePage() {
breadcrumbs={[{ label: 'Djibouti Arrival / Unloading Queue' }]}
/>
<WarehouseOpsKpiStrip />
<Card withBorder radius="md" padding="lg">
<Group justify="space-between" mb="md">
<Text fw={600}>{trains.length} arrived export train(s)</Text>

View File

@@ -8,6 +8,7 @@ import { PageContainer, PageHeader } from '@/components/page';
import {
InventoryWorkbench,
VisualEmptyState,
WarehouseOpsKpiStrip,
formatNumber,
} from '@/components/warehouses';
import { LoadToTrainPanel } from '@/components/warehouses/LoadToTrainPanel';
@@ -74,6 +75,8 @@ export default function LoadingQueuePage() {
}
/>
<WarehouseOpsKpiStrip />
<Card>
<Tabs defaultValue="ready">
<Tabs.List>

View File

@@ -5,6 +5,7 @@ import { api as apiClient } from '../auth/http';
import { URL_CONSTANTS } from '@/constants/URLS';
import type {
ZoneOccupancy,
WarehouseOpsStats,
AllocationCriteria,
AllocationPreviewResult,
AllocationRule,
@@ -370,6 +371,8 @@ export const warehouseService = {
apiClient.get<ZoneOccupancy[]>(
URL_CONSTANTS.WAREHOUSE_INVENTORY.ZONE_OCCUPANCY(yardId),
),
opsStats: () =>
apiClient.get<WarehouseOpsStats>(URL_CONSTANTS.WAREHOUSE_INVENTORY.OPS_STATS),
autoUnloadArrived: () =>
apiClient.post<AutoUnloadResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.AUTO_UNLOAD_ARRIVED),
autoLoadReady: () =>

View File

@@ -1107,3 +1107,11 @@ export interface ZoneOccupancy {
/** 0100+, container-count based (weight is a rough fallback). Null if no capacity set. */
occupancyPct: number | null;
}
/** At-a-glance warehouse ops counters for the KPI strip. */
export interface WarehouseOpsStats {
receivedToday: number;
pendingInspection: number;
trucksOnSite: number;
itemsAging: number;
}