import React, { useState, useEffect, useRef } from 'react'; import { useParams, Link, useNavigate } from 'react-router-dom'; import { useQuery } from '@tanstack/react-query'; import { apiClient } from '@/lib/api/client'; import { useCartStore } from '@/lib/cart/store'; import { Button } from '@/components/ui/button'; import Container from '@/components/Layout/Container'; import { formatPrice } from '@/lib/currency'; import { ShoppingCart, Minus, Plus, ArrowLeft, ChevronLeft, ChevronRight, Heart } from 'lucide-react'; import { toast } from 'sonner'; import type { Product as ProductType, ProductsResponse } from '@/types/product'; export default function Product() { const { slug } = useParams<{ slug: string }>(); const navigate = useNavigate(); const [quantity, setQuantity] = useState(1); const [activeTab, setActiveTab] = useState<'description' | 'additional' | 'reviews'>('description'); const [selectedImage, setSelectedImage] = useState(); const [selectedVariation, setSelectedVariation] = useState(null); const [selectedAttributes, setSelectedAttributes] = useState>({}); const thumbnailsRef = useRef(null); const { addItem } = useCartStore(); // Fetch product details by slug const { data: product, isLoading, error } = useQuery({ queryKey: ['product', slug], queryFn: async () => { if (!slug) return null; const response = await apiClient.get(apiClient.endpoints.shop.products, { slug, per_page: 1, }); if (response && response.products && response.products.length > 0) { return response.products[0]; } return null; }, enabled: !!slug, }); // Set initial image when product loads useEffect(() => { if (product && !selectedImage) { setSelectedImage(product.image || product.images?.[0]); } }, [product]); // Find matching variation when attributes change useEffect(() => { if (product?.type === 'variable' && product.variations && Object.keys(selectedAttributes).length > 0) { const variation = (product.variations as any[]).find(v => { return Object.entries(selectedAttributes).every(([key, value]) => { const attrKey = `attribute_${key.toLowerCase()}`; return v.attributes[attrKey] === value.toLowerCase(); }); }); setSelectedVariation(variation || null); } }, [selectedAttributes, product]); // Auto-switch image when variation selected useEffect(() => { if (selectedVariation && selectedVariation.image) { setSelectedImage(selectedVariation.image); } }, [selectedVariation]); // Scroll thumbnails const scrollThumbnails = (direction: 'left' | 'right') => { if (thumbnailsRef.current) { const scrollAmount = 200; thumbnailsRef.current.scrollBy({ left: direction === 'left' ? -scrollAmount : scrollAmount, behavior: 'smooth' }); } }; const handleAttributeChange = (attributeName: string, value: string) => { setSelectedAttributes(prev => ({ ...prev, [attributeName]: value })); }; const handleAddToCart = async () => { if (!product) return; // Validate variation selection for variable products if (product.type === 'variable') { if (!selectedVariation) { toast.error('Please select all product options'); return; } } try { await apiClient.post(apiClient.endpoints.cart.add, { product_id: product.id, quantity, variation_id: selectedVariation?.id || 0, }); addItem({ key: `${product.id}${selectedVariation ? `-${selectedVariation.id}` : ''}`, product_id: product.id, name: product.name, price: parseFloat(selectedVariation?.price || product.price), quantity, image: selectedImage || product.image, }); toast.success(`${product.name} added to cart!`, { action: { label: 'View Cart', onClick: () => navigate('/cart'), }, }); } catch (error) { toast.error('Failed to add to cart'); console.error(error); } }; if (isLoading) { return (
); } if (error || !product) { return (

Product Not Found

The product you're looking for doesn't exist.

); } const currentPrice = selectedVariation?.price || product.price; const regularPrice = selectedVariation?.regular_price || product.regular_price; const isOnSale = selectedVariation ? parseFloat(selectedVariation.sale_price || '0') > 0 : product.on_sale; const stockStatus = selectedVariation?.in_stock !== undefined ? (selectedVariation.in_stock ? 'instock' : 'outofstock') : product.stock_status; return (
{/* Breadcrumb */}
{/* Product Images */}
{/* Main Image */}
{selectedImage ? ( {product.name} ) : (
No image
)}
{/* Thumbnail Slider */} {product.images && product.images.length > 1 && (
{/* Left Arrow */} {product.images.length > 4 && ( )} {/* Scrollable Thumbnails */}
{product.images.map((img, index) => ( ))}
{/* Right Arrow */} {product.images.length > 4 && ( )}
)}
{/* Product Info */}

{product.name}

{/* Price */}
{isOnSale && regularPrice ? (
{formatPrice(currentPrice)} {formatPrice(regularPrice)} SALE
) : ( {formatPrice(currentPrice)} )}
{/* Stock Status */}
{stockStatus === 'instock' ? ( In Stock ) : ( Out of Stock )}
{/* Short Description */} {product.short_description && (
)} {/* Variation Selector */} {product.type === 'variable' && product.attributes && product.attributes.length > 0 && (
{product.attributes.map((attr: any, index: number) => ( attr.variation && (
) ))}
)} {/* Quantity & Add to Cart */} {stockStatus === 'instock' && (
{/* Quantity Selector */}
setQuantity(Math.max(1, parseInt(e.target.value) || 1))} className="w-16 text-center border-x border-gray-300 py-2 focus:outline-none" min="1" />
{/* Action Buttons */}
)} {/* Product Meta */}
{product.sku && (
SKU: {product.sku}
)} {product.categories && product.categories.length > 0 && (
Categories: {product.categories.map((cat: any) => cat.name).join(', ')}
)}
{/* Product Tabs */}
{/* Tab Headers */}
{/* Tab Content */}
{activeTab === 'description' && (
{product.description ? (
) : (

No description available.

)}
)} {activeTab === 'additional' && (
{product.attributes && product.attributes.length > 0 ? ( {product.attributes.map((attr: any, index: number) => ( ))}
{attr.name} {Array.isArray(attr.options) ? attr.options.join(', ') : attr.options}
) : (

No additional information available.

)}
)} {activeTab === 'reviews' && (

Reviews coming soon...

)}
); }