import { useState, useEffect } from "react"; import styles from "./ProductCard.module.scss"; import { IoMdHeartEmpty, IoMdHeart } from "react-icons/io"; import { FaShoppingCart } from "react-icons/fa"; import { useNavigate } from "react-router-dom"; import { useAddFavoriteMutation, useRemoveFavoriteMutation, useGetFavoritesQuery, } from "../../app/api/favoritesApi"; import { useAddToCartMutation, useUpdateCartItemMutation, useRemoveFromCartMutation, } from "../../app/api/cartApi"; import { Modal } from "antd"; import { useTranslation } from "react-i18next"; import { DecreaseIcon, IncreaseIcon } from "../Icons"; import ImageCarousel from "./imageCarousel/index"; import { useCart } from "../../app/api/useCart"; const truncateDescription = (htmlString, maxLength = 80) => { const tempDiv = document.createElement("div"); tempDiv.innerHTML = htmlString; const textContent = tempDiv.textContent || tempDiv.innerText || ""; return textContent.length > maxLength ? textContent.substring(0, maxLength).trim() + "..." : textContent; }; const isPriceZero = (price) => !price || parseFloat(price) === 0; const ProductCard = ({ product, showAddToCart = true, showFavoriteButton = true, onAddToCart, onToggleFavorite, isFavorite = false, descriptionMaxLength = 85, }) => { const { t } = useTranslation(); const navigate = useNavigate(); const [stockErrorModalVisible, setStockErrorModalVisible] = useState(false); const [isLoading, setIsLoading] = useState(false); const [isHovered, setIsHovered] = useState(false); const [addFavorite] = useAddFavoriteMutation(); const [removeFavorite] = useRemoveFavoriteMutation(); const { data: favoriteProducts = [] } = useGetFavoritesQuery(); const [localIsFavorite, setLocalIsFavorite] = useState( favoriteProducts.some((fav) => fav.product?.id === product.id) ); const { getCartItem } = useCart(); const [addToCart] = useAddToCartMutation(); const [updateCartItem] = useUpdateCartItemMutation(); const [removeFromCart] = useRemoveFromCartMutation(); const cartItem = getCartItem(product.id); const [localQuantity, setLocalQuantity] = useState(0); const [pendingQuantity, setPendingQuantity] = useState(0); const { name, price_amount, old_price_amount, media = [], reviews } = product; const truncatedDesc = truncateDescription(product.description, descriptionMaxLength); const calculatedDiscount = !product.discount && old_price_amount && price_amount && old_price_amount > price_amount ? Math.round(((old_price_amount - price_amount) / old_price_amount) * 100) : null; useEffect(() => { const qty = parseInt(cartItem?.quantity || cartItem?.product_quantity || 0, 10); setLocalQuantity(qty); setPendingQuantity(qty); }, [cartItem]); useEffect(() => { if (Array.isArray(favoriteProducts)) { setLocalIsFavorite( favoriteProducts.some((fav) => fav.product?.id === product.id) ); } }, [favoriteProducts, product.id]); useEffect(() => { const serverQty = parseInt(cartItem?.quantity || cartItem?.product_quantity || 0, 10); if (pendingQuantity === serverQty || pendingQuantity <= 0) return; const handler = setTimeout(async () => { try { setIsLoading(true); await updateCartItem({ productId: product.id, quantity: pendingQuantity }).unwrap(); } catch { setLocalQuantity(serverQty); setPendingQuantity(serverQty); } finally { setIsLoading(false); } }, 500); return () => clearTimeout(handler); }, [pendingQuantity, cartItem, product.id, updateCartItem]); const handleCardClick = () => navigate(`/product/${product.id}`); const handleAddToCart = async (event) => { event.preventDefault(); event.stopPropagation(); if (product.stock <= 0) { setStockErrorModalVisible(true); return; } setLocalQuantity((prev) => prev + 1); setPendingQuantity((prev) => prev + 1); try { await addToCart({ productId: product.id, quantity: 1 }).unwrap(); } catch { setLocalQuantity((prev) => prev - 1); setPendingQuantity((prev) => prev - 1); } }; const handleQuantityIncrease = (event) => { event.preventDefault(); event.stopPropagation(); if (isLoading) return; if (localQuantity >= product.stock) { setStockErrorModalVisible(true); return; } setLocalQuantity((prev) => prev + 1); setPendingQuantity((prev) => prev + 1); }; const handleQuantityDecrease = (event) => { event.preventDefault(); event.stopPropagation(); if (isLoading) return; if (pendingQuantity <= 1) { setPendingQuantity(0); setLocalQuantity(0); setIsLoading(true); removeFromCart({ productId: product.id }) .unwrap() .catch(() => { setLocalQuantity(1); setPendingQuantity(1); }) .finally(() => setIsLoading(false)); } else { setLocalQuantity((prev) => prev - 1); setPendingQuantity((prev) => prev - 1); } }; const handleToggleFavorite = async (event) => { event.preventDefault(); event.stopPropagation(); if (isLoading) return; setIsLoading(true); setLocalIsFavorite((prev) => !prev); try { if (localIsFavorite) { await removeFavorite(product.id).unwrap(); } else { await addFavorite(product.id).unwrap(); } } catch { setLocalIsFavorite((prev) => !prev); // revert } finally { setIsLoading(false); } }; return ( <>
{truncatedDesc}
{t("common.not_enough_stock", { available: product.stock, requested: localQuantity + 1, })}