import React, { useState, useRef, useEffect, useMemo } from "react"; import styles from "./CartPage.module.scss"; import { FaTrashAlt } from "react-icons/fa"; import Checkout from "../../components/Checkout"; import { Modal } from "antd"; import { useTranslation } from "react-i18next"; import EmptyCartState from "./emptyCart"; import { useRemoveFromCartMutation, useUpdateCartItemMutation, useCleanCartMutation, } from "../../app/api/cartApi"; import { useCart } from "../../app/api/useCart"; import { DecreaseIcon, IncreaseIcon } from "../../components/Icons"; import Loader from "../../components/Loader/index"; const isPriceZero = (price) => !price || parseFloat(price) === 0; const TruncatedDescription = ({ description, maxLength = 100 }) => { const stripHtml = (html) => { const doc = new DOMParser().parseFromString(html, "text/html"); return doc.body.textContent || ""; }; const plainText = stripHtml(description); const shouldTruncate = plainText.length > maxLength; return (
); }; const CartPage = () => { const { cartData, cartItems, isLoading } = useCart(); const { t } = useTranslation(); const [checkoutStores, setCheckoutStores] = useState({}); const [removeFromCart] = useRemoveFromCartMutation(); const [updateCartItem] = useUpdateCartItemMutation(); const [cleanCart] = useCleanCartMutation(); const [deleteModalVisible, setDeleteModalVisible] = useState(false); const [emptyCartModalVisible, setEmptyCartModalVisible] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); const [localQuantities, setLocalQuantities] = useState({}); const [pendingQuantities, setPendingQuantities] = useState({}); const [loadingItems, setLoadingItems] = useState({}); const checkoutRefs = useRef({}); const modalProps = { centered: true, className: styles.cartDeleteModal, maskClosable: false, width: 400, }; const stores = useMemo(() => { return Object.entries(cartData) .map(([storeSlug, items]) => { if (!items?.length) return null; const storeInfo = items[0]?.product?.channel?.[0]; return { id: storeInfo?.id || storeSlug, name: storeInfo?.name || storeSlug, slug: storeSlug, shipping_price: storeInfo?.shipping_price, items, }; }) .filter(Boolean); }, [cartData]); useEffect(() => { const newLocal = {}; const newPending = {}; cartItems.forEach((item) => { const id = item.product.id; const qty = parseInt(item.product_quantity, 10) || 0; newLocal[id] = qty; newPending[id] = qty; }); setLocalQuantities(newLocal); setPendingQuantities(newPending); }, [cartItems]); useEffect(() => { const timers = {}; Object.keys(pendingQuantities).forEach((productId) => { const serverItem = cartItems.find( (item) => String(item.product.id) === String(productId), ); const serverQty = serverItem ? parseInt(serverItem.product_quantity, 10) : 0; const pendingQty = pendingQuantities[productId]; if ( pendingQty === undefined || pendingQty === serverQty || pendingQty <= 0 ) return; timers[productId] = setTimeout(async () => { try { setLoadingItems((prev) => ({ ...prev, [productId]: true })); await updateCartItem({ productId, quantity: pendingQty }).unwrap(); } catch { setLocalQuantities((prev) => ({ ...prev, [productId]: serverQty })); setPendingQuantities((prev) => ({ ...prev, [productId]: serverQty })); } finally { setLoadingItems((prev) => ({ ...prev, [productId]: false })); } }, 500); }); return () => Object.values(timers).forEach(clearTimeout); }, [pendingQuantities, cartItems, updateCartItem]); const handleQuantityIncrease = (productId) => (event) => { event.preventDefault(); event.stopPropagation(); if (loadingItems[productId]) return; const item = cartItems.find((i) => i.product.id === productId); if (!item || localQuantities[productId] >= item.product.stock) return; const newQty = (localQuantities[productId] || 0) + 1; setLocalQuantities((prev) => ({ ...prev, [productId]: newQty })); setPendingQuantities((prev) => ({ ...prev, [productId]: newQty })); }; const handleQuantityDecrease = (productId) => (event) => { event.preventDefault(); event.stopPropagation(); if (loadingItems[productId]) return; const currentQty = localQuantities[productId] || 0; if (currentQty <= 1) { showDeleteConfirm(productId); return; } const newQty = currentQty - 1; setLocalQuantities((prev) => ({ ...prev, [productId]: newQty })); setPendingQuantities((prev) => ({ ...prev, [productId]: newQty })); }; const getStoreShippingPrice = (store) => store.shipping_price != null ? parseFloat(store.shipping_price) : 20; // Store içinde fiyatsız ürün var mı? const storeHasZeroPriceItem = (storeItems) => storeItems.some((item) => isPriceZero(item.product.price_amount)); const calculateStoreTotal = (storeItems) => storeItems.reduce((sum, item) => { return ( sum + (parseFloat(item.product.price_amount) || 0) * (parseInt(item.product_quantity, 10) || 0) ); }, 0); const handleCheckout = (storeId) => setCheckoutStores((prev) => ({ ...prev, [storeId]: true })); const handleBackToCart = (storeId) => setCheckoutStores((prev) => ({ ...prev, [storeId]: false })); const handleOrderSubmit = async (storeId) => { if (checkoutStores[storeId] && checkoutRefs.current[storeId]) { const success = await checkoutRefs.current[storeId](); if (success) setCheckoutStores((prev) => ({ ...prev, [storeId]: false })); } else { handleCheckout(storeId); } }; const showDeleteConfirm = (productId) => { setItemToDelete(productId); setDeleteModalVisible(true); }; const handleDeleteConfirm = async () => { if (itemToDelete) { try { await removeFromCart({ productId: itemToDelete }).unwrap(); setLocalQuantities((prev) => { const s = { ...prev }; delete s[itemToDelete]; return s; }); setPendingQuantities((prev) => { const s = { ...prev }; delete s[itemToDelete]; return s; }); } catch (e) { console.error("Failed to remove item:", e); } } setDeleteModalVisible(false); setItemToDelete(null); }; const handleEmptyCartConfirm = async () => { try { await cleanCart().unwrap(); setLocalQuantities({}); setPendingQuantities({}); setCheckoutStores({}); } catch (e) { console.error("Failed to clean cart:", e); } setEmptyCartModalVisible(false); }; const getTotalItemCount = () => cartItems.reduce( (sum, item) => sum + parseInt(item.product_quantity, 10), 0, ); return (
setDeleteModalVisible(false)} okText={t("common.yes")} cancelText={t("common.no")} >

{t("common.Do_you_really_want_to_remove_the_item_from_the_cart")}

setEmptyCartModalVisible(false)} okText={t("common.yes")} cancelText={t("common.no")} >

{t("common.Are_you_sure_you_want_to_empty_the_cart")}

{isLoading ? ( ) : cartItems.length === 0 ? ( ) : (

{t("cart.basket")} ({getTotalItemCount()})

{stores.map((store) => { const shippingPrice = getStoreShippingPrice(store); const storeTotal = calculateStoreTotal(store.items); const totalWithShipping = storeTotal + shippingPrice; const hasZeroPrice = storeHasZeroPriceItem(store.items); return (
{checkoutStores[store.id] ? ( item.product.id)} onBackToCart={() => handleBackToCart(store.id)} onPlaceOrder={(fn) => { checkoutRefs.current[store.id] = fn; }} /> ) : (

{store.name}

{store.items.map((item) => (
{item.product.name}

{item.product.name}

{isPriceZero(item.product.price_amount) ? "Bahasyny anyklamaly" : `${parseFloat(item.product.price_amount).toFixed(2)} m.`}
{localQuantities[item.product.id] !== undefined ? localQuantities[item.product.id] : parseInt(item.product_quantity, 10) || 0}
))}
)} {/* ✅ Store Summary - fiyatsız ürün varsa "Baha anyklamak" */}

{store.name} - {t("cart.basket")}:

{hasZeroPrice ? ( <>
{t("cart.price")}: Bahasyny anyklamaly
{t("cart.delivery")}: Bahasyny anyklamaly
{t("cart.total")}: Bahasyny anyklamaly
) : ( <>
{t("cart.price")}: {storeTotal.toFixed(2)} m.
{t("cart.delivery")}: {shippingPrice.toFixed(2)} m.
{t("cart.total")}: {totalWithShipping.toFixed(2)} m.
)}
); })}
{/* Mobile sticky summary */} {/*
{t("cart.price")}: {calculateTotal().toFixed(2)} m.
{t("cart.delivery")}: {stores.reduce((sum, store) => sum + getStoreShippingPrice(store), 0).toFixed(2)} m.
{ setIsExpanded(!isExpanded); e.target.style.outline = "none"; }} > {isExpanded ? ( ) : ( )} {t("cart.total")}: {(calculateTotal() + stores.reduce((sum, store) => sum + getStoreShippingPrice(store), 0)).toFixed(2)} m.
*/}
)}
); }; export default CartPage;