summaryrefslogtreecommitdiff
path: root/src-migrate/modules/cart/components/ItemSelect.tsx
blob: 733ee64df7d7c7e271f8e1efc3fc73882ce4c906 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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;
};

const CartItemSelect = ({ item }: Props) => {
  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,
        });

        // 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);

        // Update cookie back
        updateSelectedItemInCookie(item.id, !newSelectedState);

        // 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 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;