"use client"; import { useState } from "react"; import Link from "next/link"; import StatusBadge from "./StatusBadge"; import { HaulingLot, updateHarvestLotStatus } from "@/actions/route-trace/lots"; // One-color outline icons matching the design system const Icons = { clipboard: (className: string) => ( ), search: (className: string) => ( ), plus: (className: string) => ( ), truck: (className: string) => ( ), package: (className: string) => ( ), printer: (className: string) => ( ), file: (className: string) => ( ), camera: (className: string) => ( ), }; const STATUS_FILTERS = [ { value: "", label: "All" }, { value: "active", label: "Active" }, { value: "in_transit", label: "In Transit" }, { value: "at_shed", label: "At Shed" }, { value: "packed", label: "Packed" }, { value: "delivered", label: "Delivered" }, ]; function getAgeStatus(harvestDate: string): { label: string; className: string; days: number } | null { const harvested = new Date(harvestDate + "T00:00:00"); const now = new Date(); const days = Math.floor((now.getTime() - harvested.getTime()) / (1000 * 60 * 60 * 24)); if (days < 0) return null; if (days <= 3) return { label: `${days}d`, className: "bg-green-100 text-green-700", days }; if (days <= 7) return { label: `${days}d`, className: "bg-amber-100 text-amber-700", days }; if (days <= 14) return { label: `${days}d`, className: "bg-orange-100 text-orange-700", days }; return { label: `${days}d`, className: "bg-red-100 text-red-700", days }; } export default function LotListTable({ initialLots, brandId, onCreateNew, }: { initialLots: HaulingLot[]; brandId: string; onCreateNew?: () => void; }) { const [filter, setFilter] = useState(""); const [query, setQuery] = useState(""); const [selected, setSelected] = useState>(new Set()); const [showBulk, setShowBulk] = useState(false); const filtered = initialLots.filter((lot) => { if (filter && lot.status !== filter) return false; if (query) { const q = query.toLowerCase(); if ( !lot.lot_number.toLowerCase().includes(q) && !lot.crop_type.toLowerCase().includes(q) && !(lot.field_location ?? "").toLowerCase().includes(q) && !(lot.bin_id ?? "").toLowerCase().includes(q) ) return false; } return true; }); function toggleSelect(id: string) { setSelected((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); } function toggleSelectAll() { if (selected.size === filtered.length) { setSelected(new Set()); } else { setSelected(new Set(filtered.map((l) => l.lot_id))); } } async function handleBulkStickers(type: "field" | "shed") { if (selected.size === 0) return; const ids = [...selected]; for (const id of ids) { window.open(`/api/route-trace/sticker-pdf?lotId=${id}&type=${type}&size=4x2&copies=1`, "_blank"); } } function handleBulkExport() { if (selected.size === 0) return; const ids = [...selected]; ids.forEach((id) => { window.location.href = `/api/route-trace/trace-report?lotId=${id}&format=csv`; }); } function handleBulkMarkUsed() { if (selected.size === 0) return; const ids = [...selected]; if (ids.length === 1) { window.location.href = `/admin/route-trace/lots/${ids[0]}`; } else { window.location.href = `/admin/route-trace/lots?bulk_mark=${ids.join(",")}`; } } async function handleBulkMarkLoaded() { if (selected.size === 0) return; const ids = [...selected]; await Promise.all( ids.map(async (id) => { try { await updateHarvestLotStatus(id, "in_transit"); } catch (err) { // A single failure must not block other lots from being marked. console.warn("[bulk-mark-loaded] updateHarvestLotStatus failed for", id, err); } }) ); window.location.reload(); } return (
{/* Search and filters */}
{Icons.clipboard("w-5 h-5 text-[var(--admin-accent)]")}

All Lots

{filtered.length} lot{filtered.length !== 1 ? "s" : ""}

{/* Filter bar */}
{STATUS_FILTERS.map((f) => ( ))}
{/* Search */}
{Icons.search("h-4 w-4")} setQuery(e.target.value)} className="w-full rounded-xl border border-stone-200 bg-stone-50 pl-9 pr-4 py-3 text-base outline-none focus:border-emerald-600 focus:bg-white transition-colors" />
{/* Bulk action bar */} {selected.size > 0 && (
{selected.size} lot{selected.size !== 1 ? "s" : ""} selected
)} {/* Table */} {filtered.length === 0 ? (
{Icons.search("h-10 w-10")}

No lots found

) : (
{showBulk && ( )} {["Lot #", "Crop / Variety", "Harvest Date", "Age", "Field", "Bins", "Qty", "Status"].map((h) => ( ))} {filtered.map((lot) => ( {showBulk && ( )} ))}
0} onChange={toggleSelectAll} className="h-4 w-4 rounded border-stone-300" /> {h}
toggleSelect(lot.lot_id)} className="h-4 w-4 rounded border-stone-300" /> {lot.lot_number}
{lot.crop_type}
{(() => { const age = getAgeStatus(lot.harvest_date); return age ? ( {age.label} ) : ( ); })()}
{lot.field_location ?? "—"}
{lot.field_block &&
Block: {lot.field_block}
}
{lot.bin_id && ( {lot.bin_id} )} {lot.pallets != null && ( {lot.pallets} PLT )} {!lot.bin_id && lot.pallets == null && }
{lot.quantity_lbs != null ? `${lot.quantity_lbs.toLocaleString()} ${lot.yield_unit ?? "lbs"}` : "—"} View →
)}
); }