diff --git a/src/hooks/useProductDetail.ts b/src/hooks/useProductDetail.ts index 1db5cee..dd0c4d7 100644 --- a/src/hooks/useProductDetail.ts +++ b/src/hooks/useProductDetail.ts @@ -1,37 +1,196 @@ -import { useState, useEffect } from "react"; +"use client"; -export interface Product { - id: string; - name: string; - price: number; - category: string; - description?: string; +import { useState, useMemo, useCallback } from "react"; +import { useProduct } from "./useProduct"; +import type { Product } from "@/lib/api/product"; +import type { ProductVariant } from "@/components/ecommerce/productDetail/ProductDetailCard"; +import type { ExtendedCartItem } from "./useCart"; + +interface ProductImage { + src: string; + alt: string; } -export const useProductDetail = (productId: string | undefined) => { - const [product, setProduct] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); +interface ProductMeta { + salePrice?: string; + ribbon?: string; + inventoryStatus?: string; + inventoryQuantity?: number; + sku?: string; +} - useEffect(() => { - if (!productId) return; +export function useProductDetail(productId: string) { + const { product, isLoading, error } = useProduct(productId); + const [selectedQuantity, setSelectedQuantity] = useState(1); + const [selectedVariants, setSelectedVariants] = useState>({}); - const fetchProduct = async () => { - try { - setIsLoading(true); - // Simulate API call - await new Promise((resolve) => setTimeout(resolve, 500)); - // Product would be fetched here - setProduct(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to load product"); - } finally { - setIsLoading(false); - } + const images = useMemo(() => { + if (!product) return []; + + if (product.images && product.images.length > 0) { + return product.images.map((src, index) => ({ + src, + alt: product.imageAlt || `${product.name} - Image ${index + 1}`, + })); + } + return [{ + src: product.imageSrc, + alt: product.imageAlt || product.name, + }]; + }, [product]); + + const meta = useMemo(() => { + if (!product?.metadata) return {}; + + const metadata = product.metadata; + + let salePrice: string | undefined; + const onSaleValue = metadata.onSale; + const onSale = String(onSaleValue) === "true" || onSaleValue === 1 || String(onSaleValue) === "1"; + const salePriceValue = metadata.salePrice; + + if (onSale && salePriceValue !== undefined && salePriceValue !== null) { + if (typeof salePriceValue === 'number') { + salePrice = `$${salePriceValue.toFixed(2)}`; + } else { + const salePriceStr = String(salePriceValue); + salePrice = salePriceStr.startsWith('$') ? salePriceStr : `$${salePriceStr}`; + } + } + + let inventoryQuantity: number | undefined; + if (metadata.inventoryQuantity !== undefined) { + const qty = metadata.inventoryQuantity; + inventoryQuantity = typeof qty === 'number' ? qty : parseInt(String(qty), 10); + } + + return { + salePrice, + ribbon: metadata.ribbon ? String(metadata.ribbon) : undefined, + inventoryStatus: metadata.inventoryStatus ? String(metadata.inventoryStatus) : undefined, + inventoryQuantity, + sku: metadata.sku ? String(metadata.sku) : undefined, + }; + }, [product]); + + const variants = useMemo(() => { + if (!product) return []; + + const variantList: ProductVariant[] = []; + + if (product.metadata?.variantOptions) { + try { + const variantOptionsStr = String(product.metadata.variantOptions); + const parsedOptions = JSON.parse(variantOptionsStr); + + if (Array.isArray(parsedOptions)) { + parsedOptions.forEach((option: any) => { + if (option.name && option.values) { + const values = typeof option.values === 'string' + ? option.values.split(',').map((v: string) => v.trim()) + : Array.isArray(option.values) + ? option.values.map((v: any) => String(v).trim()) + : [String(option.values)]; + + if (values.length > 0) { + const optionLabel = option.name; + const currentSelected = selectedVariants[optionLabel] || values[0]; + + variantList.push({ + label: optionLabel, + options: values, + selected: currentSelected, + onChange: (value) => { + setSelectedVariants((prev) => ({ + ...prev, + [optionLabel]: value, + })); + }, + }); + } + } + }); + } + } catch (error) { + console.warn("Failed to parse variantOptions:", error); + } + } + + if (variantList.length === 0 && product.brand) { + variantList.push({ + label: "Brand", + options: [product.brand], + selected: product.brand, + onChange: () => { }, + }); + } + + if (variantList.length === 0 && product.variant) { + const variantOptions = product.variant.includes('/') + ? product.variant.split('/').map(v => v.trim()) + : [product.variant]; + + const variantLabel = "Variant"; + const currentSelected = selectedVariants[variantLabel] || variantOptions[0]; + + variantList.push({ + label: variantLabel, + options: variantOptions, + selected: currentSelected, + onChange: (value) => { + setSelectedVariants((prev) => ({ + ...prev, + [variantLabel]: value, + })); + }, + }); + } + + return variantList; + }, [product, selectedVariants]); + + const quantityVariant = useMemo(() => ({ + label: "Quantity", + options: Array.from({ length: 10 }, (_, i) => String(i + 1)), + selected: String(selectedQuantity), + onChange: (value) => setSelectedQuantity(parseInt(value, 10)), + }), [selectedQuantity]); + + const createCartItem = useCallback((): ExtendedCartItem | null => { + if (!product) return null; + + const variantStrings = Object.entries(selectedVariants).map( + ([label, value]) => `${label}: ${value}` + ); + + if (variantStrings.length === 0 && product.variant) { + variantStrings.push(`Variant: ${product.variant}`); + } + + const variantId = Object.values(selectedVariants).join('-') || 'default'; + + return { + id: `${product.id}-${variantId}-${selectedQuantity}`, + productId: product.id, + name: product.name, + variants: variantStrings, + price: product.price, + quantity: selectedQuantity, + imageSrc: product.imageSrc, + imageAlt: product.imageAlt || product.name, + }; + }, [product, selectedVariants, selectedQuantity]); + + return { + product, + isLoading, + error, + images, + meta, + variants, + quantityVariant, + selectedQuantity, + selectedVariants, + createCartItem, }; - - fetchProduct(); - }, [productId]); - - return { product, isLoading, error }; -}; +}