"use client"; import React, { useState, useEffect } from 'react'; import { getProduct } from '@/hooks/use-shopify-products'; import { useShopifyCart } from '@/hooks/use-shopify-cart'; import ProductDetailGallery from './ProductDetailGallery'; import ProductDetailInfo from './ProductDetailInfo'; import { Button } from '../ui/button'; interface ProductImage { url: string; altText?: string; } interface ProductPrice { amount: string; currencyCode: string; } export interface ProductVariant { id: string; title: string; price: ProductPrice; availableForSale: boolean; selectedOptions: Array<{ name: string; value: string; }>; image?: { url: string; altText?: string; }; } interface ProductOption { id: string; name: string; values: string[]; } export interface Product { id: string; title: string; description?: string; descriptionHtml?: string; handle: string; images: { edges: Array<{ node: ProductImage; }>; }; priceRange: { minVariantPrice: ProductPrice; }; compareAtPriceRange?: { minVariantPrice: ProductPrice; }; variants: { edges: Array<{ node: ProductVariant; }>; }; options: ProductOption[]; } type ProductDetailProps = { handle: string; onAddToCart?: () => void; } const ProductDetail: React.FC = ({ handle, onAddToCart: onAddToCartCallback }) => { const { addItem, openCart } = useShopifyCart(); const [product, setProduct] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedVariant, setSelectedVariant] = useState(null); const [selectedOptions, setSelectedOptions] = useState>({}); const [quantity, setQuantity] = useState(1); const [selectedImageIndex, setSelectedImageIndex] = useState(0); const [isAddingToCart, setIsAddingToCart] = useState(false); useEffect(() => { if (!handle) return; const fetchProduct = async () => { try { setLoading(true); setError(null); const productData = await getProduct(handle); if (!productData) { setError('Product not found'); return; } setProduct(productData); // Set default variant const firstVariant = productData.variants.edges[0]?.node; if (firstVariant) { setSelectedVariant(firstVariant); // Initialize selected options const initialOptions: Record = {}; firstVariant.selectedOptions.forEach(option => { initialOptions[option.name] = option.value; }); setSelectedOptions(initialOptions); } } catch (err) { console.error('Error fetching product:', err); setError(err instanceof Error ? err.message : 'Failed to load product'); } finally { setLoading(false); } }; fetchProduct(); }, [handle]); const handleOptionChange = (optionName: string, value: string) => { const newOptions = { ...selectedOptions, [optionName]: value }; setSelectedOptions(newOptions); // Find matching variant const matchingVariant = product?.variants.edges.find(({ node }) => { return node.selectedOptions.every(option => newOptions[option.name] === option.value ); }); if (matchingVariant) { setSelectedVariant(matchingVariant.node); // Update image if variant has an associated image if (matchingVariant.node.image && product) { const imageIndex = product.images.edges.findIndex( ({ node }) => node.url === matchingVariant.node.image?.url ); if (imageIndex !== -1) { setSelectedImageIndex(imageIndex); } } } }; const handleAddToCart = async () => { if (!selectedVariant || !product) return; setIsAddingToCart(true); try { await addItem(selectedVariant.id, quantity); openCart(); if (onAddToCartCallback) { onAddToCartCallback(); } } catch (error) { console.error('Failed to add item to cart:', error); } finally { setIsAddingToCart(false); } }; if (loading) { return (
{/* Image Gallery Skeleton */}
{Array.from({ length: 4 }).map((_, i) => (
))}
{/* Product Info Skeleton */}
); } if (error || !product) { return (

Product Not Found

{error || 'The requested product could not be found.'}

); } return (
edge.node)} selectedImageIndex={selectedImageIndex} onImageChange={setSelectedImageIndex} />
); }; export default ProductDetail;