mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 01:55:41 +00:00
add script to seed freight contracts across flow variants
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
Button,
|
||||
Group,
|
||||
Modal,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
ThemeIcon,
|
||||
} from "@mantine/core";
|
||||
import { isAxiosError } from "axios";
|
||||
import { CalendarClock, Info } from "lucide-react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
import { api } from "@/services/api";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
|
||||
function parseError(error: unknown, fallback: string): string {
|
||||
if (isAxiosError(error)) {
|
||||
const message = error.response?.data?.message;
|
||||
if (Array.isArray(message)) return message.join(", ");
|
||||
if (typeof message === "string") return message;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/** ISO → the `YYYY-MM-DDTHH:mm` value a datetime-local input expects (local time). */
|
||||
function toLocalInputValue(iso: string | null | undefined): string {
|
||||
if (!iso) return "";
|
||||
const date = new Date(iso);
|
||||
if (Number.isNaN(date.getTime())) return "";
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
return (
|
||||
`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` +
|
||||
`T${pad(date.getHours())}:${pad(date.getMinutes())}`
|
||||
);
|
||||
}
|
||||
|
||||
export interface EditScheduleDateModalProps {
|
||||
scheduleId: string | null;
|
||||
currentDate: string | null;
|
||||
routeName?: string | null;
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
/** Called after a successful save (e.g. to refetch a list). */
|
||||
onSaved?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reschedule a train's departure date. Only shown for schedules whose booking
|
||||
* window has not opened yet; the API rejects a date inside the booking lead
|
||||
* window (import/intercity lead in days, export in hours).
|
||||
*/
|
||||
export default function EditScheduleDateModal({
|
||||
scheduleId,
|
||||
currentDate,
|
||||
routeName,
|
||||
opened,
|
||||
onClose,
|
||||
onSaved,
|
||||
}: EditScheduleDateModalProps) {
|
||||
const { toast } = useToast();
|
||||
const save = useMutation(
|
||||
api.trainScheduling.updateScheduleDate.mutationOptions(),
|
||||
);
|
||||
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (opened) setValue(toLocalInputValue(currentDate));
|
||||
}, [opened, currentDate]);
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!scheduleId || !value) {
|
||||
toast({ title: "Pick a departure date", variant: "destructive" });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await save.mutateAsync({
|
||||
id: scheduleId,
|
||||
scheduleDate: new Date(value).toISOString(),
|
||||
});
|
||||
toast({ title: "Departure date updated" });
|
||||
onSaved?.();
|
||||
onClose();
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: "Update failed",
|
||||
description: parseError(err, "Could not update departure date"),
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
opened={opened}
|
||||
onClose={onClose}
|
||||
centered
|
||||
radius="lg"
|
||||
title={
|
||||
<Group gap="sm">
|
||||
<ThemeIcon variant="light" color="edr-green" radius="md" size={34}>
|
||||
<CalendarClock size={18} />
|
||||
</ThemeIcon>
|
||||
<Box>
|
||||
<Text fw={600} lh={1.2}>
|
||||
Edit departure date
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed" lh={1.2}>
|
||||
{routeName ?? "This schedule only"}
|
||||
</Text>
|
||||
</Box>
|
||||
</Group>
|
||||
}
|
||||
>
|
||||
<Stack gap="md">
|
||||
<Alert variant="light" color="blue" icon={<Info size={16} />}>
|
||||
The date can only be changed before the booking window opens, and must
|
||||
still leave room for the booking lead window before departure.
|
||||
</Alert>
|
||||
<TextInput
|
||||
label="Departure date"
|
||||
type="datetime-local"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.currentTarget.value)}
|
||||
/>
|
||||
<Group justify="flex-end" mt="xs">
|
||||
<Button variant="default" onClick={onClose} disabled={save.isPending}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleSave} loading={save.isPending}>
|
||||
Save
|
||||
</Button>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user