import style from '../styles/item-action.module.css'; import React, { useEffect, useState } from 'react'; import { Spinner, Tooltip } from '@chakra-ui/react'; import { MinusIcon, PlusIcon, Trash2Icon } from 'lucide-react'; import { CartItem } from '~/types/cart'; import { getAuth } from '~/libs/auth'; import { deleteUserCart, upsertUserCart } from '~/services/cart'; import { useDebounce } from 'usehooks-ts'; import { useCartStore } from '../stores/useCartStore'; import { useProductCartContext } from '@/contexts/ProductCartContext'; import { removeSelectedItemsFromCookie, removeCartItemsFromCookie, quantityUpdateState, getCartDataFromCookie, setCartDataToCookie, } from '~/utils/cart'; import { toast } from 'react-hot-toast'; type Props = { item: CartItem; }; const CartItemAction = ({ item }: Props) => { const auth = getAuth(); const { setRefreshCart } = useProductCartContext(); const [isLoadDelete, setIsLoadDelete] = useState(false); const [isLoadQuantity, setIsLoadQuantity] = useState(false); const [quantity, setQuantity] = useState(item.quantity); const { loadCart, cart, updateCartItem } = useCartStore(); const limitQty = item.limit_qty?.transaction || 0; const handleDelete = async () => { if (typeof auth !== 'object') return; setIsLoadDelete(true); try { // Delete from server await deleteUserCart(auth.id, [item.cart_id]); // Clean up cookies immediately removeSelectedItemsFromCookie([item.id]); removeCartItemsFromCookie([item.cart_id]); // Update local cart state optimistically if (cart) { const updatedProducts = cart.products.filter( (product) => product.id !== item.id ); const updatedCart = { ...cart, products: updatedProducts, product_total: updatedProducts.length, }; updateCartItem(updatedCart); } // Reload from server and refresh context await loadCart(auth.id); setRefreshCart(true); toast.success('Item berhasil dihapus'); } catch (error) { console.error('Failed to delete cart item:', error); toast.error('Gagal menghapus item'); // Reload on error await loadCart(auth.id); } finally { setIsLoadDelete(false); } }; const updateQuantityInCookie = (productId, cartId, newQuantity) => { try { const cartData = getCartDataFromCookie(); let itemFound = false; // Find item by cart_id key or search within objects if (cartData[cartId]) { cartData[cartId].quantity = newQuantity; itemFound = true; } else { // Search by product id or cart_id within objects for (const key in cartData) { const item = cartData[key]; if (item.id === productId || item.cart_id === cartId) { item.quantity = newQuantity; itemFound = true; break; } } } if (itemFound) { setCartDataToCookie(cartData); return true; } return false; } catch (error) { console.error('Error updating quantity in cookie:', error); return false; } }; const decreaseQty = () => { setQuantity((quantity) => (quantity -= 1)); }; const increaseQty = () => { setQuantity((quantity) => (quantity += 1)); }; const debounceQty = useDebounce(quantity, 1000); useEffect(() => { if (isNaN(debounceQty)) setQuantity(1); if (limitQty > 0 && debounceQty > limitQty) setQuantity(limitQty); }, [debounceQty, limitQty]); useEffect(() => { const updateCart = async () => { if (typeof auth !== 'object' || isNaN(debounceQty)) return; if (debounceQty === item.quantity) return; quantityUpdateState.startUpdate(item.id); setIsLoadQuantity(true); try { // Update cookie immediately for responsive UI updateQuantityInCookie(item.id, item.cart_id, debounceQty); // Update local cart state optimistically if (cart) { const updatedProducts = cart.products.map((product) => product.id === item.id ? { ...product, quantity: debounceQty } : product ); const updatedCart = { ...cart, products: updatedProducts, }; updateCartItem(updatedCart); } // Send update to server await upsertUserCart({ userId: auth.id, type: item.cart_type, id: item.id, qty: debounceQty, selected: item.selected, }); // Reload from server to ensure consistency await loadCart(auth.id); // Re-update cookie if server reload overwrote it const currentCookieData = getCartDataFromCookie(); let needsReUpdate = false; for (const key in currentCookieData) { const cookieItem = currentCookieData[key]; if ( (cookieItem.id === item.id || cookieItem.cart_id === item.cart_id) && cookieItem.quantity !== debounceQty ) { needsReUpdate = true; break; } } if (needsReUpdate) { updateQuantityInCookie(item.id, item.cart_id, debounceQty); } } catch (error) { console.error('Error updating quantity:', error); toast.error('Gagal mengupdate quantity'); // Revert changes on error updateQuantityInCookie(item.id, item.cart_id, item.quantity); loadCart(auth.id); } finally { setIsLoadQuantity(false); quantityUpdateState.endUpdate(item.id); } }; updateCart(); //eslint-disable-next-line react-hooks/exhaustive-deps }, [debounceQty]); return (
{isLoadQuantity && (
)} setQuantity(parseInt(e.target.value))} value={quantity} /> 0 ? `Max. ${limitQty}` : ''}>
); }; export default CartItemAction;