This commit is contained in:
Marshal
2026-07-14 13:10:00 +00:00
parent 6d0cf50b4d
commit b5a97d344a
36 changed files with 1101 additions and 355 deletions

View File

@@ -49,6 +49,7 @@ import { api } from "@/services/api";
import { PageContainer } from "@/components/page";
import { PageHeader } from "@/components/page/PageHeader";
import { contractsService } from "@/services/contracts.service";
import { bookingsService } from "@/services/bookings.service";
import {
useContractCapacity,
useContractDetail,
@@ -180,6 +181,9 @@ export default function GlCreateBookingForm() {
}>();
const [searchParams] = useSearchParams();
const requestIdParam = searchParams.get("requestId");
// Rebook: copy an EXPIRED booking's cargo into a fresh booking on the same
// contract (GL only picks a new schedule). Set by the clearance Rebook action.
const copyFromParam = searchParams.get("copyFrom");
const navigate = useNavigate();
const { data: contract, isLoading } = useContractDetail(id);
const mutations = useContractMutations(id ?? "");
@@ -205,6 +209,13 @@ export default function GlCreateBookingForm() {
enabled: Boolean(requestId),
});
// The expired booking a Rebook is copying from (its cargo seeds the form).
const { data: copyFromBooking } = useQuery({
queryKey: ["rebook-copy-from", copyFromParam],
queryFn: () => bookingsService.getById(copyFromParam!),
enabled: Boolean(copyFromParam),
});
// Same window-gating the customer sees: booking is only allowed while a
// window is OPEN for one of the contract's routes. Intercity contracts are
// never window-gated — the shipment rides a passing train staff pick later.
@@ -363,6 +374,28 @@ export default function GlCreateBookingForm() {
if (bookingRequest.notes) setNotes(bookingRequest.notes);
}, [bookingRequest, prefilled]);
// Rebook seed: copy the source booking's container lines once. (Bulk weight /
// item count isn't on the booking payload yet, so bulk rebooks fall through to
// the normal contract seed and GL re-enters the quantity.)
useEffect(() => {
if (!copyFromBooking || prefilled) return;
const lines = copyFromBooking.bookingContainers ?? [];
if (!lines.length) return;
setPrefilled(true);
setContainerLines(
lines.map((c) => {
const qty = Math.max(1, c.quantity);
return {
containerSize: String(c.containerType?.sizeFt ?? ""),
quantity: String(qty),
hazardousQuantity: "0",
reeferQuantity: "0",
units: Array.from({ length: qty }, emptyUnit),
};
}),
);
}, [copyFromBooking, prefilled]);
// Seed one shipment line per contracted size exactly once — same seeding the
// portal form does. Subsequent renders reuse the lines.
useEffect(() => {