Files
zentral/frontend/src/modules/warehouse/pages/InventoryListPage.tsx
2025-11-29 17:01:20 +01:00

205 lines
5.8 KiB
TypeScript

import { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useNavigate } from "react-router-dom";
import {
Box,
Typography,
Button,
Paper,
Chip,
IconButton,
Tooltip,
} from "@mui/material";
import {
DataGrid,
GridColDef,
GridRenderCellParams,
GridToolbar,
} from "@mui/x-data-grid";
import {
Add as AddIcon,
Visibility as ViewIcon,
PlayArrow as StartIcon,
Cancel as CancelIcon,
} from "@mui/icons-material";
import { inventoryService } from "../services/warehouseService";
import { InventoryCountDto, InventoryStatus } from "../types";
import dayjs from "dayjs";
export default function InventoryListPage() {
const navigate = useNavigate();
const queryClient = useQueryClient();
const [statusFilter] = useState<InventoryStatus | undefined>(
undefined
);
const { data: inventories = [], isLoading } = useQuery({
queryKey: ["inventory-counts", statusFilter],
queryFn: () => inventoryService.getAll(statusFilter),
});
const cancelMutation = useMutation({
mutationFn: (id: number) => inventoryService.cancel(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["inventory-counts"] });
},
});
const handleCreate = () => {
navigate("/warehouse/inventory/new");
};
const handleView = (id: number) => {
navigate(`/warehouse/inventory/${id}`);
};
const handleStart = (id: number) => {
navigate(`/warehouse/inventory/${id}/count`);
};
const getStatusChip = (status: InventoryStatus) => {
switch (status) {
case InventoryStatus.Draft:
return <Chip label="Bozza" size="small" />;
case InventoryStatus.InProgress:
return <Chip label="In Corso" color="primary" size="small" />;
case InventoryStatus.Completed:
return <Chip label="Completato" color="info" size="small" />;
case InventoryStatus.Confirmed:
return <Chip label="Confermato" color="success" size="small" />;
case InventoryStatus.Cancelled:
return <Chip label="Annullato" color="error" size="small" />;
default:
return <Chip label={status} size="small" />;
}
};
const columns: GridColDef[] = [
{ field: "code", headerName: "Codice", width: 120 },
{ field: "description", headerName: "Descrizione", flex: 1, minWidth: 200 },
{
field: "inventoryDate",
headerName: "Data Inventario",
width: 150,
valueFormatter: (value) =>
value ? dayjs(value).format("DD/MM/YYYY") : "",
},
{ field: "warehouseName", headerName: "Magazzino", width: 180 },
{ field: "categoryName", headerName: "Categoria", width: 150 },
{
field: "status",
headerName: "Stato",
width: 120,
renderCell: (params: GridRenderCellParams<InventoryCountDto>) =>
getStatusChip(params.row.status),
},
{
field: "progress",
headerName: "Progresso",
width: 150,
valueGetter: (_value, row) => {
if (!row.lineCount) return "0%";
const percentage = Math.round(
(row.countedLineCount / row.lineCount) * 100
);
return `${row.countedLineCount}/${row.lineCount} (${percentage}%)`;
},
},
{
field: "actions",
headerName: "Azioni",
width: 180,
sortable: false,
renderCell: (params: GridRenderCellParams<InventoryCountDto>) => (
<Box>
<Tooltip title="Dettaglio">
<IconButton size="small" onClick={() => handleView(params.row.id)}>
<ViewIcon />
</IconButton>
</Tooltip>
{params.row.status === InventoryStatus.Draft && (
<Tooltip title="Avvia Conteggio">
<IconButton
size="small"
color="primary"
onClick={() => handleStart(params.row.id)}
>
<StartIcon />
</IconButton>
</Tooltip>
)}
{params.row.status === InventoryStatus.InProgress && (
<Tooltip title="Continua Conteggio">
<IconButton
size="small"
color="primary"
onClick={() => handleStart(params.row.id)}
>
<StartIcon />
</IconButton>
</Tooltip>
)}
{params.row.status === InventoryStatus.Draft && (
<Tooltip title="Annulla">
<IconButton
size="small"
color="error"
onClick={() => {
if (confirm("Sei sicuro di voler annullare questo inventario?")) {
cancelMutation.mutate(params.row.id);
}
}}
>
<CancelIcon />
</IconButton>
</Tooltip>
)}
</Box>
),
},
];
return (
<Box sx={{ p: 3 }}>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
mb: 3,
}}
>
<Typography variant="h4">Inventari Fisici</Typography>
<Button
variant="contained"
startIcon={<AddIcon />}
onClick={handleCreate}
>
Nuovo Inventario
</Button>
</Box>
<Paper sx={{ height: 600, width: "100%" }}>
<DataGrid
rows={inventories}
columns={columns}
loading={isLoading}
slots={{ toolbar: GridToolbar }}
slotProps={{
toolbar: {
showQuickFilter: true,
},
}}
disableRowSelectionOnClick
initialState={{
pagination: { paginationModel: { pageSize: 25 } },
sorting: {
sortModel: [{ field: "inventoryDate", sort: "desc" }],
},
}}
/>
</Paper>
</Box>
);
}