Admin AI Tools page: unified design system styling, provider selector with OpenAI turd emoji, free-text model input with exact ID warning

This commit is contained in:
2026-06-02 02:21:11 +00:00
parent 809e0061ca
commit 15e939ad7e
116 changed files with 14991 additions and 5326 deletions
@@ -11,6 +11,12 @@ import {
getRecentLotEvents,
} from "@/actions/route-trace/lots";
export const metadata = {
title: "Lot Lookup | Route Trace",
description: "Search and lookup harvest lots by lot number, bin ID, or container ID. Quick traceability search for produce distribution.",
keywords: ["lot lookup", "search lots", "find lot", "traceability search", "lot number search", "bin lookup"],
};
export default async function LookupPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
+25 -6
View File
@@ -1,18 +1,37 @@
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import { getRouteTraceLotDetail, getLotOrders } from "@/actions/route-trace/lots";
import LotDetailPanel from "@/components/route-trace/LotDetailPanel";
import RouteTraceNav from "@/components/route-trace/RouteTraceNav";
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const detailResult = await getRouteTraceLotDetail(id);
const lotNumber = detailResult.success && detailResult.lot ? detailResult.lot.lot_number : null;
return {
title: lotNumber ? `Lot ${lotNumber} | Route Trace` : "Lot Detail | Route Trace",
description: lotNumber
? `View complete traceability details for harvest lot ${lotNumber}. Track events, order fulfillment, and FSMA compliance records.`
: "View harvest lot traceability details and order fulfillment information.",
keywords: lotNumber ? [`lot ${lotNumber}`, "lot detail", "traceability", "harvest lot", "lot events"] : ["lot detail", "traceability", "harvest lot"],
};
}
export default async function LotDetailPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const cookieStore = await cookies();
const devSession = cookieStore.get("dev_session")?.value;
const isDevMode = !!devSession;
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
const enabled = isDevMode ? true : await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
const [detailResult, ordersResult] = await Promise.all([
@@ -22,11 +41,11 @@ export default async function LotDetailPage({ params }: { params: Promise<{ id:
if (!detailResult.success || !detailResult.lot) {
return (
<div className="min-h-screen bg-zinc-950 px-6 py-10">
<div className="min-h-screen bg-stone-50 px-6 py-10">
<div className="mx-auto max-w-2xl">
<div className="rounded-xl border border-red-200 bg-zinc-900 p-6 text-center">
<div className="rounded-xl border border-red-200 bg-white p-6 text-center">
<p className="text-red-600">Lot not found</p>
<a href="/admin/route-trace/lots" className="mt-3 inline-block text-sm text-blue-400 hover:underline"> Back to Lots</a>
<a href="/admin/route-trace/lots" className="mt-3 inline-block text-sm text-stone-500 hover:text-stone-700"> Back to Lots</a>
</div>
</div>
</div>
@@ -34,10 +53,10 @@ export default async function LotDetailPage({ params }: { params: Promise<{ id:
}
return (
<div className="min-h-screen bg-zinc-950 px-6 py-10">
<div className="min-h-screen bg-stone-50 px-6 py-10">
<div className="mx-auto max-w-3xl">
<div className="mb-6">
<a href="/admin/route-trace/lots" className="text-sm text-zinc-500 hover:text-zinc-300"> Back to Lots</a>
<a href="/admin/route-trace/lots" className="text-sm text-stone-500 hover:text-stone-700"> Back to Lots</a>
</div>
<RouteTraceNav activeTab="lots" />
<LotDetailPanel
+14 -3
View File
@@ -1,23 +1,34 @@
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import LotCreateForm from "@/components/route-trace/LotCreateForm";
import RouteTraceNav from "@/components/route-trace/RouteTraceNav";
export const metadata = {
title: "Create New Lot | Route Trace",
description: "Create a new harvest lot for traceability tracking. Record crop type, field location, worker, quantity, and harvest date.",
keywords: ["create lot", "new lot", "harvest entry", "lot creation", "traceability", "harvest tracking"],
};
export default async function NewLotPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const cookieStore = await cookies();
const devSession = cookieStore.get("dev_session")?.value;
const isDevMode = !!devSession;
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
const enabled = isDevMode ? true : await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
return (
<div className="min-h-screen bg-zinc-950 px-6 py-10">
<div className="min-h-screen bg-stone-50 px-6 py-10">
<div className="mx-auto max-w-2xl">
<div className="mb-6">
<a href="/admin/route-trace/lots" className="text-sm text-zinc-500 hover:text-zinc-300"> Back to Lots</a>
<a href="/admin/route-trace/lots" className="text-sm text-stone-500 hover:text-stone-700"> Back to Lots</a>
</div>
<RouteTraceNav activeTab="lots" />
<LotCreateForm brandId={effectiveBrandId} />
+12 -1
View File
@@ -1,4 +1,5 @@
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import { getRouteTraceLots } from "@/actions/route-trace/lots";
@@ -11,13 +12,23 @@ import {
getRecentLotEvents,
} from "@/actions/route-trace/lots";
export const metadata = {
title: "Harvest Lots | Route Trace",
description: "View and manage all harvest lots. Track active lots, in-transit shipments, and completed deliveries across your produce distribution network.",
keywords: ["harvest lots", "lot management", "lot tracking", "produce lots", "harvest tracking", "field lots"],
};
export default async function LotsPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const cookieStore = await cookies();
const devSession = cookieStore.get("dev_session")?.value;
const isDevMode = !!devSession;
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
const enabled = isDevMode ? true : await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
const [statsResult, lotsResult, haulingResult, yieldResult, invResult, eventsResult] = await Promise.all([
+64 -11
View File
@@ -1,4 +1,5 @@
import { redirect } from "next/navigation";
import { cookies } from "next/headers";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import {
@@ -11,13 +12,43 @@ import {
} from "@/actions/route-trace/lots";
import RouteTracePage from "@/components/route-trace/RouteTracePage";
export const metadata = {
title: "Route Trace | Harvest Traceability Dashboard",
description: "Track produce lots from field to delivery. Manage harvest events, hauling logistics, inventory by crop, and FSMA compliance reporting for fresh produce distribution.",
keywords: ["route trace", "harvest traceability", "lot tracking", "farm to fork", "FSMA compliance", "food safety", "produce distribution", "haul tracking", "inventory management"],
openGraph: {
title: "Route Trace | Harvest Traceability",
description: "Complete lot traceability from field to delivery with real-time tracking and FSMA compliance.",
type: "website",
},
};
// Route Trace icon component
const Icons = {
routeTrace: (className: string) => (
<svg className={className} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M3 3v18h18" />
<path d="M7 16l4-8 4 5 5-9" />
<circle cx="7" cy="16" r="1.5" fill="currentColor" />
<circle cx="11" cy="8" r="1.5" fill="currentColor" />
<circle cx="15" cy="13" r="1.5" fill="currentColor" />
<circle cx="20" cy="4" r="1.5" fill="currentColor" />
</svg>
),
};
export default async function RouteTraceDashboardPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const cookieStore = await cookies();
const devSession = cookieStore.get("dev_session")?.value;
const isDevMode = !!devSession;
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
// Bypass feature check in dev mode (dev_session cookie present)
const enabled = isDevMode ? true : await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
const [statsResult, lotsResult, haulingResult, yieldResult, invResult, eventsResult] = await Promise.all([
@@ -40,15 +71,37 @@ export default async function RouteTraceDashboardPage() {
const recentActivity = eventsResult.success ? eventsResult.events : [];
return (
<RouteTracePage
stats={stats}
recentLots={recentLots}
haulingLots={haulingLots}
fieldYield={fieldYield}
inventoryByCrop={inventoryByCrop}
recentActivity={recentActivity}
brandId={effectiveBrandId}
lots={allLots}
/>
<main className="min-h-screen bg-[var(--admin-bg)]">
{/* Header */}
<div className="px-4 sm:px-6 md:px-8 py-6 sm:py-8">
<div className="flex flex-col sm:flex-row items-start sm:items-start justify-between gap-4 mb-4 sm:mb-6">
<div className="space-y-1 flex-1 min-w-0">
<div className="flex items-center gap-2 sm:gap-3">
<div className="flex h-10 w-10 sm:h-12 sm:w-12 items-center justify-center rounded-xl bg-emerald-600">
{Icons.routeTrace("h-5 w-5 sm:h-6 sm:w-6 text-white")}
</div>
<div>
<h1 className="text-2xl sm:text-3xl font-black text-[var(--admin-text-primary)] tracking-tight">Route Trace</h1>
<p className="text-xs sm:text-sm text-[var(--admin-text-muted)]">Field-to-delivery lot traceability</p>
</div>
</div>
</div>
</div>
</div>
{/* Content */}
<div className="px-4 sm:px-6 md:px-8 py-4 sm:py-6">
<RouteTracePage
stats={stats}
recentLots={recentLots}
haulingLots={haulingLots}
fieldYield={fieldYield}
inventoryByCrop={inventoryByCrop}
recentActivity={recentActivity}
brandId={effectiveBrandId}
lots={allLots}
/>
</div>
</main>
);
}
@@ -11,6 +11,12 @@ import {
getRecentLotEvents,
} from "@/actions/route-trace/lots";
export const metadata = {
title: "Route Trace Settings",
description: "Configure Route Trace traceability workflow settings, defaults, and add-on features for your produce distribution operation.",
keywords: ["route trace settings", "traceability configuration", "FSMA settings", "traceability defaults"],
};
export default async function RouteTraceSettingsPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");