From 7d4445bb9bad3d6c945503086a07bd882536e5f6 Mon Sep 17 00:00:00 2001
From: Miqdad <ahmadmiqdad27@gmail.com>
Date: Mon, 19 May 2025 11:02:19 +0700
Subject: <miqdad> fix unresponsive cart select

---
 src-migrate/modules/cart/components/ItemSelect.tsx | 170 +++++++++++++++------
 1 file changed, 126 insertions(+), 44 deletions(-)

(limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')

diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index d4a1b537..733ee64d 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -1,56 +1,138 @@
-import { Checkbox, Spinner } from '@chakra-ui/react'
-import React, { useState } from 'react'
-
-import { getAuth } from '~/libs/auth'
-import { CartItem } from '~/types/cart'
-import { upsertUserCart } from '~/services/cart'
-
-import { useCartStore } from '../stores/useCartStore'
+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,
+} from '~/utils/cart';
 
 type Props = {
-  item: CartItem
-}
+  item: CartItem;
+};
 
 const CartItemSelect = ({ item }: Props) => {
-  const auth = getAuth()
-  const { updateCartItem, cart } = useCartStore()
+  const auth = getAuth();
+  const { updateCartItem, cart, loadCart } = useCartStore();
+  const [isUpdating, setIsUpdating] = useState<boolean>(false);
+  const [localSelected, setLocalSelected] = useState<boolean>(item.selected);
+
+  // 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 this state to cookie for future use
+      updateSelectedItemInCookie(item.id, item.selected);
+    }
+  }, [item.id, item.selected, localSelected, cart, updateCartItem, isUpdating]);
+
+  const handleChange = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (typeof auth !== 'object' || !cart || isUpdating) {
+        return;
+      }
+
+      const newSelectedState = e.target.checked;
+
+      // Update local state immediately for responsiveness
+      setLocalSelected(newSelectedState);
+      setIsUpdating(true);
+
+      try {
+        // Update cookie immediately
+        updateSelectedItemInCookie(item.id, newSelectedState);
+
+        // 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,
+        });
 
-  const [isLoad, setIsLoad] = useState<boolean>(false)
+        // 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');
 
-  const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
-    if (typeof auth !== 'object' || !cart) return
-    
-    setIsLoad(true);
-    const updatedCartItems = cart.products.map(cartItem =>
-      cartItem.id === item.id
-        ? { ...cartItem, selected: e.target.checked }
-        : cartItem
-    );
+        // Revert local state on error
+        setLocalSelected(!newSelectedState);
 
-    // Update the entire cart
-    const updatedCart = { ...cart, products: updatedCartItems };
-    updateCartItem(updatedCart);
+        // Update cookie back
+        updateSelectedItemInCookie(item.id, !newSelectedState);
 
-    setIsLoad(false);
-  }
+        // Reload cart to get server state
+        loadCart(auth.id);
+      } finally {
+        setIsUpdating(false);
+      }
+    },
+    [auth, cart, item, isUpdating, updateCartItem, loadCart]
+  );
 
   return (
-    <div className='w-6 my-auto'>
-      {isLoad && (
-        <Spinner className='my-auto' size='sm' />
-      )}
-
-      {!isLoad && (
-        <Checkbox
-          borderColor='gray.600'
-          colorScheme='red'
-          size='lg'
-          isChecked={item.selected}
-          onChange={handleChange}
-        />
-      )}
+    <div className='w-6 my-auto relative'>
+      <Checkbox
+        borderColor='gray.600'
+        colorScheme='red'
+        size='lg'
+        isChecked={localSelected}
+        onChange={handleChange}
+        isDisabled={isUpdating}
+        opacity={isUpdating ? 0.5 : 1}
+        cursor={isUpdating ? 'not-allowed' : 'pointer'}
+        _disabled={{
+          opacity: 0.5,
+          cursor: 'not-allowed',
+          backgroundColor: 'gray.100',
+        }}
+      />
     </div>
-  )
-}
+  );
+};
 
-export default CartItemSelect
\ No newline at end of file
+export default CartItemSelect;
-- 
cgit v1.2.3

