projects
This commit is contained in:
@@ -5,6 +5,7 @@ import { Link, useParams } from "react-router-dom";
|
||||
|
||||
import { useAuth } from "../../auth/AuthProvider";
|
||||
import { api, ApiError } from "../../lib/api";
|
||||
import { FileAttachmentsPanel } from "../../components/FileAttachmentsPanel";
|
||||
import { shipmentStatusOptions } from "./config";
|
||||
import { ShipmentStatusBadge } from "./ShipmentStatusBadge";
|
||||
|
||||
@@ -15,7 +16,7 @@ export function ShipmentDetailPage() {
|
||||
const [relatedShipments, setRelatedShipments] = useState<ShipmentSummaryDto[]>([]);
|
||||
const [status, setStatus] = useState("Loading shipment...");
|
||||
const [isUpdatingStatus, setIsUpdatingStatus] = useState(false);
|
||||
const [isRenderingPdf, setIsRenderingPdf] = useState(false);
|
||||
const [activeDocumentAction, setActiveDocumentAction] = useState<"packing-slip" | "label" | "bol" | null>(null);
|
||||
|
||||
const canManage = user?.permissions.includes(permissions.shippingWrite) ?? false;
|
||||
|
||||
@@ -56,24 +57,48 @@ export function ShipmentDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleOpenPackingSlip() {
|
||||
async function handleOpenDocument(kind: "packing-slip" | "label" | "bol") {
|
||||
if (!token || !shipment) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsRenderingPdf(true);
|
||||
setStatus("Rendering packing slip PDF...");
|
||||
setActiveDocumentAction(kind);
|
||||
setStatus(
|
||||
kind === "packing-slip"
|
||||
? "Rendering packing slip PDF..."
|
||||
: kind === "label"
|
||||
? "Rendering shipping label PDF..."
|
||||
: "Rendering bill of lading PDF..."
|
||||
);
|
||||
try {
|
||||
const blob = await api.getShipmentPackingSlipPdf(token, shipment.id);
|
||||
const blob =
|
||||
kind === "packing-slip"
|
||||
? await api.getShipmentPackingSlipPdf(token, shipment.id)
|
||||
: kind === "label"
|
||||
? await api.getShipmentLabelPdf(token, shipment.id)
|
||||
: await api.getShipmentBillOfLadingPdf(token, shipment.id);
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
window.open(objectUrl, "_blank", "noopener,noreferrer");
|
||||
window.setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);
|
||||
setStatus("Packing slip PDF rendered.");
|
||||
setStatus(
|
||||
kind === "packing-slip"
|
||||
? "Packing slip PDF rendered."
|
||||
: kind === "label"
|
||||
? "Shipping label PDF rendered."
|
||||
: "Bill of lading PDF rendered."
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof ApiError ? error.message : "Unable to render packing slip PDF.";
|
||||
const message =
|
||||
error instanceof ApiError
|
||||
? error.message
|
||||
: kind === "packing-slip"
|
||||
? "Unable to render packing slip PDF."
|
||||
: kind === "label"
|
||||
? "Unable to render shipping label PDF."
|
||||
: "Unable to render bill of lading PDF.";
|
||||
setStatus(message);
|
||||
} finally {
|
||||
setIsRenderingPdf(false);
|
||||
setActiveDocumentAction(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +119,14 @@ export function ShipmentDetailPage() {
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<Link to="/shipping/shipments" className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text">Back to shipments</Link>
|
||||
<Link to={`/sales/orders/${shipment.salesOrderId}`} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text">Open sales order</Link>
|
||||
<button type="button" onClick={handleOpenPackingSlip} disabled={isRenderingPdf} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text disabled:cursor-not-allowed disabled:opacity-60">
|
||||
{isRenderingPdf ? "Rendering PDF..." : "Open packing slip"}
|
||||
<button type="button" onClick={() => handleOpenDocument("packing-slip")} disabled={activeDocumentAction !== null} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text disabled:cursor-not-allowed disabled:opacity-60">
|
||||
{activeDocumentAction === "packing-slip" ? "Rendering PDF..." : "Open packing slip"}
|
||||
</button>
|
||||
<button type="button" onClick={() => handleOpenDocument("label")} disabled={activeDocumentAction !== null} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text disabled:cursor-not-allowed disabled:opacity-60">
|
||||
{activeDocumentAction === "label" ? "Rendering PDF..." : "Open shipping label"}
|
||||
</button>
|
||||
<button type="button" onClick={() => handleOpenDocument("bol")} disabled={activeDocumentAction !== null} className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text disabled:cursor-not-allowed disabled:opacity-60">
|
||||
{activeDocumentAction === "bol" ? "Rendering PDF..." : "Open bill of lading"}
|
||||
</button>
|
||||
{canManage ? (
|
||||
<Link to={`/shipping/shipments/${shipment.id}/edit`} className="inline-flex items-center justify-center rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white">Edit shipment</Link>
|
||||
@@ -168,6 +199,14 @@ export function ShipmentDetailPage() {
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
<FileAttachmentsPanel
|
||||
ownerType="SHIPMENT"
|
||||
ownerId={shipment.id}
|
||||
eyebrow="Logistics Attachments"
|
||||
title="Shipment files"
|
||||
description="Store carrier paperwork, signed delivery records, bills of lading, and related logistics support files on the shipment record."
|
||||
emptyMessage="No logistics attachments have been uploaded for this shipment yet."
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user