"use client"; import { useState, useEffect } from "react"; import { LotDetail } from "@/actions/route-trace/lots"; type StickerType = "field" | "shed"; type StickerSize = "4x2" | "4x3"; const COPY_OPTIONS = [1, 2, 3, 5, 10]; export default function StickerPreviewModal({ lot, onClose }: { lot: LotDetail; onClose: () => void }) { const [stickerType, setStickerType] = useState("field"); const [stickerSize, setStickerSize] = useState("4x2"); const [copies, setCopies] = useState(1); const [loading, setLoading] = useState(false); const [qrDataUrl, setQrDataUrl] = useState(null); const baseUrl = typeof window !== "undefined" ? window.location.origin : "http://localhost:3000"; const traceUrl = `${baseUrl}/trace/${lot.lot_number}`; useEffect(() => { import("qrcode").then(({ toDataURL }) => { toDataURL(traceUrl, { width: 200, margin: 1, color: { dark: "#000000", light: "#FFFFFF" } }) .then(setQrDataUrl) .catch(() => {}); }); }, [traceUrl]); async function handlePrint() { setLoading(true); try { const url = `/api/route-trace/sticker-pdf?lotId=${lot.lot_id}&type=${stickerType}&size=${stickerSize}&copies=${copies}`; const res = await fetch(url); if (!res.ok) throw new Error("Failed to generate PDF"); const blob = await res.blob(); const blobUrl = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = blobUrl; a.download = `${lot.lot_number}-${stickerType}-${stickerSize}.pdf`; a.target = "_blank"; a.click(); URL.revokeObjectURL(blobUrl); } catch (e) { alert("Failed to generate PDF. Please try again."); } finally { setLoading(false); } } // Actual thermal label dimensions in points: 4x2" = 288×144, 4x3" = 288×216 const LABEL_W = 288; const LABEL_H = stickerSize === "4x3" ? 216 : 144; // Scale preview to ~1.8x so it's readable in the modal const scale = 1.8; const previewW = LABEL_W * scale; const previewH = LABEL_H * scale; const qrSize = stickerSize === "4x3" ? 130 : 110; const qrPreviewSize = qrSize * scale * 0.55; // scaled down for preview return (
e.stopPropagation()}>

🖨 Print Sticker

{lot.lot_number} · {lot.crop_type}

{/* Type + Size selectors */}

Sticker Type

{(["field", "shed"] as StickerType[]).map((t) => { const label = t === "field" ? "🌱 Field" : "🏭 Shed"; const desc = t === "field" ? "After harvest" : "At shed arrival"; return ( ); })}

Label Size

{(["4x2", "4x3"] as StickerSize[]).map((s) => { const w = s === "4x2" ? "2 in" : "3 in"; const h = s === "4x2" ? "2 in" : "3 in"; return ( ); })}

Copies

{COPY_OPTIONS.map((n) => ( ))}

labels per sheet

{/* Sticker preview — actual proportions, scaled */}

Preview

{/* Brand row */}
Route Trace {stickerSize}"
{/* Lot number — dominant */}
{lot.lot_number}
{/* Crop */}
{lot.crop_type}
{/* Data rows */}
{stickerType === "field" ? ( <> {lot.harvest_date &&
Harvested: {lot.harvest_date}
} {lot.quantity_lbs && (
{Number(lot.quantity_lbs).toLocaleString()} lbs
)} {lot.field_location &&
{lot.field_location}
} {lot.field_block &&
Block: {lot.field_block}
} {lot.worker_name &&
{lot.worker_name}
} {lot.yield_estimate_lbs && (
Est: {Number(lot.yield_estimate_lbs).toLocaleString()} {lot.yield_unit ?? "lbs"}
)} ) : ( <> {lot.quantity_lbs && (
{Number(lot.quantity_lbs).toLocaleString()} {lot.yield_unit ?? "lbs"}
)} {lot.harvest_date &&
Packed: {lot.harvest_date}
} {lot.field_location &&
From: {lot.field_location}
} {lot.worker_name &&
{lot.worker_name}
} {lot.destination_stop_id && (
Dest: #{lot.destination_stop_id.slice(0, 8)}
)} )}
{/* Right — bin/container */}
{lot.bin_id && (
BIN {lot.bin_id}
)} {lot.container_id && (
CONT {lot.container_id}
)} {lot.pallets && (
{lot.pallets} PLT
)} {lot.field_block && stickerType === "shed" && (
Block: {lot.field_block}
)}
{/* QR — bottom right */}
{qrDataUrl ? ( QR ) : (
QR
)}
{/* /trace url — bottom left */}
/trace/{lot.lot_number}
{/* Print specs */}

Direct Thermal · {stickerSize}" · Black on White · Large QR

Helvetica Bold · High-contrast QR · No margins · 2 per sheet

{lot.lot_number}

2 per sheet

); }