This commit is contained in:
2026-03-14 23:50:41 -05:00
parent 7b85d14ff6
commit 5f93adab8b
4 changed files with 254 additions and 0 deletions

View File

@@ -464,6 +464,19 @@ export const api = {
token
);
},
async getShipmentPackingSlipPdf(token: string, shipmentId: string) {
const response = await fetch(`/api/v1/documents/shipping/shipments/${shipmentId}/packing-slip.pdf`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new ApiError("Unable to render packing slip PDF.", "PACKING_SLIP_FAILED");
}
return response.blob();
},
async getCompanyProfilePreviewPdf(token: string) {
const response = await fetch("/api/v1/documents/company-profile-preview.pdf", {
headers: {

View File

@@ -15,6 +15,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 canManage = user?.permissions.includes(permissions.shippingWrite) ?? false;
@@ -55,6 +56,27 @@ export function ShipmentDetailPage() {
}
}
async function handleOpenPackingSlip() {
if (!token || !shipment) {
return;
}
setIsRenderingPdf(true);
setStatus("Rendering packing slip PDF...");
try {
const blob = await api.getShipmentPackingSlipPdf(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.");
} catch (error: unknown) {
const message = error instanceof ApiError ? error.message : "Unable to render packing slip PDF.";
setStatus(message);
} finally {
setIsRenderingPdf(false);
}
}
if (!shipment) {
return <div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">{status}</div>;
}
@@ -72,6 +94,9 @@ 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>
{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>
) : null}