trains, wagons,containers and cargoes schema and API

This commit is contained in:
hagiye
2026-06-04 15:56:29 +03:00
parent 18015ceaff
commit 71ac89edc7
66 changed files with 2077 additions and 90 deletions

View File

@@ -0,0 +1,44 @@
import { useCargoesByContainer, useDeliverCargo, useUnloadCargo } from '@/hooks/useCargoes';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { LoadCargoDialog } from './LoadCargoDialog';
export function CargoesTable({ containerId }: { containerId: string }) {
const { data: cargoes, refetch } = useCargoesByContainer(containerId);
const deliver = useDeliverCargo();
const unload = useUnloadCargo();
if (!cargoes?.length) return <div className="text-muted-foreground">No cargoes for this container.</div>;
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Reference</TableHead>
<TableHead>Description</TableHead>
<TableHead>Quantity</TableHead>
<TableHead>Weight (kg)</TableHead>
<TableHead>Status</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{cargoes.map(cargo => (
<TableRow key={cargo.id}>
<TableCell>{cargo.cargoReference}</TableCell>
<TableCell>{cargo.description || '-'}</TableCell>
<TableCell>{cargo.quantity}</TableCell>
<TableCell>{cargo.weight}</TableCell>
<TableCell><Badge variant="outline">{cargo.status}</Badge></TableCell>
<TableCell className="space-x-2">
{cargo.status === 'PENDING' && <LoadCargoDialog cargoId={cargo.id} onSuccess={() => refetch()} />}
{cargo.status === 'LOADED' && <Button size="sm" onClick={() => deliver.mutateAsync(cargo.id).then(() => refetch())}>Deliver</Button>}
{cargo.status === 'LOADED' && <Button size="sm" variant="outline" onClick={() => unload.mutateAsync(cargo.id).then(() => refetch())}>Unload</Button>}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}

View File

@@ -0,0 +1,38 @@
import { useState } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useLoadCargo } from '@/hooks/useCargoes';
import { useToast } from '@/hooks/use-toast';
export function LoadCargoDialog({ cargoId, onSuccess }: { cargoId: string; onSuccess?: () => void }) {
const [open, setOpen] = useState(false);
const [quantity, setQuantity] = useState(0);
const [weight, setWeight] = useState(0);
const [volume, setVolume] = useState<number>();
const load = useLoadCargo();
const { toast } = useToast();
const handleLoad = async () => {
await load.mutateAsync({ id: cargoId, quantity, weight, volume });
toast({ title: 'Loaded', description: 'Cargo loaded into container.' });
setOpen(false);
onSuccess?.();
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild><Button size="sm">Load Cargo</Button></DialogTrigger>
<DialogContent>
<DialogHeader><DialogTitle>Load Cargo</DialogTitle></DialogHeader>
<div className="space-y-4">
<div><Label>Quantity*</Label><Input type="number" required value={quantity} onChange={e => setQuantity(parseFloat(e.target.value))} /></div>
<div><Label>Weight (kg)*</Label><Input type="number" required value={weight} onChange={e => setWeight(parseFloat(e.target.value))} /></div>
<div><Label>Volume (m³)</Label><Input type="number" value={volume ?? ''} onChange={e => setVolume(parseFloat(e.target.value) || undefined)} /></div>
<Button onClick={handleLoad} disabled={load.isPending}>Confirm Load</Button>
</div>
</DialogContent>
</Dialog>
);
}