diff --git a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx
index 0c96311df..f30e464e7 100644
--- a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx
@@ -186,6 +186,133 @@ const BookingInfo = ({ job }: { job: LastMileJob }) => (
);
+const tripSlipRows = (job: LastMileJob): [string, string][] => [
+ ["Customer", job.customer],
+ ["Service", job.serviceType],
+ ["Origin yard", job.originYard],
+ ["Destination", job.destination],
+ ["Cargo", job.cargo],
+ ["Weight", job.weight],
+ ["Vehicle", job.assignedVehicle ?? "Unassigned"],
+ ["Contact", `${job.contactName} · ${job.contactPhone}`],
+ ["Requested date", job.requestedDate],
+ ["Delivery status", DELIVERY_STATUS_META[job.deliveryStatus].label],
+];
+
+const SignatureBlock = ({ title }: { title: string }) => (
+
+
+ {title}
+
+
+
+ Name:
+
+
+
+
+
+ Signature:
+
+
+
+
+
+ Stamp
+
+
+
+);
+
+const TripSlipDocument = ({ job }: { job: LastMileJob }) => (
+
+
+ EDR Freight
+
+ Last Mile Trip Slip
+
+
+
+
+ {job.bookingRef}
+
+
+ {job.requestedDate}
+
+
+
+
+ {tripSlipRows(job).map(([label, value]) => (
+
+ ))}
+
+
+
+
+
+
+
+);
+
+const escapeHtml = (value: string) =>
+ value
+ .replace(/&/g, "&")
+ .replace(//g, ">");
+
+const buildTripSlipHtml = (job: LastMileJob) => {
+ const rows = tripSlipRows(job)
+ .map(
+ ([label, value]) =>
+ `
| ${escapeHtml(label)} | ${escapeHtml(value)} |
`,
+ )
+ .join("");
+ const signature = (title: string) => `
+
+
${title}
+
Name:
+
Signature:
+
STAMP
+
`;
+ return `
+ Trip Slip ${escapeHtml(job.bookingRef)}
+
+
+ EDR Freight
Last Mile Trip Slip
+ ${escapeHtml(job.bookingRef)}${escapeHtml(job.requestedDate)}
+
+ Acknowledgement
+ ${signature("Driver")}${signature("Operator")}
+ `;
+};
+
const LastMilePage = () => {
const { toast } = useToast();
const { pagination, setPagination } = usePagination({ pageSize: 10 });
@@ -196,6 +323,8 @@ const LastMilePage = () => {
const [assignOpen, setAssignOpen] = useState(false);
const [detailOpen, setDetailOpen] = useState(false);
+ const [tripSlipOpen, setTripSlipOpen] = useState(false);
+ const [tripSlipJob, setTripSlipJob] = useState(null);
const [activeJobId, setActiveJobId] = useState(null);
const [vehicleValue, setVehicleValue] = useState(null);
@@ -315,8 +444,23 @@ const LastMilePage = () => {
};
const handlePrintTripSlip = (job: LastMileJob) => {
- // Placeholder — wire to the trip-slip document service when available.
- toast({ title: "Printing trip slip", description: job.bookingRef });
+ setTripSlipJob(job);
+ setTripSlipOpen(true);
+ };
+
+ const printTripSlip = () => {
+ if (!tripSlipJob) return;
+ const win = window.open("", "_blank", "width=820,height=920");
+ if (!win) {
+ toast({
+ title: "Pop-up blocked",
+ description: "Allow pop-ups to print the trip slip.",
+ variant: "destructive",
+ });
+ return;
+ }
+ win.document.write(buildTripSlipHtml(tripSlipJob));
+ win.document.close();
};
const columns = useMemo((): ColumnDef[] => {
@@ -582,6 +726,28 @@ const LastMilePage = () => {
+
+ setTripSlipOpen(false)}
+ title={Trip Slip}
+ size="lg"
+ radius="lg"
+ centered
+ >
+
+ {tripSlipJob && }
+
+
+
+ } onClick={printTripSlip}>
+ Print
+
+
+
+
);
};