import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { Suspense } from 'react'; import clsx from 'clsx'; import { AddManyToCart } from 'components/cart/add-many-to-cart'; import { GridTileImage } from 'components/grid/tile'; import Label from 'components/label'; import { SupportedLocale } from 'components/layout/navbar/language-control'; import Price from 'components/price'; import { ProductDescription } from 'components/product/product-description'; import { ProductTastingNotes } from 'components/product/tasting-notes'; import { VariantSelector } from 'components/product/variant-selector'; import { HIDDEN_PRODUCT_TAG } from 'lib/constants'; import { getProduct, getProductRecommendations } from 'lib/shopify'; import { Image as MediaImage, Product } from 'lib/shopify/types'; import Image from 'next/image'; import Link from 'next/link'; export const runtime = 'edge'; export const revalidate = 43200; // 12 hours in seconds export async function generateMetadata({ params }: { params: { handle: string; locale?: SupportedLocale }; }): Promise { const product: Product | undefined = await getProduct({ handle: params.handle, language: params?.locale?.toUpperCase() }); if (!product) return notFound(); const { url, 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: url ? { images: [ { url, width, height, alt } ] } : null }; } export default async function ProductPage({ params }: { params: { handle: string; locale?: SupportedLocale }; }) { const numberOfOtherImages = 3; const product = await getProduct({ handle: params.handle, language: params?.locale?.toUpperCase() }); let otherImages: MediaImage[] = []; if (!!product) { otherImages = product.images .slice(0, numberOfOtherImages + 1) // +1 to account for featured image .filter((image) => image?.url !== product.featuredImage?.url); } if (!product) return notFound(); const productJsonLd = { '@context': 'https://schema.org', '@type': 'Product', name: product.title, description: product.description, image: product.featuredImage.url, 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 ( <>