1fe5ffee8d
Server-side / caching refactor (Grok): - New RPC get_public_stops_for_brand (migration 148) for public storefront stops - New server action getPublicStopsForBrand with revalidate=300 + tags - Add revalidateTag invalidation to createStopsBatch + publishStop - Convert /tuxedo/stops and /indian-river-direct/stops to Server Components - Extract TuxedoStopsList + IndianRiverStopsList as client islands (GSAP only) - Removes supabase-js from browser bundle on those routes - Both pages now statically prerendered (5m ISR) Parallel agent changes also staged: - AI provider model list refresh (claude-sonnet-4-5, etc.) - ESLint directive patches for react-hooks/set-state-in-effect - Admin + storefront + checkout + cart updates - New admin_create_stop_rpcs migration (147) - Misc fixes across ~90 files Build verified: typecheck clean, lint clean on new files, production build succeeds.
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { supabase } from "@/lib/supabase";
|
|
import NewStopForm from "@/components/admin/NewStopForm";
|
|
import StopProductAssignment from "@/components/admin/StopProductAssignment";
|
|
import { getAdminUser } from "@/lib/admin-permissions";
|
|
import AdminAccessDenied from "@/components/admin/AdminAccessDenied";
|
|
import { redirect } from "next/navigation";
|
|
import Link from "next/link";
|
|
|
|
type Stop = {
|
|
city: string;
|
|
state: string;
|
|
location: string;
|
|
date: string;
|
|
time: string;
|
|
brand_id: string;
|
|
active: boolean;
|
|
address?: string | null;
|
|
zip?: string | null;
|
|
cutoff_time?: string | null;
|
|
};
|
|
|
|
export default async function NewStopPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: Promise<{ duplicate?: string }>;
|
|
}) {
|
|
const adminUser = await getAdminUser();
|
|
const { duplicate } = await searchParams;
|
|
|
|
if (!adminUser) return <AdminAccessDenied />;
|
|
if (!adminUser.can_manage_stops) redirect("/admin/pickup");
|
|
|
|
let duplicateFrom: Stop | null = null;
|
|
if (duplicate) {
|
|
const { data } = await supabase
|
|
.from("stops")
|
|
.select("city, state, location, date, time, brand_id, active, address, zip, cutoff_time")
|
|
.eq("id", duplicate)
|
|
.single();
|
|
duplicateFrom = data;
|
|
}
|
|
|
|
const brandId =
|
|
adminUser.brand_id ?? "64294306-5f42-463d-a5e8-2ad6c81a96de";
|
|
|
|
const [{ data: allProducts }] = await Promise.all([
|
|
supabase
|
|
.from("products")
|
|
.select("id, name, type, price")
|
|
.eq("brand_id", brandId)
|
|
.eq("active", true),
|
|
]);
|
|
|
|
return (
|
|
<main className="min-h-screen px-6 py-12" style={{ backgroundColor: "var(--admin-bg)" }}>
|
|
<div className="mx-auto max-w-4xl">
|
|
<div className="mb-8">
|
|
<Link
|
|
href="/admin/stops"
|
|
className="text-sm text-stone-500 hover:text-stone-700"
|
|
>
|
|
← Back to Stops
|
|
</Link>
|
|
</div>
|
|
|
|
<div className="rounded-2xl bg-white p-8 border border-stone-200 shadow-lg">
|
|
<h1 className="text-3xl font-bold text-stone-950">
|
|
{duplicateFrom ? "Duplicate Stop" : "Create Stop"}
|
|
</h1>
|
|
|
|
<p className="mt-2 text-stone-600">
|
|
{duplicateFrom
|
|
? `Pre-filled from ${duplicateFrom.city}, ${duplicateFrom.state}. Edit and save to create.`
|
|
: "Add a new tour stop for Tuxedo Corn or Indian River Direct."}
|
|
</p>
|
|
|
|
<NewStopForm duplicateFrom={duplicateFrom} />
|
|
</div>
|
|
</div>
|
|
</main>
|
|
);
|
|
}
|