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. */}
>
);
}