diff --git a/apps/edr-freight-api/src/modules/warehouses/warehouse-dashboard.service.ts b/apps/edr-freight-api/src/modules/warehouses/warehouse-dashboard.service.ts index 0bbcdee48..3eee095f8 100644 --- a/apps/edr-freight-api/src/modules/warehouses/warehouse-dashboard.service.ts +++ b/apps/edr-freight-api/src/modules/warehouses/warehouse-dashboard.service.ts @@ -3,6 +3,7 @@ import { DataSource, FindManyOptions, IsNull, ObjectLiteral, Repository } from ' import { Warehouse } from './entities/warehouse.entity'; import { WarehouseInventory } from './entities/warehouse-inventory.entity'; +import { SchedulingReadFacade } from './scheduling-read.facade'; export interface WarehouseDashboard { totalWarehouses: number; @@ -20,11 +21,45 @@ export interface WarehouseDashboard { // Import branch readyForPickup: number; delivered: number; + // Fleet / train snapshot + emptyContainers: number; + importTrains: number; + exportTrains: number; } @Injectable() export class WarehouseDashboardService { - constructor(private readonly dataSource: DataSource) {} + constructor( + private readonly dataSource: DataSource, + private readonly schedulingRead: SchedulingReadFacade, + ) {} + + private async safeQueryCount(sql: string, params: unknown[] = []): Promise { + try { + const rows = await this.dataSource.query(sql, params); + return Number(rows?.[0]?.count) || 0; + } catch { + return 0; + } + } + + /** ARRIVED trains with IMPORT-direction routing — same set as the import arrival queue. */ + private async safeImportTrains(): Promise { + try { + return (await this.schedulingRead.importArriveQueue()).length; + } catch { + return 0; + } + } + + /** Trains at/near Djibouti relevant to the export flow — same set as the Djibouti unloading queue. */ + private async safeExportTrains(): Promise { + try { + return (await this.schedulingRead.exportDjiboutiArrivalQueue()).length; + } catch { + return 0; + } + } private async safeCount( repo: Repository, @@ -69,6 +104,9 @@ export class WarehouseDashboardService { readyForPickup, delivered, receivedToday, + emptyContainers, + importTrains, + exportTrains, ] = await Promise.all([ this.safeCount(warehouseRepo), this.safeCount(inventoryRepo), @@ -82,6 +120,16 @@ export class WarehouseDashboardService { this.safeCount(inventoryRepo, { where: { status: 'READY_FOR_PICKUP' } }), this.safeCount(inventoryRepo, { where: { status: 'DELIVERED' } }), this.safeReceivedToday(startOfToday), + // ponytail: the container fleet has no literal EMPTY status (AVAILABLE | LOADED | + // IN_TRANSIT | MAINTENANCE | DAMAGED) — AVAILABLE (not on a wagon, not in transit, + // not flagged) is the closest proxy for "empty and free to use". Revisit if the + // domain ever grows a real empty/full distinction per container. + this.safeQueryCount( + `SELECT count(*)::int AS count FROM freight.containers WHERE deleted_at IS NULL AND status = $1`, + ['AVAILABLE'], + ), + this.safeImportTrains(), + this.safeExportTrains(), ]); return { @@ -97,6 +145,9 @@ export class WarehouseDashboardService { dispatched, readyForPickup, delivered, + emptyContainers, + importTrains, + exportTrains, }; } } diff --git a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx index d8298761a..93dd830a2 100644 --- a/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/warehouses/WarehouseDashboardPage.tsx @@ -1,18 +1,17 @@ import { useNavigate } from 'react-router-dom'; import { Badge, Card, Center, Divider, Group, Loader, SimpleGrid, Stack, Text, ThemeIcon } from '@mantine/core'; import { - ClipboardCheck, ClipboardList, - ShieldCheck, PackageCheck, + PackageOpen, PackagePlus, PackageSearch, CircleCheck, Send, + Train, Truck, Warehouse as WarehouseIcon, Boxes, - Layers, } from 'lucide-react'; import { PageContainer, PageHeader } from '@/components/page'; @@ -53,13 +52,13 @@ const METRICS: Metric[] = [ { key: 'totalInventory', label: 'Total Inventory', icon: , to: '/dashboard/warehouse-inventory', theme: GREEN }, { key: 'receivedToday', label: 'Received Today', icon: , to: '/dashboard/warehouse-inventory?status=RECEIVED', theme: ORANGE }, { key: 'awaitingInspection', label: 'Awaiting Inspection', icon: , to: '/dashboard/warehouse-inventory?status=RECEIVED', theme: GREEN }, - { key: 'inspected', label: 'Inspected', icon: , to: '/dashboard/warehouse-inventory', theme: ORANGE }, - { key: 'stored', label: 'Stored', icon: , to: '/dashboard/warehouse-inventory?status=STORED', theme: GREEN }, - { key: 'reserved', label: 'Reserved', icon: , to: '/dashboard/warehouse-inventory?status=RESERVED', theme: ORANGE }, - { key: 'readyForLoading', label: 'Ready For Loading', icon: , to: '/dashboard/loading-queue', theme: GREEN }, - { key: 'loaded', label: 'Loaded', icon: , to: '/dashboard/loaded-inventory', theme: ORANGE }, - { key: 'dispatched', label: 'Dispatched', icon: , to: '/dashboard/dispatch-queue', theme: GREEN }, - { key: 'readyForPickup', label: 'Ready For Pickup', icon: , to: '/dashboard/warehouse-inventory?status=READY_FOR_PICKUP', theme: ORANGE }, + { key: 'emptyContainers', label: 'Empty Containers', icon: , to: '/dashboard/containers', theme: ORANGE }, + { key: 'importTrains', label: 'Import Trains', icon: , to: '/dashboard/import-warehouse', theme: GREEN }, + { key: 'exportTrains', label: 'Export Trains', icon: , to: '/dashboard/export-warehouse', theme: ORANGE }, + { key: 'loaded', label: 'Loaded', icon: , to: '/dashboard/loaded-inventory', theme: GREEN }, + { key: 'dispatched', label: 'Dispatched', icon: , to: '/dashboard/dispatch-queue', theme: ORANGE }, + { key: 'readyForPickup', label: 'Ready For Pickup', icon: , to: '/dashboard/warehouse-inventory?status=READY_FOR_PICKUP', theme: GREEN }, + { key: 'readyForLoading', label: 'Ready For Loading', icon: , to: '/dashboard/loading-queue', theme: ORANGE }, { key: 'delivered', label: 'Delivered', icon: , to: '/dashboard/warehouse-inventory?status=DELIVERED', theme: GREEN }, ]; diff --git a/apps/edr-freight-web/backoffice/src/types/warehouse.ts b/apps/edr-freight-web/backoffice/src/types/warehouse.ts index aac7e532d..1773fb9b9 100644 --- a/apps/edr-freight-web/backoffice/src/types/warehouse.ts +++ b/apps/edr-freight-web/backoffice/src/types/warehouse.ts @@ -299,6 +299,9 @@ export interface WarehouseDashboard { dispatched: number; readyForPickup: number; delivered: number; + emptyContainers: number; + importTrains: number; + exportTrains: number; } // ── Loading (Batch 3) ────────────────────────────────────────────────────────