"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[selectedImage].url})
{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("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) => (
))}
)}
>
);
}