booking operations and trains scheduling also allocations

This commit is contained in:
marshal
2026-06-10 00:48:32 +03:00
parent 675975bc08
commit 5774d7db9d
180 changed files with 13423 additions and 3877 deletions

View File

@@ -1,53 +1,90 @@
import { useState } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
// import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useWagons, useAssignWagonToTrain } from '@/hooks/useWagons';
import { useToast } from '@/hooks/use-toast';
import { Plus } from 'lucide-react';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@edr/ui-common';
import { useState } from "react";
import { Plus } from "lucide-react";
import { Button, Group, Modal, NumberInput, Select, Stack, Text } from "@mantine/core";
import { Freight } from "@edr/types";
import { useToast } from "@/hooks/use-toast";
import { useAssignWagonToTrain, useWagons } from "@/hooks/useWagons";
export function AssignWagonDialog({ trainId }: { trainId: string }) {
const [open, setOpen] = useState(false);
const [wagonId, setWagonId] = useState('');
const [sequence, setSequence] = useState<number>();
const [wagonId, setWagonId] = useState<string | null>(null);
const [sequence, setSequence] = useState<number | "">("");
const { data: wagons } = useWagons();
const assign = useAssignWagonToTrain();
const { toast } = useToast();
const available = wagons?.filter((w:any) => w.status === 'AVAILABLE' || !w.trainId);
const available = (wagons ?? []).filter(
(w) => w.status === Freight.WagonStatus.Available || !w.trainId,
);
const wagonOptions = available.map((w) => ({
value: w.id,
label: `${w.wagonNumber} (${w.readiness.replace("_", " ").toLowerCase()})`,
}));
const handleAssign = async () => {
if (!wagonId) return;
await assign.mutateAsync({ wagonId, trainId, sequenceNumber: sequence });
toast({ title: 'Assigned', description: 'Wagon attached to train.' });
setOpen(false);
try {
await assign.mutateAsync({
wagonId,
trainId,
sequenceNumber: sequence === "" ? undefined : Number(sequence),
});
toast({ title: "Wagon attached to train" });
setOpen(false);
setWagonId(null);
setSequence("");
} catch {
toast({ title: "Failed to assign wagon", variant: "destructive" });
}
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild><Button size="sm"><Plus className="mr-2 h-4 w-4" />Assign Wagon</Button></DialogTrigger>
<DialogContent>
<DialogHeader><DialogTitle>Assign Wagon to Train</DialogTitle></DialogHeader>
<div className="space-y-4">
<div>
<Label>Wagon</Label>
<Select value={wagonId} onValueChange={setWagonId}>
<SelectTrigger><SelectValue placeholder="Select wagon" /></SelectTrigger>
<SelectContent>
{available?.map((w:any) => <SelectItem key={w.id} value={w.id}>{w.wagonNumber}</SelectItem>)}
</SelectContent>
</Select>
</div>
<div>
<Label>Sequence (optional)</Label>
<Input type="number" value={sequence ?? ''} onChange={e => setSequence(parseInt(e.target.value) || undefined)} />
</div>
<Button onClick={handleAssign} disabled={assign.isPending}>Assign</Button>
</div>
</DialogContent>
</Dialog>
<>
<Button
color="green"
size="sm"
radius="lg"
leftSection={<Plus size={16} />}
onClick={() => setOpen(true)}
>
Assign wagon
</Button>
<Modal
opened={open}
onClose={() => setOpen(false)}
title={<Text fw={600}>Assign wagon to train</Text>}
radius="lg"
centered
>
<Stack gap="md">
<Select
label="Wagon"
placeholder="Select wagon"
data={wagonOptions}
value={wagonId}
onChange={setWagonId}
searchable
/>
<NumberInput
label="Sequence (optional)"
value={sequence}
onChange={(value) => setSequence(value === "" ? "" : Number(value))}
min={1}
/>
<Group justify="flex-end">
<Button variant="default" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button color="green" loading={assign.isPending} onClick={handleAssign}>
Assign
</Button>
</Group>
</Stack>
</Modal>
</>
);
}
}