import { Checkbox } from '@chakra-ui/react'; import React, { useState, useCallback, useEffect } from 'react'; import { getAuth } from '~/libs/auth'; import { CartItem } from '~/types/cart'; import { upsertUserCart } from '~/services/cart'; import { useCartStore } from '../stores/useCartStore'; import { toast } from 'react-hot-toast'; import { getSelectedItemsFromCookie, updateSelectedItemInCookie, checkboxUpdateState, } from '~/utils/cart'; type Props = { item: CartItem; }; const CartItemSelect = ({ item }: Props) => { const auth = getAuth(); const { updateCartItem, cart, loadCart } = useCartStore(); const [isUpdating, setIsUpdating] = useState(false); const [localSelected, setLocalSelected] = useState(item.selected); const [isGlobalUpdating, setIsGlobalUpdating] = useState(false); // Subscribe to global checkbox update state useEffect(() => { const handleUpdateStateChange = (isUpdating) => { setIsGlobalUpdating(isUpdating); }; checkboxUpdateState.addListener(handleUpdateStateChange); return () => { checkboxUpdateState.removeListener(handleUpdateStateChange); }; }, []); // Initialize local state from cookie or server useEffect(() => { if (isUpdating) return; // Skip if we're currently updating // Check cookie first const selectedItems = getSelectedItemsFromCookie(); const storedState = selectedItems[item.id]; if (storedState !== undefined) { // Only update local state if it differs from current state if (localSelected !== storedState) { setLocalSelected(storedState); } // If cookie state differs from server state and we're not in the middle of an update, // synchronize the item state with cookie if (storedState !== item.selected) { // Update cart item silently to match cookie if (cart) { const updatedCartItems = cart.products.map((cartItem) => cartItem.id === item.id ? { ...cartItem, selected: storedState } : cartItem ); const updatedCart = { ...cart, products: updatedCartItems }; updateCartItem(updatedCart); } } } else { // Fall back to server state if no cookie exists setLocalSelected(item.selected); // Save state to cookie for future updateSelectedItemInCookie(item.id, item.selected, false); } }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]); const handleChange = useCallback( async (e: React.ChangeEvent) => { if (typeof auth !== 'object' || !cart || isUpdating) { return; } const newSelectedState = e.target.checked; // Update local state immediately for responsiveness setLocalSelected(newSelectedState); setIsUpdating(true); // Start the update - notify global state with this checkbox's ID checkboxUpdateState.startUpdate(item.id); try { // The cookie update is now handled inside the function with notification updateSelectedItemInCookie(item.id, newSelectedState, false); // We already started above // Update cart state immediately for UI responsiveness const updatedCartItems = cart.products.map((cartItem) => cartItem.id === item.id ? { ...cartItem, selected: newSelectedState } : cartItem ); const updatedCart = { ...cart, products: updatedCartItems }; updateCartItem(updatedCart); // Save to server await upsertUserCart({ userId: auth.id, type: item.cart_type, id: item.id, qty: item.quantity, selected: newSelectedState, // purchase_tax_id: item.purchase_tax_id || null, // Ensure null for numeric fields }); // Reload cart to ensure consistency await loadCart(auth.id); } catch (error) { console.error('Failed to update item selection:', error); toast.error('Gagal memperbarui pilihan barang'); // Revert local state on error setLocalSelected(!newSelectedState); // Revert cookie change updateSelectedItemInCookie(item.id, !newSelectedState, false); // Reload cart to get server state loadCart(auth.id); } finally { setIsUpdating(false); // End the update - notify global state with this checkbox's ID checkboxUpdateState.endUpdate(item.id); } }, [auth, cart, item, isUpdating, updateCartItem, loadCart] ); // Determine if THIS specific checkbox should be disabled - only disable // if this specific checkbox is updating const isDisabled = isUpdating || checkboxUpdateState.isCheckboxUpdating(item.id); return (
); }; export default CartItemSelect;