Initial commit - Route Commerce platform

This commit is contained in:
2026-06-01 19:40:55 +00:00
commit 53a9671461
617 changed files with 106132 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
import { redirect } from "next/navigation";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import AdminLookupPage from "@/components/route-trace/AdminLookupPage";
import RouteTraceNav from "@/components/route-trace/RouteTraceNav";
export default async function LookupPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = 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="mx-auto max-w-3xl">
<div className="mb-8">
<h1 className="text-2xl font-semibold text-zinc-100">Lookup</h1>
<p className="mt-1 text-sm text-zinc-500">Find lots by lot number or crop type</p>
</div>
<RouteTraceNav activeTab="lookup" />
<AdminLookupPage brandId={effectiveBrandId} />
</div>
</div>
);
}
@@ -0,0 +1,51 @@
import { redirect } from "next/navigation";
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 default async function LotDetailPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
const [detailResult, ordersResult] = await Promise.all([
getRouteTraceLotDetail(id),
getLotOrders(id),
]);
if (!detailResult.success || !detailResult.lot) {
return (
<div className="min-h-screen bg-zinc-950 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">
<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>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-zinc-950 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>
</div>
<RouteTraceNav activeTab="lots" />
<LotDetailPanel
lot={detailResult.lot}
brandId={effectiveBrandId}
orders={ordersResult.success ? ordersResult.orders : []}
/>
</div>
</div>
);
}
@@ -0,0 +1,27 @@
import { redirect } from "next/navigation";
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 default async function NewLotPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = 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="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>
</div>
<RouteTraceNav activeTab="lots" />
<LotCreateForm brandId={effectiveBrandId} />
</div>
</div>
);
}
+41
View File
@@ -0,0 +1,41 @@
import { redirect } from "next/navigation";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import { getRouteTraceLots } from "@/actions/route-trace/lots";
import RouteTraceNav from "@/components/route-trace/RouteTraceNav";
import LotListTable from "@/components/route-trace/LotListTable";
import Link from "next/link";
export default async function LotsPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
const result = await getRouteTraceLots(effectiveBrandId);
const lots = result.success ? result.lots : [];
return (
<div className="min-h-screen bg-zinc-950 px-6 py-10">
<div className="mx-auto max-w-6xl">
<div className="mb-8 flex items-center justify-between">
<div>
<h1 className="text-2xl font-semibold text-zinc-100">Lots</h1>
<p className="mt-1 text-sm text-zinc-500">{lots.length} lot{lots.length !== 1 ? "s" : ""} total</p>
</div>
<Link
href="/admin/route-trace/lots/new"
className="rounded-xl bg-stone-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-stone-800 transition-colors"
>
+ New Lot
</Link>
</div>
<RouteTraceNav activeTab="lots" />
<LotListTable initialLots={lots} brandId={effectiveBrandId} />
</div>
</div>
);
}
+56
View File
@@ -0,0 +1,56 @@
import { redirect } from "next/navigation";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import {
getRouteTraceStats,
getRouteTraceLots,
getHarvestLotsReadyToHaul,
getFieldYieldSummary,
getInventoryByCrop,
getRecentLotEvents,
} from "@/actions/route-trace/lots";
import RouteTraceDashboard from "@/components/route-trace/RouteTraceDashboard";
export default async function RouteTraceDashboardPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = await isFeatureEnabled(effectiveBrandId, "route_trace");
if (!enabled) redirect("/admin/settings/apps?reason=route_trace");
const [statsResult, lotsResult, haulingResult, yieldResult, invResult, eventsResult] = await Promise.all([
getRouteTraceStats(effectiveBrandId),
getRouteTraceLots(effectiveBrandId),
getHarvestLotsReadyToHaul(effectiveBrandId),
getFieldYieldSummary(effectiveBrandId),
getInventoryByCrop(effectiveBrandId),
getRecentLotEvents(effectiveBrandId, 10),
]);
const stats = statsResult.success ? statsResult.stats : {
active_count: 0, in_transit_count: 0, at_shed_count: 0, total_lots_today: 0, total_harvested_today: 0, total_lots: 0,
};
const recentLots = lotsResult.success ? lotsResult.lots.slice(0, 8) : [];
const haulingLots = haulingResult.success ? haulingResult.lots : [];
const fieldYield = yieldResult.success ? yieldResult.summary : [];
const inventoryByCrop = invResult.success ? invResult.inventory : [];
const recentActivity = eventsResult.success ? eventsResult.events : [];
return (
<main className="min-h-screen px-6 py-8">
<div className="mx-auto max-w-5xl">
<RouteTraceDashboard
stats={stats}
recentLots={recentLots}
haulingLots={haulingLots}
fieldYield={fieldYield}
inventoryByCrop={inventoryByCrop}
recentActivity={recentActivity}
brandId={effectiveBrandId}
/>
</div>
</main>
);
}
@@ -0,0 +1,35 @@
import { redirect } from "next/navigation";
import { getAdminUser } from "@/lib/admin-permissions";
import { isFeatureEnabled } from "@/lib/feature-flags";
import RouteTraceNav from "@/components/route-trace/RouteTraceNav";
export default async function RouteTraceSettingsPage() {
const adminUser = await getAdminUser();
if (!adminUser) redirect("/login");
const effectiveBrandId = adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
const enabled = 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="mx-auto max-w-2xl">
<div className="mb-8">
<h1 className="text-2xl font-semibold text-zinc-100">Route Trace Settings</h1>
<p className="mt-1 text-sm text-zinc-500">Configure your traceability workflow and defaults</p>
</div>
<RouteTraceNav activeTab="settings" />
<div className="rounded-2xl border border-zinc-800 bg-zinc-900 shadow-black/20 p-6">
<p className="text-sm text-zinc-500">Settings coming soon. For now, use the Add-ons page to manage Route Trace.</p>
<a
href="/admin/settings/apps"
className="mt-4 inline-flex items-center gap-1.5 rounded-xl bg-stone-900 px-4 py-2.5 text-sm font-medium text-white hover:bg-stone-800 transition-colors"
>
Manage Add-ons
</a>
</div>
</div>
</div>
);
}