import { Link as RouterLink } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import Box from "@mui/material/Box"; import Typography from "@mui/material/Typography"; import { useAuth } from "../context/AuthContext"; import Forbidden from "../components/Forbidden"; import { warehouseStockStatusOptions, warehouseBelowMinimumOptions, warehouseReservationListOptions, warehouseMovementLogOptions, type WarehouseItem, type MovementLogRow, } from "../lib/queries/warehouse"; import { formatCurrency, formatDate } from "../utils/formatters"; import { Button, Card, DataTable, StatCard, StatusChip, EmptyState, LoadingState, PageHeader, PageEnter, type DataColumn, type StatCardColor, } from "../ui"; const TYPE_LABEL: Record = { receipt: "Příjem", issue: "Výdej", }; // Movement type → StatusChip color (legacy: incoming=success, outgoing=info) const TYPE_COLOR: Record = { receipt: "success", issue: "info", }; const ReceiptIcon = ( ); const IssueIcon = ( ); interface BelowMinRow { id: number; name: string; available_quantity: number; min_quantity: number; } // Dashboard movement row = the shared lib row plus a stable list index for rowKey. type MovementRow = MovementLogRow & { _idx: number }; export default function Warehouse() { const { hasPermission } = useAuth(); const { data: stockItems, isPending: stockPending } = useQuery( warehouseStockStatusOptions(), ); const { data: belowMinItems, isPending: belowMinPending } = useQuery( warehouseBelowMinimumOptions(), ); const { data: reservationsData, isPending: reservationsPending } = useQuery( warehouseReservationListOptions({ status: "ACTIVE", perPage: 1 }), ); const { data: recentMovements = [], isPending: movementsLoading } = useQuery( warehouseMovementLogOptions({ limit: 10 }), ); if (!hasPermission("warehouse.view")) return ; const items = (stockItems as WarehouseItem[] | undefined) ?? []; const belowMin = (belowMinItems as WarehouseItem[] | undefined) ?? []; const activeReservationCount = (reservationsData as { pagination?: { total: number } } | undefined) ?.pagination?.total ?? 0; const totalItems = items.length; const totalStockValue = items.reduce( (sum, item) => sum + (item.stock_value ?? 0), 0, ); const belowMinimumCount = belowMin.length; const isLoading = stockPending || belowMinPending || reservationsPending || movementsLoading; const belowMinColor: StatCardColor = belowMinimumCount > 0 ? "error" : "warning"; const belowMinColumns: DataColumn[] = [ { key: "name", header: "Název", width: "50%", bold: true, render: (item) => item.name, }, { key: "available_quantity", header: "K dispozici", width: "25%", mono: true, render: (item) => String(item.available_quantity), }, { key: "min_quantity", header: "Min. množství", width: "25%", mono: true, render: (item) => String(item.min_quantity), }, ]; const movementColumns: DataColumn[] = [ { key: "date", header: "Datum", width: "12%", mono: true, render: (row) => formatDate(row.date), }, { key: "type", header: "Typ", width: "12%", render: (row) => ( ), }, { key: "document_number", header: "Doklad", width: "16%", mono: true, render: (row) => row.document_number || "—", }, { key: "item_name", header: "Položka", width: "28%", bold: true, render: (row) => row.item_name, }, { key: "quantity", header: "Množství", width: "12%", mono: true, render: (row) => String(row.quantity), }, { key: "supplier_or_project", header: "Dodavatel / Projekt", width: "20%", render: (row) => row.supplier_or_project || "—", }, ]; return ( {hasPermission("warehouse.operate") && ( <> )} {hasPermission("warehouse.manage") && ( )} } /> {/* KPI cards */} {/* Below minimum alert */} {belowMin.length > 0 && ( Položky pod minimem columns={belowMinColumns} rows={belowMin.map((item) => ({ id: item.id, name: item.name, available_quantity: item.available_quantity ?? 0, min_quantity: item.min_quantity ?? 0, }))} rowKey={(item) => item.id} rowDanger={() => true} /> )} {/* Recent movements */} Poslední pohyby {movementsLoading ? ( ) : ( columns={movementColumns} rows={recentMovements.map((row, i) => ({ ...row, _idx: i }))} rowKey={(row) => row._idx} empty={} /> )} ); }