summaryrefslogtreecommitdiff
path: root/src-migrate/modules/cart/components/ItemSelect.tsx
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-05-19 11:02:19 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-05-19 11:02:19 +0700
commit7d4445bb9bad3d6c945503086a07bd882536e5f6 (patch)
treea24e5b110887fd96ee7803c7857a254c3aeb9590 /src-migrate/modules/cart/components/ItemSelect.tsx
parent746a11b810ae9e8a974a76d0548297cd0faff9b5 (diff)
<miqdad> fix unresponsive cart select
Diffstat (limited to 'src-migrate/modules/cart/components/ItemSelect.tsx')
-rw-r--r--src-migrate/modules/cart/components/ItemSelect.tsx170
1 files changed, 126 insertions, 44 deletions
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;