"use client"; import { useState, useEffect } from "react"; import Image from "next/image"; import Link from "next/link"; import { motion, AnimatePresence } from "framer-motion"; import { ChevronDown, Star, Minus, Plus } from "lucide-react"; import { useTranslations } from "next-intl"; import type { Product } from "@/types/saleor"; import { useSaleorCheckoutStore } from "@/stores/saleorCheckoutStore"; import { getProductPrice, getProductPriceAmount, getLocalizedProduct, formatPrice } from "@/lib/saleor"; import { getTranslatedShortDescription, getTranslatedBenefits } from "@/lib/i18n/productText"; import { isValidLocale } from "@/lib/i18n/locales"; import ProductCard from "@/components/product/ProductCard"; import ProductBenefits from "@/components/product/ProductBenefits"; import ProductReviews from "@/components/product/ProductReviews"; import AsSeenIn from "@/components/home/AsSeenIn"; import TrustBadges from "@/components/home/TrustBadges"; import BeforeAfterGallery from "@/components/home/BeforeAfterGallery"; import HowItWorks from "@/components/home/HowItWorks"; import NewsletterSection from "@/components/home/NewsletterSection"; import BundleSelector from "@/components/product/BundleSelector"; import { useAnalytics } from "@/lib/analytics"; interface ProductDetailProps { product: Product; relatedProducts: Product[]; bundleProducts?: Product[]; locale?: string; } function ExpandableSection({ title, children, defaultOpen = false }: { title: string; children: React.ReactNode; defaultOpen?: boolean; }) { const [isOpen, setIsOpen] = useState(defaultOpen); return (
{isOpen && (
{children}
)}
); } function StarRating({ rating = 5, count = 0 }: { rating?: number; count?: number }) { return (
{[...Array(5)].map((_, i) => ( ))}
{count > 0 && ( ({count >= 1000 ? '1000+' : count}) )}
); } export default function ProductDetail({ product, relatedProducts, bundleProducts = [], locale = "sr" }: ProductDetailProps) { const t = useTranslations("ProductDetail"); const tProduct = useTranslations("Product"); const [selectedImage, setSelectedImage] = useState(0); const [quantity, setQuantity] = useState(1); const [isAdding, setIsAdding] = useState(false); const [urgencyIndex, setUrgencyIndex] = useState(0); const [selectedBundleVariantId, setSelectedBundleVariantId] = useState(null); const { addLine, openCart } = useSaleorCheckoutStore(); const { trackProductView, trackAddToCart } = useAnalytics(); const validLocale = isValidLocale(locale) ? locale : "sr"; // Track product view on mount useEffect(() => { const localized = getLocalizedProduct(product, locale); const baseVariant = product.variants?.[0]; const price = baseVariant?.pricing?.price?.gross?.amount || 0; const currency = baseVariant?.pricing?.price?.gross?.currency || "RSD"; trackProductView({ id: product.id, name: localized.name, price, currency, category: product.category?.name, }); }, [product, locale]); useEffect(() => { const interval = setInterval(() => { setUrgencyIndex(prev => (prev + 1) % 3); }, 3000); return () => clearInterval(interval); }, []); const urgencyMessages = [ { icon: "🚀", text: t("urgency1") }, { icon: "🛒", text: t("urgency2") }, { icon: "👀", text: t("urgency3") }, ]; const localized = getLocalizedProduct(product, locale); const baseVariant = product.variants?.[0]; const selectedVariantId = selectedBundleVariantId || baseVariant?.id; const selectedVariant = selectedVariantId === baseVariant?.id ? baseVariant : bundleProducts.find(p => p.variants?.[0]?.id === selectedVariantId)?.variants?.[0]; const images = product.media?.length > 0 ? product.media.filter(m => m.type === "IMAGE") : [{ id: "0", url: "/placeholder-product.jpg", alt: localized.name, type: "IMAGE" as const }]; const handleAddToCart = async () => { if (!selectedVariantId) return; setIsAdding(true); try { await addLine(selectedVariantId, 1); // Track add to cart const localized = getLocalizedProduct(product, locale); const baseVariant = product.variants?.[0]; const selectedVariant = selectedVariantId === baseVariant?.id ? baseVariant : bundleProducts.find(p => p.variants?.[0]?.id === selectedVariantId)?.variants?.[0]; const price = selectedVariant?.pricing?.price?.gross?.amount || 0; const currency = selectedVariant?.pricing?.price?.gross?.currency || "RSD"; trackAddToCart({ id: product.id, name: localized.name, price, currency, quantity: 1, variant: selectedVariant?.name, }); openCart(); } finally { setIsAdding(false); } }; const handleSelectVariant = (variantId: string, qty: number, price: number) => { setSelectedBundleVariantId(variantId); setQuantity(qty); }; const isAvailable = (selectedVariant?.quantityAvailable ?? 0) > 0; const selectedPrice = selectedVariant?.pricing?.price?.gross?.amount || 0; const price = selectedPrice > 0 ? new Intl.NumberFormat(validLocale === "en" ? "en-US" : validLocale === "de" ? "de-DE" : validLocale === "fr" ? "fr-FR" : "sr-RS", { style: "currency", currency: selectedVariant?.pricing?.price?.gross?.currency || "RSD", minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(selectedPrice) : ""; const priceAmount = selectedPrice; const originalPrice = priceAmount > 0 ? new Intl.NumberFormat(validLocale === "en" ? "en-US" : validLocale === "de" ? "de-DE" : validLocale === "fr" ? "fr-FR" : "sr-RS", { style: "currency", currency: "RSD", minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(Math.round(priceAmount * 1.30)) : null; const shortDescription = getTranslatedShortDescription(localized.description, validLocale); const metadataBenefits = product.metadata?.find(m => m.key === "benefits")?.value?.split(','); const benefits = getTranslatedBenefits(metadataBenefits, validLocale); return ( <>
{images.length > 1 && (
{images.map((image, index) => ( ))}
)}
{images[selectedImage].alt {images.length > 1 && ( <>
{images.map((_, index) => (
)}
{urgencyMessages[urgencyIndex].icon} {urgencyMessages[urgencyIndex].text}

{localized.name}

{shortDescription}

{t("stocksRunningOut")}
{originalPrice && priceAmount > 0 && (
{originalPrice} -30%
{price}
)} {!originalPrice && (
{price || tProduct("outOfStock")}
)}
{bundleProducts.length > 0 ? ( ) : ( product.variants && product.variants.length > 1 && (
{t("size")}
{product.variants.map((v) => ( ))}
) )} {isAvailable ? ( ) : (
{t("outOfStock")}
)}

{t("freeShipping")}

{t("guarantee")}

{t("secureCheckout")}

{t("easyReturns")}

{t("benefits")}
{benefits.map((benefit, index) => ( {benefit.trim()} ))}

{t("howToUseText")}

{t("ingredientsText")}

{selectedVariant?.sku && (

SKU: {selectedVariant.sku}

)}
{relatedProducts && relatedProducts.length > 0 && (
{t("youMayAlsoLike")}

{t("similarProducts")}

{relatedProducts.filter(p => p && p.id).slice(0, 4).map((relatedProduct, index) => (
))}
)} ); }