fix(storefront): align store actions with actual DB schema
Reviewer caught three runtime breakages that the prior commit would
have introduced (the legacy supabase shim masked them by returning
null):
1. **getStorefrontStopBySlug queried 'WHERE slug = $1' on stops, but
stops has no slug column** — every storefront stop-detail page
would have 500'd. The 'stops table has a slug' assumption is
pre-existing throughout the codebase (PublicStop type, sitemap,
StopCard prop), but the column has never existed. Fix: switch the
route param to the stop's UUID (id). Rename folder [slug] → [id]
for honesty. Update StopCard prop and the two stops-list links to
pass stop.id instead of stop.slug. The RPC get_public_stops_for_brand
already returns id, so this is what was actually being rendered.
2. **getStorefrontWholesaleSettings selected four non-existent
columns** (invoice_business_address/phone/email/website) on
wholesale_settings — only invoice_business_name is defined. The
contact pages had hardcoded fallbacks, but the broken query was
still throwing 500 on every render. Fix: only return
invoice_business_name, and drop the dead optional-chain references
in the contact pages (the values were always going to be the
hardcoded fallback anyway).
3. **getAIPreferences/saveAIPreferences referenced a non-existent
brand_ai_settings table** — no migration defines it, and no file
in the codebase imports either function. Deleted the whole
preferences.ts module (dead code that would have 500'd the moment
anyone wired it up).
4. **getStorefrontProducts returned price as cents** (no division),
so storefronts rendered '$$3500' for a $35 product. Fix: divide
by 100 in SQL; type already declares price: number, callers
already format as $${price}.
Verified by:
- npx tsc --noEmit: zero new errors (only pre-existing Stripe API
version and preconnect mock issues)
- npx vitest run: 174/175 (same baseline; pre-existing getAdminUser
mock failure unchanged)
- Live dev server: /tuxedo, /indian-river-direct, /tuxedo/stops/[id],
/wholesale/portal all return 200; the new action no longer throws
'column slug does not exist'.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
export default function ErrorPage({
|
||||
error,
|
||||
reset,
|
||||
}: {
|
||||
error: Error & { digest?: string };
|
||||
reset: () => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-blue-600 via-blue-700 to-blue-900 flex items-center justify-center p-6">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="max-w-lg w-full text-center relative"
|
||||
>
|
||||
<div className="absolute inset-0 opacity-20 pointer-events-none">
|
||||
<div className="absolute top-0 right-0 w-40 h-40 bg-white rounded-full -translate-y-1/2 translate-x-1/4" />
|
||||
<div className="absolute bottom-0 left-0 w-32 h-32 bg-white rounded-full translate-y-1/2 -translate-x-1/4" />
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ scale: 0 }}
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ delay: 0.2, type: "spring", stiffness: 200 }}
|
||||
className="relative inline-flex h-24 w-24 items-center justify-center rounded-full bg-white/20 backdrop-blur-sm mb-8"
|
||||
>
|
||||
<svg className="h-12 w-12 text-white" fill="none" viewBox="0 0 24 24" strokeWidth={1.5}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
|
||||
</svg>
|
||||
</motion.div>
|
||||
|
||||
<h1 className="text-4xl font-black text-white mb-4">Stop Not Available</h1>
|
||||
<p className="text-blue-100 mb-8 leading-relaxed">
|
||||
We couldn't load this stop. Please try again.
|
||||
</p>
|
||||
|
||||
{process.env.NODE_ENV === "development" && (
|
||||
<div className="mb-8 rounded-2xl bg-white/10 border border-white/20 p-5 text-left backdrop-blur-sm">
|
||||
<p className="text-xs font-semibold uppercase tracking-wider text-blue-200 mb-2">Error Details</p>
|
||||
<p className="text-sm text-white/80 font-mono leading-relaxed break-all">{error.message}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="relative flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<button
|
||||
onClick={reset}
|
||||
className="rounded-2xl bg-white text-blue-700 hover:bg-blue-50 px-8 py-4 text-sm font-bold transition-all hover:shadow-xl hover:-translate-y-0.5 active:scale-95 shadow-lg"
|
||||
>
|
||||
Try Again
|
||||
</button>
|
||||
<Link
|
||||
href="/indian-river-direct"
|
||||
className="rounded-2xl bg-blue-700/50 backdrop-blur-sm border border-white/30 text-white hover:bg-blue-600/80 px-8 py-4 text-sm font-bold transition-all hover:-translate-y-0.5 active:scale-95"
|
||||
>
|
||||
Back to Homepage
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user