add bookings management and settings

This commit is contained in:
Marshal
2026-07-05 10:22:58 +00:00
parent dfdf7a025d
commit 3447394e32
13 changed files with 1617 additions and 9 deletions

View File

@@ -20,6 +20,7 @@ import {
ArrowLeft,
CalendarClock,
CheckCircle2,
Clock,
Container as ContainerIcon,
Eye,
FileText,
@@ -47,7 +48,8 @@ import { ContainerPlacementGrid } from "@/components/trainScheduling/ContainerPl
import { FleetAvailabilitySummary } from "@/components/trainScheduling/FleetAvailabilitySummary";
import { ImportLoadingConfirmationPanel } from "@/components/trainScheduling/ImportLoadingConfirmationPanel";
import { RescheduleTrainDialog } from "@/components/trainScheduling/RescheduleTrainDialog";
import { ScheduleBatchPanel } from "@/components/trainScheduling/ScheduleBatchPanel";
import BookingWindowSettingsModal from "@/components/trainScheduling/BookingWindowSettingsModal";
// import { ScheduleBatchPanel } from "@/components/trainScheduling/ScheduleBatchPanel";
import { ScheduleBookingsStep } from "@/components/trainScheduling/ScheduleBookingsStep";
import { ScheduleWorkspacePanel } from "@/components/trainScheduling/ScheduleWorkspacePanel";
import { FreightTypeBadge } from "@/components/trainScheduling/ScheduleStatusBadge";
@@ -95,6 +97,7 @@ export default function TrainScheduleV2DetailPage() {
const [previewResult, setPreviewResult] = useState<TrainSchedulePreviewResponse | null>(null);
const [containerPlacements, setContainerPlacements] = useState<ContainerPlacement[]>([]);
const [maintenanceOpen, setMaintenanceOpen] = useState(false);
const [windowSettingsOpen, setWindowSettingsOpen] = useState(false);
const [gatepassSecuredAt, setGatepassSecuredAt] = useState("");
const [gatepassReference, setGatepassReference] = useState("");
const [gatepassFileUrl, setGatepassFileUrl] = useState("");
@@ -886,6 +889,18 @@ export default function TrainScheduleV2DetailPage() {
Track train
</Button>
) : null}
{schedule.windowPhase === "PRE_WINDOW" ? (
<Button
variant="light"
color="edr-green"
radius="lg"
size="sm"
leftSection={<Clock size={16} />}
onClick={() => setWindowSettingsOpen(true)}
>
Window settings
</Button>
) : null}
{["DRAFT", "SCHEDULED"].includes(schedule.status) ? (
<Button
variant="default"
@@ -1126,7 +1141,7 @@ export default function TrainScheduleV2DetailPage() {
</Stack>
</Paper>
<ScheduleBatchPanel schedule={schedule} />
{/* <ScheduleBatchPanel schedule={schedule} /> */}
</Stack>
</Tabs.Panel>
@@ -1150,6 +1165,13 @@ export default function TrainScheduleV2DetailPage() {
onComplete={() => void detailQuery.refetch()}
/>
) : null}
<BookingWindowSettingsModal
scheduleId={scheduleId ?? null}
opened={windowSettingsOpen}
onClose={() => setWindowSettingsOpen(false)}
onSaved={() => void detailQuery.refetch()}
/>
</PageContainer>
);
}

View File

@@ -20,6 +20,7 @@ import {
ArrowRight,
Ban,
CalendarClock,
Clock,
Eye,
MoreHorizontal,
Navigation,
@@ -36,6 +37,7 @@ import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import RuleEngineListFooter from "@/components/ruleEngine/RuleEngineListFooter";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { FreightTypeBadge } from "@/components/trainScheduling/ScheduleStatusBadge";
import BookingWindowSettingsModal from "@/components/trainScheduling/BookingWindowSettingsModal";
import {
locomotiveOption,
showScheduleWarnings,
@@ -86,6 +88,7 @@ export default function TrainScheduleV2ListPage() {
const [statusFilter, setStatusFilter] = useState("ALL");
const [freightFilter, setFreightFilter] = useState("ALL");
const [createOpen, setCreateOpen] = useState(false);
const [windowSettingsId, setWindowSettingsId] = useState<string | null>(null);
const [routeId, setRouteId] = useState("");
const [scheduleDate, setScheduleDate] = useState("");
const [locomotiveIds, setLocomotiveIds] = useState<string[]>([]);
@@ -315,6 +318,14 @@ export default function TrainScheduleV2ListPage() {
Track
</Menu.Item>
) : null}
{["DRAFT", "SCHEDULED"].includes(schedule.status) ? (
<Menu.Item
leftSection={<Clock size={15} />}
onClick={() => setWindowSettingsId(schedule.id)}
>
Booking window settings
</Menu.Item>
) : null}
{["DRAFT", "SCHEDULED"].includes(schedule.status) ? (
<Menu.Item
color="red"
@@ -583,6 +594,13 @@ export default function TrainScheduleV2ListPage() {
</Group>
</Stack>
</Modal>
<BookingWindowSettingsModal
scheduleId={windowSettingsId}
opened={windowSettingsId != null}
onClose={() => setWindowSettingsId(null)}
onSaved={() => void schedulesQuery.refetch()}
/>
</PageContainer>
);
}

View File

@@ -58,6 +58,7 @@ export default function TrainSchedulingGlobalRulesPage() {
"importWindowLeadDays",
"exportBookingLeadHours",
"windowOpenHour",
"windowCloseHour",
"windowDurationHours",
"docReviewMinutes",
"paymentWindowMinutes",
@@ -196,7 +197,7 @@ export default function TrainSchedulingGlobalRulesPage() {
/>
<NumberInput
label="Window open hour (EAT)"
description="Local hour the import window opens on its booking day (e.g. 8 = 08:00)"
description="Local hour the booking desk opens each day (e.g. 8 = 08:00)"
value={form.windowOpenHour ?? ""}
onChange={(value) =>
setForm((current) => ({ ...current, windowOpenHour: value }))
@@ -207,6 +208,19 @@ export default function TrainSchedulingGlobalRulesPage() {
max={23}
disabled={loading}
/>
<NumberInput
label="Window close hour (EAT)"
description="Local hour the booking desk shuts each day; a not-yet-full window resumes next morning at the open hour. Set equal to the open hour for a 24-hour desk."
value={form.windowCloseHour ?? ""}
onChange={(value) =>
setForm((current) => ({ ...current, windowCloseHour: value }))
}
clampBehavior="none"
allowDecimal
min={0}
max={23}
disabled={loading}
/>
<DurationField
label="Window duration"
description="How long the import booking window stays open"