summaryrefslogtreecommitdiff
path: root/src-migrate/modules/cart/components
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-05-26 20:00:17 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-05-26 20:00:17 +0700
commit3feaad9127ff429b27f0eb69fa6ea539de2f2e8c (patch)
treed2b65790861531e08fd9eb3e1d1cd64eb5805e15 /src-migrate/modules/cart/components
parentcca6d803fc4db729865def23004ab1c4bd279e24 (diff)
<miqdad> Cleaning code
Diffstat (limited to 'src-migrate/modules/cart/components')
-rw-r--r--src-migrate/modules/cart/components/ItemAction.tsx125
-rw-r--r--src-migrate/modules/cart/components/ItemSelect.tsx76
2 files changed, 134 insertions, 67 deletions
diff --git a/src-migrate/modules/cart/components/ItemAction.tsx b/src-migrate/modules/cart/components/ItemAction.tsx
index eea0cbe9..4dcebd9e 100644
--- a/src-migrate/modules/cart/components/ItemAction.tsx
+++ b/src-migrate/modules/cart/components/ItemAction.tsx
@@ -15,7 +15,11 @@ import { useProductCartContext } from '@/contexts/ProductCartContext';
import {
removeSelectedItemsFromCookie,
removeCartItemsFromCookie,
+ quantityUpdateState,
+ getCartDataFromCookie,
+ setCartDataToCookie,
} from '~/utils/cart';
+
import { toast } from 'react-hot-toast';
type Props = {
@@ -30,25 +34,24 @@ const CartItemAction = ({ item }: Props) => {
const [quantity, setQuantity] = useState<number>(item.quantity);
- const { loadCart, cart, updateCartItem } = useCartStore(); // TAMBAHKAN cart dan updateCartItem
+ const { loadCart, cart, updateCartItem } = useCartStore();
const limitQty = item.limit_qty?.transaction || 0;
- // PERBAIKI FUNCTION INI
const handleDelete = async () => {
if (typeof auth !== 'object') return;
setIsLoadDelete(true);
try {
- // Step 1: Delete from server
+ // Delete from server
await deleteUserCart(auth.id, [item.cart_id]);
- // Step 2: Clean up cookies IMMEDIATELY
+ // Clean up cookies immediately
removeSelectedItemsFromCookie([item.id]);
removeCartItemsFromCookie([item.cart_id]);
- // Step 3: Update local cart state optimistically
+ // Update local cart state optimistically
if (cart) {
const updatedProducts = cart.products.filter(
(product) => product.id !== item.id
@@ -61,7 +64,7 @@ const CartItemAction = ({ item }: Props) => {
updateCartItem(updatedCart);
}
- // Step 4: Reload from server to ensure consistency
+ // Reload from server and refresh context
await loadCart(auth.id);
setRefreshCart(true);
@@ -77,12 +80,47 @@ const CartItemAction = ({ item }: Props) => {
}
};
+ 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(() => {
@@ -93,18 +131,73 @@ const CartItemAction = ({ item }: Props) => {
useEffect(() => {
const updateCart = async () => {
if (typeof auth !== 'object' || isNaN(debounceQty)) return;
+ if (debounceQty === item.quantity) return;
+ quantityUpdateState.startUpdate(item.id);
setIsLoadQuantity(true);
- await upsertUserCart({
- userId: auth.id,
- type: item.cart_type,
- id: item.id,
- qty: debounceQty,
- selected: item.selected,
- });
- await loadCart(auth.id);
- setIsLoadQuantity(false);
+
+ 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]);
@@ -156,4 +249,4 @@ const CartItemAction = ({ item }: Props) => {
);
};
-export default CartItemAction;
+export default CartItemAction; \ No newline at end of file
diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 00c7be43..8dbfe2bc 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -20,124 +20,98 @@ const CartItemSelect = ({ item }: Props) => {
const { updateCartItem, cart, loadCart } = useCartStore();
const [isUpdating, setIsUpdating] = useState<boolean>(false);
const [localSelected, setLocalSelected] = useState<boolean>(item.selected);
- const [isGlobalUpdating, setIsGlobalUpdating] = useState<boolean>(false);
// Subscribe to global checkbox update state
useEffect(() => {
const handleUpdateStateChange = (isUpdating) => {
- setIsGlobalUpdating(isUpdating);
+ // This component doesn't need to react to global state changes
+ // Individual checkboxes are managed independently
};
checkboxUpdateState.addListener(handleUpdateStateChange);
-
- return () => {
- checkboxUpdateState.removeListener(handleUpdateStateChange);
- };
+ return () => checkboxUpdateState.removeListener(handleUpdateStateChange);
}, []);
- // Initialize local state from cookie or server
+ // Sync local state with cookie and server data
useEffect(() => {
- if (isUpdating) return; // Skip if we're currently updating
+ if (isUpdating) return;
- // Check cookie first
const selectedItems = getSelectedItemsFromCookie();
const storedState = selectedItems[item.id];
if (storedState !== undefined) {
- // Only update local state if it differs from current state
+ // Update local state if cookie differs
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);
- }
+ // Sync cart state with cookie if needed
+ if (storedState !== item.selected && cart) {
+ const updatedCartItems = cart.products.map((cartItem) =>
+ cartItem.id === item.id
+ ? { ...cartItem, selected: storedState }
+ : cartItem
+ );
+ updateCartItem({ ...cart, products: updatedCartItems });
}
} else {
- // Fall back to server state if no cookie exists
+ // Initialize cookie with server state
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<HTMLInputElement>) => {
- if (typeof auth !== 'object' || !cart || isUpdating) {
- return;
- }
+ if (typeof auth !== 'object' || !cart || isUpdating) return;
const newSelectedState = e.target.checked;
- // Update local state immediately for responsiveness
+ // Update local state immediately
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 cookie immediately for responsive UI
+ updateSelectedItemInCookie(item.id, newSelectedState, false);
- // Update cart state immediately for UI responsiveness
+ // Update cart state optimistically
const updatedCartItems = cart.products.map((cartItem) =>
cartItem.id === item.id
? { ...cartItem, selected: newSelectedState }
: cartItem
);
+ updateCartItem({ ...cart, products: updatedCartItems });
- const updatedCart = { ...cart, products: updatedCartItems };
- updateCartItem(updatedCart);
-
- // Save to server
+ // Send update 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
+ purchase_tax_id: item.purchase_tax_id || null,
});
- // Reload cart to ensure consistency
+ // Reload cart for 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
+ // Revert changes 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);