import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; import { MobileAddToCart } from "@/components/product/mobile-add-to-cart"; import { ProductCard } from "@/components/product/product-card"; import { ProductCarousel } from "@/components/product/product-carousel"; import { ProductGallery } from "@/components/product/product-gallery"; import { ProductPurchase } from "@/components/product/product-purchase"; import { getProductBySlug, getProducts } from "@/lib/headless/client"; interface ProductPageProps { params: Promise<{ slug: string }> } // generateStaticParams + revalidate quedaban aquí para pre-renderizar en // build time, pero HEADLESS_PROVIDER/MEDUSA_* no existen en el contexto del // Docker build: el snapshot estático quedaba congelado con el catálogo mock // (todos los productos con price: null) hasta que ISR lo revalidara. Con // frontend-deploy corriendo 2 réplicas y sin cacheHandler compartido, cada // pod revalida su propia caché de forma independiente, así que un producto // podía mostrar "Consultar precio" en un pod y el precio real en el otro // según cuál hubiera sido "calentado". force-dynamic elimina esa caché por // pod y deja esta ruta en vivo contra Medusa, igual que el listado // (dinámico por searchParams). export const dynamic = "force-dynamic"; export async function generateMetadata({ params }: ProductPageProps): Promise { const { slug } = await params; const product = await getProductBySlug(slug); return product ? { title: product.name, description: product.shortDescription, openGraph: { images: [product.image] } } : { title: "Producto" }; } export default async function ProductPage({ params }: ProductPageProps) { const { slug } = await params; const product = await getProductBySlug(slug); if (!product) notFound(); const products = await getProducts(); const recommended = products.filter((candidate) => candidate.id !== product.id && (candidate.category === product.category || candidate.collection === product.collection)).slice(0, 8); const suggested = recommended[0]; return ( <> {/* max-w-[1600px] (antes max-w-7xl/1280px) y una 3ra columna desde xl -- aprovecha pantallas grandes en vez de dejar el buy box apretado contra el texto o cortado por el panel de zoom de al lado (ver ProductGallery). Por debajo de xl, el buy box cae al flujo normal en la 2da columna, sin duplicar el componente en el DOM (evita el id="product-buy-button" repetido que rompería el IntersectionObserver de MobileAddToCart). */}
{product.category} · {product.collection}

{product.name}

{product.description}

Detalles del producto Marca: {product.brand}. Edad recomendada: {product.ageRange}. La disponibilidad y presentación final se confirman con Ari Shopping. Envíos y entregas Coordinamos envíos nacionales y entrega según ubicación. Los tiempos se confirman durante la cotización.
{/* Buy box estilo Amazon: precio/variantes/carrito en su propia tarjeta, sticky desde xl mientras el resto de la pagina scrollea. El sugerido usa el mismo cálculo de "recommended" que ya alimenta el carrusel de abajo -- mismo criterio real (categoría/colección), no un dato inventado. */}
{suggested && (

También te puede interesar

)}
{recommended.length > 0 && (

También te puede gustar

)} ); }