Merge branch 'dev' into freight/nati-2

This commit is contained in:
Nathnael
2026-08-13 11:34:57 +00:00
47 changed files with 1441 additions and 72 deletions

View File

@@ -1,7 +1,10 @@
import type { ReactNode } from "react";
import { Truck } from "lucide-react";
import { SimpleGrid, Stack } from "@mantine/core";
import { Download, Truck } from "lucide-react";
import { Button, Group, SimpleGrid, Stack, Text } from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { lastMileRequestsService } from "@/services/last-mile-requests.service";
import type { BookingDetail } from "@/types/booking";
import { SectionCard } from "./SectionCard";
@@ -16,18 +19,44 @@ export interface BookingMileServicesCardProps {
handoverSection?: ReactNode;
}
/** First / last mile addresses, plus the export handover control. Renders
* nothing when none of the three are present. */
/**
* First / last mile addresses, plus the export handover control and the
* stored last-mile contract reference (signed status + PDF download) for
* Truck & Machinery once a request on this booking is approved. Renders
* nothing when none of the three are present.
*/
export function BookingMileServicesCard({
booking,
handoverSection,
}: BookingMileServicesCardProps) {
const hasAddresses =
Boolean(booking.firstMilePickupAddress) || Boolean(booking.lastMileDeliveryAddress);
const { data: requestsResponse } = useQuery({
queryKey: QUERY_KEYS.LAST_MILE_REQUESTS.list({ bookingId: booking.id }),
queryFn: async () =>
(await lastMileRequestsService.list({ bookingId: booking.id })).data,
enabled: Boolean(booking.lastMileDeliveryAddress),
});
const approvedRequest = (requestsResponse?.data ?? []).find(
(r) => r.status === "APPROVED",
);
if (!hasAddresses && !handoverSection) {
return null;
}
const downloadContract = async () => {
if (!approvedRequest) return;
const blob = (await lastMileRequestsService.contractDocument(approvedRequest.id)).data;
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `last-mile-contract-${booking.reference ?? booking.id}.pdf`;
a.click();
URL.revokeObjectURL(url);
};
return (
<SectionCard icon={Truck} title="Mile services" accent="grape">
<Stack gap="md">
@@ -41,6 +70,32 @@ export function BookingMileServicesCard({
)}
</SimpleGrid>
)}
{approvedRequest && (
<Group justify="space-between" align="center" wrap="wrap">
<Stack gap={0}>
<Text size="sm" fw={600}>
Last-mile contract
</Text>
<Text size="xs" c={approvedRequest.customerSignedAt ? "green.8" : "orange.8"}>
{approvedRequest.customerSignedAt
? `Signed ${new Date(approvedRequest.customerSignedAt).toLocaleDateString()}${
approvedRequest.signerDisplayName
? ` by ${approvedRequest.signerDisplayName}`
: ""
}`
: "Awaiting customer signature"}
</Text>
</Stack>
<Button
size="xs"
variant="light"
leftSection={<Download size={14} />}
onClick={() => void downloadContract()}
>
Download PDF
</Button>
</Group>
)}
{handoverSection}
</Stack>
</SectionCard>