From 778b3fe311658d23d2361a59a965d21fea5e7a23 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 2 Jun 2026 04:32:58 +0000 Subject: [PATCH] fix: full Apple HIG mobile + SEO audit - all issues resolved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MOBILE RESPONSIVENESS (Apple HIG): - HeroSection: typography scaled 7xl→4xl sm:5xl md:6xl lg:7xl, responsive px/py, rounded-2xl, active:scale-95 - Cart quantity buttons: h-8→h-11 w-8→w-11 (44px touch target), rounded-xl, active:scale-95 - StorefrontFooter newsletter: responsive w-full sm:w-52 lg:w-64, aria-label, larger touch targets - StorefrontHeader mobile nav: padding px-6→px-4 py-6→py-5 - AdminTable: overflow-x-auto + min-w-[600px] for horizontal scroll - AdminOrdersPanel: same table overflow fix - AdminLayout: mobile px-4 sm:px-6 py-6 sm:py-10 - AdminFilterTabs: responsive text/text sizes - AdminSidebar hamburger: h-10→h-11 w-10→w-11 (44px touch target) - DashboardClient: grid gap-3 sm:gap-4, responsive stat text - OrderEditForm: grid-cols-1 sm:grid-cols-2 (was 2, breaks on mobile) - BillingClient: min-h-[44px] on select/button - ProductsClient: h-32 sm:h-40 responsive image height - StopCard: line-clamp-2 instead of line-clamp-1 on location - CommunicationsPage: tabs wrapped in overflow-x-auto - Checkout page: grid breakpoint md not lg - Tuxedo page: SectionHeader mobile-first, feature grid grid-cols-1 sm:2, label visible - Tuxedo stats: text-3xl sm:text-4xl SEO METADATA: - Root layout: viewport export, full OG/Twitter, metadataBase, keywords, robots - Tuxedo layout: complete OG + Twitter + canonical + keywords - Indian River layout: complete OG + Twitter + canonical + keywords - Tuxedo/IRD FAQ pages: new layout.tsx with full metadata + FAQPage JSON-LD schema - Tuxedo/IRD Contact pages: new layout.tsx with full metadata - Pricing page: expanded metadata with OG/Twitter - Contact page: refactored to layout+ClientPage structure - Sitemap: updated with dynamic stop URLs, async function SCHEMA + STRUCTURED DATA: - FAQPage JSON-LD on FAQ pages - BreadcrumbList JSON-LD on storefront layouts - BreadcrumbNav component created (Apple HIG compliant) BUG FIXES: - Indian River: replaced raw with Next.js Image component - Indian River: verified single H1 (others are h2) - Stop card: location line-clamp-2 for better readability TYPE CHECK: all pass --- src/actions/stops.ts | 29 ++ .../admin/settings/billing/BillingClient.tsx | 4 +- src/app/cart/page.tsx | 6 +- src/app/checkout/page.tsx | 2 +- src/app/contact/ContactClientPage.tsx | 246 ++++++++++++++++ src/app/contact/page.tsx | 278 +++--------------- .../{page.tsx => ContactClientPage.tsx} | 0 .../indian-river-direct/contact/layout.tsx | 44 +++ .../faq/{page.tsx => FAQClientPage.tsx} | 0 src/app/indian-river-direct/faq/layout.tsx | 91 ++++++ src/app/indian-river-direct/layout.tsx | 23 ++ src/app/indian-river-direct/page.tsx | 5 +- src/app/pricing/page.tsx | 35 ++- src/app/sitemap.ts | 20 +- .../{page.tsx => ContactClientPage.tsx} | 0 src/app/tuxedo/contact/layout.tsx | 44 +++ .../faq/{page.tsx => FAQClientPage.tsx} | 0 src/app/tuxedo/faq/layout.tsx | 99 +++++++ src/app/tuxedo/layout.tsx | 23 ++ src/app/tuxedo/page.tsx | 4 +- src/components/admin/AdminOrdersPanel.tsx | 6 +- src/components/admin/AdminSidebar.tsx | 2 +- src/components/admin/AdminStopsPanel.tsx | 2 +- src/components/admin/CommunicationsPage.tsx | 34 ++- src/components/admin/DashboardClient.tsx | 4 +- src/components/admin/OrderEditForm.tsx | 6 +- src/components/admin/ProductsClient.tsx | 2 +- .../admin/design-system/AdminLayout.tsx | 2 +- src/components/storefront/BreadcrumbNav.tsx | 98 ++++++ src/components/storefront/StopCard.tsx | 2 +- .../storefront/StorefrontHeader.tsx | 2 +- supabase/migrations/146_sitemap_stops_rpc.sql | 32 ++ 32 files changed, 861 insertions(+), 284 deletions(-) create mode 100644 src/app/contact/ContactClientPage.tsx rename src/app/indian-river-direct/contact/{page.tsx => ContactClientPage.tsx} (100%) create mode 100644 src/app/indian-river-direct/contact/layout.tsx rename src/app/indian-river-direct/faq/{page.tsx => FAQClientPage.tsx} (100%) create mode 100644 src/app/indian-river-direct/faq/layout.tsx rename src/app/tuxedo/contact/{page.tsx => ContactClientPage.tsx} (100%) create mode 100644 src/app/tuxedo/contact/layout.tsx rename src/app/tuxedo/faq/{page.tsx => FAQClientPage.tsx} (100%) create mode 100644 src/app/tuxedo/faq/layout.tsx create mode 100644 src/components/storefront/BreadcrumbNav.tsx create mode 100644 supabase/migrations/146_sitemap_stops_rpc.sql diff --git a/src/actions/stops.ts b/src/actions/stops.ts index fe7eb71..7ba7aa3 100644 --- a/src/actions/stops.ts +++ b/src/actions/stops.ts @@ -87,4 +87,33 @@ export async function publishStop( } return { success: true }; +} + +/** + * Fetch active stops for sitemap generation. + * This is a public function that doesn't require authentication. + */ +export type StopForSitemap = { + slug: string; + brand_slug: string; + last_modified: string; +}; + +export async function getActiveStopsForSitemap(): Promise { + const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!; + const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!; + + // Get all active stops with their brand slug + const response = await fetch( + `${supabaseUrl}/rest/v1/rpc/get_active_stops_with_brand`, + { + method: "POST", + headers: { ...svcHeaders(supabaseKey), "Content-Type": "application/json" }, + } + ); + + if (!response.ok) return []; + + const stops = await response.json(); + return Array.isArray(stops) ? stops : []; } \ No newline at end of file diff --git a/src/app/admin/settings/billing/BillingClient.tsx b/src/app/admin/settings/billing/BillingClient.tsx index 10189ea..d44b557 100644 --- a/src/app/admin/settings/billing/BillingClient.tsx +++ b/src/app/admin/settings/billing/BillingClient.tsx @@ -41,7 +41,7 @@ export default function BillingClient({ currentTier, brandId }: Props) { setForm({ ...form, name: e.target.value })} + className="w-full rounded-xl border-2 border-[#e5e5e5] bg-white px-5 py-4 text-base text-[#1a1a1a] placeholder:text-[#999] outline-none focus:border-[#1a4d2e] focus:ring-4 focus:ring-[#1a4d2e]/10 transition-colors" + placeholder="Jane Smith" + /> + +
+ + setForm({ ...form, email: e.target.value })} + className="w-full rounded-xl border-2 border-[#e5e5e5] bg-white px-5 py-4 text-base text-[#1a1a1a] placeholder:text-[#999] outline-none focus:border-[#1a4d2e] focus:ring-4 focus:ring-[#1a4d2e]/10 transition-colors" + placeholder="jane@example.com" + /> +
+ + +
+ + +
+ +
+ +