import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { GridTileImage } from "components/grid/tile"; import Footer from "components/layout/footer"; import { Gallery } from "components/product/gallery"; import { ProductProvider } from "components/product/product-context"; import { ProductDescription } from "components/product/product-description"; import { HIDDEN_PRODUCT_TAG } from "lib/constants"; import { getProduct, getProductRecommendations } from "lib/store/products"; import { getImageUrl } from "lib/utils/image"; import Link from "next/link"; import { Suspense } from "react"; export async function generateMetadata(props: { params: Promise<{ handle: string }>; }): Promise { const params = await props.params; const product = await getProduct({ handle: params.handle }); if (!product) return notFound(); const { source, width, height, altText: alt } = product.featuredImage || {}; const indexable = !product.tags.includes(HIDDEN_PRODUCT_TAG); return { title: product.seo.title || product.title, description: product.seo.description || product.description, robots: { index: indexable, follow: indexable, googleBot: { index: indexable, follow: indexable, }, }, openGraph: source ? { images: [ { url: getImageUrl(source), width, height, alt, }, ], } : null, }; } export default async function ProductPage(props: { params: Promise<{ handle: string }>; }) { const params = await props.params; const product = await getProduct({ handle: params.handle }); if (!product) return notFound(); const productJsonLd = { "@context": "https://schema.org", "@type": "Product", name: product.title, description: product.description, image: getImageUrl(product.featuredImage.source), offers: { "@type": "AggregateOffer", availability: product.availableForSale ? "https://schema.org/InStock" : "https://schema.org/OutOfStock", priceCurrency: product.priceRange.minVariantPrice.currencyCode, highPrice: product.priceRange.maxVariantPrice.amount, lowPrice: product.priceRange.minVariantPrice.amount, }, }; return (