import type { Metadata } from 'next'; import { Suspense } from 'react'; import { getServerClient } from '@/core/lib/brainerce.server'; import { buildMetaDescription } from '@/core/lib/seo'; import { OrganizationJsonLd } from '@/components/seo/organization-json-ld'; import { getCanonicalSiteUrl } from '@/core/lib/site-url'; import { RichTextBlock } from '@/ui/layout/rich-text-block'; import { HomeClient } from '@/ui/home/home-client'; import { ReferralGreeting } from '@/components/referral/referral-greeting'; // Build homepage metadata server-side so Google, Facebook, WhatsApp etc. // see a real on first request. Falls back to the // store name when the merchant hasn't authored a meta description yet. export async function generateMetadata(): Promise { try { const storeInfo = await (await getServerClient()).getStoreInfo(); const description = buildMetaDescription(storeInfo.metaDescription) || undefined; return { title: storeInfo.name, description, openGraph: { title: storeInfo.name, description, type: 'website', }, twitter: { card: 'summary_large_image', title: storeInfo.name, description, }, }; } catch { return {}; } } export default async function HomePage() { // Fetch store info server-side so the JSON-LD is in the initial HTML — // crawlers and AI Overviews see it without needing to execute JavaScript. // Failure here is non-fatal: the client component re-fetches via the // StoreProvider so the page still renders. // // Also fetch the merchant's homepage intro (RICH_TEXT key='main'). When // present, it renders as a sanitized HTML block above the product grid — // typical use is brand introduction, value-prop copy, or a seasonal // announcement that needs more formatting than the AnnouncementBar. // When absent, RichTextBlock returns null cleanly so the layout collapses // to just the product grid. const client = await getServerClient(); const [storeInfo, intro] = await Promise.all([ client.getStoreInfo().catch(() => null), client.content.richText.get('main').catch(() => null), ]); const baseUrl = await getCanonicalSiteUrl(); return ( <> {storeInfo && baseUrl ? : null} {/* Referral landing. A referral link is `/?ref=`, so it lands here. Renders nothing without a valid `?ref=`, and nothing at all on a store with referrals switched off. The Suspense boundary is required: the component reads `useSearchParams()`, which would otherwise opt this whole page out of static rendering. */} ); }