"use client"; import Image from "next/image"; import React, { useState } from "react"; import { useRouter } from "next/navigation"; import { useSelector } from "react-redux"; import { useTranslations } from "next-intl"; import { motion, AnimatePresence } from "framer-motion"; import toast from "react-hot-toast"; import { BeatLoader } from "react-spinners"; import { Badge } from "./ui/badge"; import { Card, CardContent, CardHeader } from "./ui/card"; import { Button } from "./ui/button"; import DrawerComponent from "./layout/drawer/drawer-component"; import QuickProductDetails from "./quick-product-details"; import ZeroQuantity from "./zero-quantity"; import { FavouriteButton } from "./favourite-button"; import AuthModal from "./auth/auth-modal"; import { useAppDispatch } from "@/store/hooks"; import { addToCart } from "@/store/slices/cart-slice"; import { getProductDetails } from "@/store/slices/product-details-slice"; import { ProductCardProps } from "@/types/types"; import { getCurrentMainImage, getHoverImage } from "@/static-data/static-data"; import { useFavourites } from "@/hooks/use-favourites"; import { FaPlus } from "react-icons/fa6"; import { GrView } from "react-icons/gr"; import ProductIncementOrDecrement from "./product-increment-or-decrement"; import { MdOutlineShoppingCart } from "react-icons/md"; import StarRating from "./react-stars"; /* ---------------- Helper Functions ---------------- */ const calculateProductPrice = (product: any): number => { const variants = Array.isArray(product?.variants) ? product.variants : []; const basePrice = Number.isFinite(Number(product?.price)) ? Number(product?.price) : undefined; const variantPrices = variants .map((v: any) => v?.special_price ?? v?.price) .map((x: any) => (Number.isFinite(Number(x)) ? Number(x) : undefined)) .filter((n: any) => typeof n === "number") as number[]; return basePrice ?? (variantPrices.length ? Math.min(...variantPrices) : 0); }; const findCartItem = (cartData: any, productId: number) => { if (!cartData?.data?.items) return null; return cartData.data.items.find( (item: any) => item?.additional?.product_id === productId || item?.product?.id === productId ); }; const isProductInCart = (cartData: any, productId: number): boolean => !!findCartItem(cartData, productId); const getProductCartQuantity = (cartData: any, productId: number): number => { const cartItem = findCartItem(cartData, productId); return cartItem ? Number(cartItem?.total_quantity || cartItem?.quantity) : 0; }; const resolveProductId = ( product: any, chosenVariantId: number | string | null ): number | undefined => { if (product?.variants?.length) { return chosenVariantId ? Number(chosenVariantId) : product.variants[0]?.product_id; } return product?.product_id; }; /* ---------------- Component ---------------- */ export default function ProductCard({ product, wishlistProductId, cardColSpan, wishlistId, }: ProductCardProps) { const [selectedVariantIndex, setSelectedVariantIndex] = useState< number | null >(null); const [isHovered, setIsHovered] = useState(false); const [isAdding, setIsAdding] = useState(false); const [isMovingToCart, setIsMovingToCart] = useState(false); const [chosenVariantId, setChosenVariantId] = useState< number | string | null >(null); const [chosenVariantSku, setChosenVariantSku] = useState(null); const [showAuthModal, setShowAuthModal] = useState(false); const [pendingAddProductId, setPendingAddProductId] = useState( null ); const [showIncDec, setShowIncDec] = useState(false); const dispatch = useAppDispatch(); const router = useRouter(); const { moveToCart } = useFavourites(); const t = useTranslations("products"); const td = useTranslations("product-details"); const { productDetails } = useSelector((state: any) => state.productDetails); const { isAuthenticated } = useSelector((state: any) => state.auth); const { data: cartData } = useSelector((state: any) => state.cart); const baseImageUrl = getCurrentMainImage(product, selectedVariantIndex ?? 0); const hoverImageUrl = getHoverImage(product, selectedVariantIndex ?? 0); const isInStock = product?.in_stock ?? product?.inStock ?? false; const productPrice = calculateProductPrice(product); const productId = resolveProductId(product, chosenVariantId); const isInCart = productId ? isProductInCart(cartData, productId) : false; const cartQuantity = productId ? getProductCartQuantity(cartData, productId) : 0; /* ---------------- Handlers ---------------- */ const handleViewProduct = () => { dispatch(getProductDetails({ id: product?.product_id })); }; const handleVariantSelect = ( index: number, variantId?: number | string, sku?: string ) => { setSelectedVariantIndex(index); if (variantId) setChosenVariantId(variantId); if (sku) setChosenVariantSku(sku); }; const handleAddToCart = async () => { if (!isInStock || isAdding) return; const targetId = resolveProductId(product, chosenVariantId); if (!targetId) return; if (!isAuthenticated) { setPendingAddProductId(targetId); setShowAuthModal(true); return; } try { setIsAdding(true); const promise = dispatch( addToCart({ productId: targetId, productQTY: 1 }) ); await (typeof promise.unwrap === "function" ? promise.unwrap() : promise); toast.success( isProductInCart(cartData, targetId) ? t("quantity-updated") : t("added-to-cart") ); setShowIncDec(true); } catch (error) { toast.error(error instanceof Error ? error.message : String(error)); } finally { setIsAdding(false); } }; const handleMoveToCart = async () => { if (!wishlistId) return; try { setIsMovingToCart(true); await moveToCart(wishlistId); toast.success(t("moved-to-cart")); } catch { toast.error("Failed to move to cart"); } finally { setIsMovingToCart(false); } }; /* ---------------- Cart Button Variants ---------------- */ const motionVariants = { initial: { scaleX: 0 }, animate: { scaleX: 1 }, exit: { scaleX: 0 }, }; return ( isInStock && setIsHovered(true)} onMouseLeave={() => isInStock && setIsHovered(false)} className={`relative product-card shadow-none hover:shadow-[0px_10px_30px_rgba(149,157,165,0.1)] py-0 h-fit rounded-lg gap-3 ${cardColSpan || "col-span-6 xl:col-span-2" } border border-gray-200 hover:border-red-color`} > {!isInStock && } {/* Hover Actions */} } > {/* New Badge */} {product?.new && ( {td("new")} )}
{/* Main Image */} {product?.name router.push( `/product/${wishlistProductId || product?.product_id}` ) } priority /> {/* Hover Image */} {hoverImageUrl !== baseImageUrl && ( {`${product?.name} router.push( `/product/${wishlistProductId || product?.product_id}` ) } /> )}
{/* Cart Buttons */}
{isInCart && !showIncDec ? ( ) : showIncDec && isInCart ? (
) : ( )}
{/* Content */}

{chosenVariantSku ?? product?.sku}

{product?.name}

{/* Variant Selector */}
{product?.variants?.length ? (
{product.variants .slice(0, 2) .map((variant: any, index: number) => (
{`${product?.name handleVariantSelect( index, variant?.product_id, variant?.sku ) } />
))} {product.variants.length > 2 && ( +{product.variants.length - 2} )}
) : (
{`${product?.name handleVariantSelect(0, product?.product_id, product?.sku) } />
)}
{/* Price + Rating */}

{productPrice.toFixed(2)}

{/* {product?.reviews?.total} */} 4.5 {" "}
{/* Auth Modal */} { setShowAuthModal(open); if (!open) setPendingAddProductId(null); }} onAuthenticated={async () => { const targetId = pendingAddProductId ?? resolveProductId(product, chosenVariantId); if (!targetId) return; try { setIsAdding(true); const promise = dispatch( addToCart({ productId: targetId, productQTY: 1 }) ); await (typeof promise.unwrap === "function" ? promise.unwrap() : promise); toast.success(t("added-to-cart")); setShowIncDec(true); } finally { setIsAdding(false); setPendingAddProductId(null); } }} />
); }