mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 22:18:12 +00:00
wAREHOUSE kPI strips
This commit is contained in:
@@ -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",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -30,3 +30,4 @@ export { WarehouseDashboardCharts } from './WarehouseDashboardCharts';
|
||||
export { InspectionReportModal } from './InspectionReportModal';
|
||||
export { FeePreviewModal } from './FeePreviewModal';
|
||||
export { ZoneOccupancyHeatmap } from './ZoneOccupancyHeatmap';
|
||||
export { WarehouseOpsKpiStrip } from './WarehouseOpsKpiStrip';
|
||||
|
||||
@@ -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}`
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: () =>
|
||||
|
||||
@@ -1107,3 +1107,11 @@ export interface ZoneOccupancy {
|
||||
/** 0–100+, 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user