mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 21:20:57 +00:00
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
import { useMemo, useState } from "react";
|
|
import { Button, Group, Modal, Stack, Text, TextInput, Textarea } from "@mantine/core";
|
|
import toast from "react-hot-toast";
|
|
|
|
import { trainSchedulingService } from "@/services/trainScheduling.service";
|
|
|
|
/** `min` for a `datetime-local` input: now, in the browser's local zone. */
|
|
function nowLocalDateTime(): string {
|
|
const now = new Date();
|
|
const pad = (n: number) => String(n).padStart(2, "0");
|
|
return (
|
|
`${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}` +
|
|
`T${pad(now.getHours())}:${pad(now.getMinutes())}`
|
|
);
|
|
}
|
|
|
|
export function RescheduleTrainDialog({
|
|
scheduleId,
|
|
currentBookingIds,
|
|
opened,
|
|
onClose,
|
|
onComplete,
|
|
}: {
|
|
scheduleId: string;
|
|
currentBookingIds: string[];
|
|
opened: boolean;
|
|
onClose: () => void;
|
|
onComplete?: () => void;
|
|
}) {
|
|
const [newDepartureDate, setNewDepartureDate] = useState("");
|
|
const [reason, setReason] = useState("");
|
|
const [loading, setLoading] = useState(false);
|
|
// Earliest selectable departure, refreshed each time the dialog opens.
|
|
const minDepartureDate = useMemo(
|
|
() => (opened ? nowLocalDateTime() : ""),
|
|
[opened],
|
|
);
|
|
|
|
const handleSubmit = async () => {
|
|
if (!newDepartureDate) {
|
|
toast.error("Select a new departure date");
|
|
return;
|
|
}
|
|
if (new Date(newDepartureDate).getTime() < Date.now()) {
|
|
toast.error("New departure must be in the future");
|
|
return;
|
|
}
|
|
setLoading(true);
|
|
try {
|
|
await trainSchedulingService.maintenanceReschedule(scheduleId, {
|
|
incomingBookingIds: currentBookingIds,
|
|
newDepartureDate: new Date(newDepartureDate).toISOString(),
|
|
reason,
|
|
});
|
|
toast.success("Train rescheduled for maintenance");
|
|
onComplete?.();
|
|
onClose();
|
|
} catch {
|
|
toast.error("Reschedule failed");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Modal opened={opened} onClose={onClose} title="Reschedule train (maintenance)" radius="lg">
|
|
<Stack gap="md">
|
|
<Text size="sm" c="dimmed">
|
|
Updates departure and rebalances bookings on this train. Displaced bookings return to
|
|
the operations queue when capacity is insufficient.
|
|
</Text>
|
|
<TextInput
|
|
label="New departure"
|
|
type="datetime-local"
|
|
min={minDepartureDate}
|
|
value={newDepartureDate}
|
|
onChange={(e) => setNewDepartureDate(e.target.value)}
|
|
/>
|
|
<Textarea
|
|
label="Reason"
|
|
placeholder="e.g. Locomotive maintenance"
|
|
value={reason}
|
|
onChange={(e) => setReason(e.target.value)}
|
|
/>
|
|
<Group justify="flex-end">
|
|
<Button variant="default" onClick={onClose}>
|
|
Cancel
|
|
</Button>
|
|
<Button loading={loading} onClick={handleSubmit}>
|
|
Reschedule
|
|
</Button>
|
|
</Group>
|
|
</Stack>
|
|
</Modal>
|
|
);
|
|
}
|