fix: react-doctor unused-file 123→27 (-96 dead files removed)
This commit is contained in:
@@ -1,310 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useTransition } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { createHarvestLot } from "@/actions/route-trace/lots";
|
||||
|
||||
// One-color outline icons
|
||||
const Icons = {
|
||||
plant: (className: string) => (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M12 22V12M12 12C12 12 7 10 7 5c0-2.5 2.5-5 5-5s5 2.5 5 5c0 5-5 7-5 7z" />
|
||||
</svg>
|
||||
),
|
||||
chevronUp: (className: string) => (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="m18 15-6-6-6 6"/>
|
||||
</svg>
|
||||
),
|
||||
chevronDown: (className: string) => (
|
||||
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="m6 9 6 6 6-6"/>
|
||||
</svg>
|
||||
),
|
||||
};
|
||||
|
||||
export default function LotCreateForm({ brandId }: { brandId: string }) {
|
||||
const router = useRouter();
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [notesOpen, setNotesOpen] = useState(false);
|
||||
|
||||
const [crop_type, setCropType] = useState("");
|
||||
const [variety, setVariety] = useState("");
|
||||
const [harvest_date, setHarvestDate] = useState(new Date().toISOString().split("T")[0]);
|
||||
const [field_location, setFieldLocation] = useState("");
|
||||
const [field_block, setFieldBlock] = useState("");
|
||||
const [worker_name, setWorkerName] = useState("");
|
||||
const [packer_name, setPackerName] = useState("");
|
||||
const [quantity_lbs, setQuantityLbs] = useState("");
|
||||
const [yield_estimate_lbs, setYieldEstimateLbs] = useState("");
|
||||
const [yield_unit, setYieldUnit] = useState("lbs");
|
||||
const [customYieldUnit, setCustomYieldUnit] = useState("");
|
||||
const [bin_id, setBinId] = useState("");
|
||||
const [container_id, setContainerId] = useState("");
|
||||
const [pallets, setPallets] = useState("");
|
||||
const [notes, setNotes] = useState("");
|
||||
|
||||
function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
startTransition(async () => {
|
||||
const result = await createHarvestLot(brandId, {
|
||||
crop_type,
|
||||
variety: variety || undefined,
|
||||
harvest_date,
|
||||
field_location: field_location || undefined,
|
||||
worker_name: worker_name || undefined,
|
||||
packer_name: packer_name || undefined,
|
||||
quantity_lbs: quantity_lbs ? Number(quantity_lbs) : undefined,
|
||||
notes: notes || undefined,
|
||||
bin_id: bin_id || undefined,
|
||||
container_id: container_id || undefined,
|
||||
field_block: field_block || undefined,
|
||||
yield_estimate_lbs: yield_estimate_lbs ? Number(yield_estimate_lbs) : undefined,
|
||||
yield_unit: yield_unit === "custom" ? customYieldUnit.trim() || undefined : yield_unit,
|
||||
pallets: pallets ? Number(pallets) : undefined,
|
||||
});
|
||||
if (result.success && result.lot) {
|
||||
router.push(`/admin/route-trace/lots/${result.lot.id}`);
|
||||
} else {
|
||||
setError(result.error ?? "Failed to create lot");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border border-stone-200 bg-white shadow-sm">
|
||||
<div className="border-b border-stone-100 px-6 py-5">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex h-9 w-9 items-center justify-center rounded-xl bg-green-100">
|
||||
<span className="text-green-600">{Icons.plant("h-5 w-5")}</span>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-stone-900">New Harvest Lot</h2>
|
||||
<p className="text-sm text-stone-500">Quick entry — scan or fill in the fields below</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit} className="p-6 space-y-5">
|
||||
{error && (
|
||||
<div className="rounded-xl bg-red-50 border border-red-200 p-4 text-sm text-red-700">{error}</div>
|
||||
)}
|
||||
|
||||
{/* Required — large touch targets for field use */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label htmlFor="fld-1-crop-type" className="block text-sm font-semibold text-stone-800 mb-2">Crop Type *</label>
|
||||
<input id="fld-1-crop-type" aria-label=". Sweet Corn"
|
||||
type="text"
|
||||
value={crop_type}
|
||||
onChange={(e) => setCropType(e.target.value)}
|
||||
placeholder="e.g. Sweet Corn"
|
||||
required
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-4 py-4 text-lg font-medium outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="fld-2-variety" className="block text-sm font-semibold text-stone-800 mb-2">Variety</label>
|
||||
<input id="fld-2-variety" aria-label=". Golden Bantam"
|
||||
type="text"
|
||||
value={variety}
|
||||
onChange={(e) => setVariety(e.target.value)}
|
||||
placeholder="e.g. Golden Bantam"
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-4 py-4 text-lg font-medium outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="fld-3-harvest-date" className="block text-sm font-semibold text-stone-800 mb-2">Harvest Date *</label>
|
||||
<input id="fld-3-harvest-date" aria-label="Date"
|
||||
type="date"
|
||||
value={harvest_date}
|
||||
onChange={(e) => setHarvestDate(e.target.value)}
|
||||
required
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-4 py-4 text-lg font-medium outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Field & Location */}
|
||||
<div className="border-t border-stone-100 pt-5">
|
||||
<p className="text-xs font-semibold uppercase tracking-wider text-stone-400 mb-3">Field & Location</p>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<label htmlFor="fld-4-field-location" className="block text-xs font-medium text-stone-600 mb-1.5">Field / Location *</label>
|
||||
<input id="fld-4-field-location" aria-label=". North Field"
|
||||
type="text"
|
||||
value={field_location}
|
||||
onChange={(e) => setFieldLocation(e.target.value)}
|
||||
placeholder="e.g. North Field"
|
||||
required
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-4 py-3.5 text-base outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label htmlFor="fld-5-field-block" className="block text-xs font-medium text-stone-600 mb-1.5">Field Block</label>
|
||||
<input id="fld-5-field-block" aria-label=". Block A"
|
||||
type="text"
|
||||
value={field_block}
|
||||
onChange={(e) => setFieldBlock(e.target.value)}
|
||||
placeholder="e.g. Block A"
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="fld-6-worker-harvest-lead" className="block text-xs font-medium text-stone-600 mb-1.5">Worker / Harvest Lead</label>
|
||||
<input id="fld-6-worker-harvest-lead" aria-label=". Maria S."
|
||||
type="text"
|
||||
value={worker_name}
|
||||
onChange={(e) => setWorkerName(e.target.value)}
|
||||
placeholder="e.g. Maria S."
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quantity + Yield */}
|
||||
<div className="border-t border-stone-100 pt-5">
|
||||
<p className="text-xs font-semibold uppercase tracking-wider text-stone-400 mb-3">Weight & Yield</p>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label htmlFor="fld-7-actual-qty" className="block text-xs font-medium text-stone-600 mb-1.5">Actual Qty</label>
|
||||
<input id="fld-7-actual-qty" aria-label=". 4800"
|
||||
type="number"
|
||||
value={quantity_lbs}
|
||||
onChange={(e) => setQuantityLbs(e.target.value)}
|
||||
placeholder="e.g. 4800"
|
||||
min="0"
|
||||
step="0.01"
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3.5 text-base outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-stone-600 mb-1.5" htmlFor="fld-yield-est">Yield Est.</label>
|
||||
<div className="flex rounded-xl border border-stone-200 bg-stone-50 overflow-hidden focus-within:border-emerald-600 focus-within:bg-white transition-colors">
|
||||
<input id="fld-yield-est" aria-label=". 5000"
|
||||
type="number"
|
||||
value={yield_estimate_lbs}
|
||||
onChange={(e) => setYieldEstimateLbs(e.target.value)}
|
||||
placeholder="e.g. 5000"
|
||||
min="0"
|
||||
step="0.01"
|
||||
className="flex-1 px-3 py-3.5 text-base outline-none bg-transparent"
|
||||
/>
|
||||
<select aria-label="Select"
|
||||
value={yield_unit}
|
||||
onChange={(e) => setYieldUnit(e.target.value)}
|
||||
className="px-2 py-3.5 text-sm font-semibold text-stone-600 bg-stone-100 outline-none border-l border-stone-200 cursor-pointer"
|
||||
>
|
||||
<option value="lbs">lbs</option>
|
||||
<option value="bushel">bu</option>
|
||||
<option value="box">bx</option>
|
||||
<option value="sack">sk</option>
|
||||
<option value="crate">cr</option>
|
||||
<option value="bin">bn</option>
|
||||
<option value="pallet">plt</option>
|
||||
<option value="custom">custom</option>
|
||||
</select>
|
||||
</div>
|
||||
{yield_unit === "custom" && (
|
||||
<input aria-label="Unit Name…"
|
||||
type="text"
|
||||
placeholder="Unit name…"
|
||||
value={customYieldUnit}
|
||||
onChange={(e) => setCustomYieldUnit(e.target.value)}
|
||||
className="mt-1.5 w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-2 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bin + Container */}
|
||||
<div className="border-t border-stone-100 pt-5">
|
||||
<p className="text-xs font-semibold uppercase tracking-wider text-stone-400 mb-3">Bin, Container & Pallets</p>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label htmlFor="fld-8-bin-id" className="block text-xs font-medium text-stone-600 mb-1.5">Bin ID</label>
|
||||
<input id="fld-8-bin-id" aria-label=". BIN 001"
|
||||
type="text"
|
||||
value={bin_id}
|
||||
onChange={(e) => setBinId(e.target.value)}
|
||||
placeholder="e.g. BIN-001"
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="fld-9-container-id" className="block text-xs font-medium text-stone-600 mb-1.5">Container ID</label>
|
||||
<input id="fld-9-container-id" aria-label=". CONT A42"
|
||||
type="text"
|
||||
value={container_id}
|
||||
onChange={(e) => setContainerId(e.target.value)}
|
||||
placeholder="e.g. CONT-A42"
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-3 grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label htmlFor="fld-10-pallets" className="block text-xs font-medium text-stone-600 mb-1.5">Pallets</label>
|
||||
<input id="fld-10-pallets" aria-label=". 4"
|
||||
type="number"
|
||||
value={pallets}
|
||||
onChange={(e) => setPallets(e.target.value)}
|
||||
placeholder="e.g. 4"
|
||||
min="0"
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="fld-11-packer-name" className="block text-xs font-medium text-stone-600 mb-1.5">Packer Name</label>
|
||||
<input id="fld-11-packer-name" aria-label=". Jose R."
|
||||
type="text"
|
||||
value={packer_name}
|
||||
onChange={(e) => setPackerName(e.target.value)}
|
||||
placeholder="e.g. Jose R."
|
||||
className="w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Notes — collapsible */}
|
||||
<div className="border-t border-stone-100 pt-5">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setNotesOpen(!notesOpen)}
|
||||
className="flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-stone-400 hover:text-stone-600"
|
||||
>
|
||||
<span>Notes</span>
|
||||
<span className="text-stone-500">{notesOpen ? Icons.chevronUp("h-4 w-4") : Icons.chevronDown("h-4 w-4")}</span>
|
||||
</button>
|
||||
{notesOpen && (
|
||||
<textarea aria-label="Spray Records, Weather Conditions, Or Other Harvest Details..."
|
||||
value={notes}
|
||||
onChange={(e) => setNotes(e.target.value)}
|
||||
placeholder="Spray records, weather conditions, or other harvest details..."
|
||||
rows={3}
|
||||
className="mt-3 w-full rounded-xl border border-stone-200 bg-stone-50 px-3 py-3 text-sm outline-none focus:border-emerald-600 focus:bg-white transition-colors resize-none"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Save — big button */}
|
||||
<div className="flex items-center justify-end border-t border-stone-100 pt-5">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isPending || !crop_type || !harvest_date || !field_location}
|
||||
className="rounded-xl bg-green-600 px-8 py-4 text-base font-bold text-white hover:bg-green-700 transition-colors disabled:opacity-50 flex items-center gap-2 shadow-sm"
|
||||
>
|
||||
{isPending ? "Creating..." : <><span className="inline-flex items-center gap-1.5">{Icons.plant("h-4 w-4")} Create Lot</span></>}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import ShareTraceButton from "@/components/route-trace/ShareTraceButton";
|
||||
|
||||
export default function PublicTraceActions({ lotNumber }: { lotNumber: string }) {
|
||||
return (
|
||||
<div className="flex items-center justify-center gap-2 mb-4">
|
||||
<ShareTraceButton lotNumber={lotNumber} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user