summaryrefslogtreecommitdiff
path: root/src-migrate
diff options
context:
space:
mode:
Diffstat (limited to 'src-migrate')
-rw-r--r--src-migrate/modules/cart/components/ItemAction.tsx139
-rw-r--r--src-migrate/modules/cart/components/ItemSelect.tsx2
-rw-r--r--src-migrate/pages/shop/cart/index.tsx36
-rw-r--r--src-migrate/utils/cart.js68
4 files changed, 174 insertions, 71 deletions
diff --git a/src-migrate/modules/cart/components/ItemAction.tsx b/src-migrate/modules/cart/components/ItemAction.tsx
index 7220e362..eea0cbe9 100644
--- a/src-migrate/modules/cart/components/ItemAction.tsx
+++ b/src-migrate/modules/cart/components/ItemAction.tsx
@@ -1,74 +1,121 @@
-import style from '../styles/item-action.module.css'
+import style from '../styles/item-action.module.css';
-import React, { useEffect, useState } from 'react'
+import React, { useEffect, useState } from 'react';
-import { Spinner, Tooltip } from '@chakra-ui/react'
-import { MinusIcon, PlusIcon, Trash2Icon } from 'lucide-react'
+import { Spinner, Tooltip } from '@chakra-ui/react';
+import { MinusIcon, PlusIcon, Trash2Icon } from 'lucide-react';
-import { CartItem } from '~/types/cart'
-import { getAuth } from '~/libs/auth'
-import { deleteUserCart, upsertUserCart } from '~/services/cart'
+import { CartItem } from '~/types/cart';
+import { getAuth } from '~/libs/auth';
+import { deleteUserCart, upsertUserCart } from '~/services/cart';
-import { useDebounce } from 'usehooks-ts'
-import { useCartStore } from '../stores/useCartStore'
-import { useProductCartContext } from '@/contexts/ProductCartContext'
+import { useDebounce } from 'usehooks-ts';
+import { useCartStore } from '../stores/useCartStore';
+import { useProductCartContext } from '@/contexts/ProductCartContext';
+import {
+ removeSelectedItemsFromCookie,
+ removeCartItemsFromCookie,
+} from '~/utils/cart';
+import { toast } from 'react-hot-toast';
type Props = {
- item: CartItem
-}
+ item: CartItem;
+};
const CartItemAction = ({ item }: Props) => {
- const auth = getAuth()
- const { setRefreshCart } = useProductCartContext()
- const [isLoadDelete, setIsLoadDelete] = useState<boolean>(false)
- const [isLoadQuantity, setIsLoadQuantity] = useState<boolean>(false)
+ const auth = getAuth();
+ const { setRefreshCart } = useProductCartContext();
+ const [isLoadDelete, setIsLoadDelete] = useState<boolean>(false);
+ const [isLoadQuantity, setIsLoadQuantity] = useState<boolean>(false);
- const [quantity, setQuantity] = useState<number>(item.quantity)
+ const [quantity, setQuantity] = useState<number>(item.quantity);
- const { loadCart } = useCartStore()
+ const { loadCart, cart, updateCartItem } = useCartStore(); // TAMBAHKAN cart dan updateCartItem
- const limitQty = item.limit_qty?.transaction || 0
+ const limitQty = item.limit_qty?.transaction || 0;
+ // PERBAIKI FUNCTION INI
const handleDelete = async () => {
- if (typeof auth !== 'object') return
-
- setIsLoadDelete(true)
- await deleteUserCart(auth.id, [item.cart_id])
- await loadCart(auth.id)
- setIsLoadDelete(false)
- setRefreshCart(true)
- }
-
- const decreaseQty = () => { setQuantity((quantity) => quantity -= 1) }
- const increaseQty = () => { setQuantity((quantity) => quantity += 1) }
- const debounceQty = useDebounce(quantity, 1000)
+ if (typeof auth !== 'object') return;
+
+ setIsLoadDelete(true);
+
+ try {
+ // Step 1: Delete from server
+ await deleteUserCart(auth.id, [item.cart_id]);
+
+ // Step 2: Clean up cookies IMMEDIATELY
+ removeSelectedItemsFromCookie([item.id]);
+ removeCartItemsFromCookie([item.cart_id]);
+
+ // Step 3: Update local cart state optimistically
+ if (cart) {
+ const updatedProducts = cart.products.filter(
+ (product) => product.id !== item.id
+ );
+ const updatedCart = {
+ ...cart,
+ products: updatedProducts,
+ product_total: updatedProducts.length,
+ };
+ updateCartItem(updatedCart);
+ }
+
+ // Step 4: Reload from server to ensure consistency
+ await loadCart(auth.id);
+ setRefreshCart(true);
+
+ toast.success('Item berhasil dihapus');
+ } catch (error) {
+ console.error('Failed to delete cart item:', error);
+ toast.error('Gagal menghapus item');
+
+ // Reload on error
+ await loadCart(auth.id);
+ } finally {
+ setIsLoadDelete(false);
+ }
+ };
+
+ const decreaseQty = () => {
+ setQuantity((quantity) => (quantity -= 1));
+ };
+ const increaseQty = () => {
+ setQuantity((quantity) => (quantity += 1));
+ };
+ const debounceQty = useDebounce(quantity, 1000);
+
useEffect(() => {
- if (isNaN(debounceQty)) setQuantity(1)
- if (limitQty > 0 && debounceQty > limitQty) setQuantity(limitQty)
- }, [debounceQty, limitQty])
+ if (isNaN(debounceQty)) setQuantity(1);
+ if (limitQty > 0 && debounceQty > limitQty) setQuantity(limitQty);
+ }, [debounceQty, limitQty]);
useEffect(() => {
const updateCart = async () => {
- if (typeof auth !== 'object' || isNaN(debounceQty)) return
+ if (typeof auth !== 'object' || isNaN(debounceQty)) return;
- setIsLoadQuantity(true)
+ 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)
- }
- updateCart()
+ });
+ await loadCart(auth.id);
+ setIsLoadQuantity(false);
+ };
+ updateCart();
//eslint-disable-next-line react-hooks/exhaustive-deps
- }, [debounceQty])
+ }, [debounceQty]);
return (
<div className={style.actionSection}>
- <button className={style.deleteButton} onClick={handleDelete} disabled={isLoadDelete}>
+ <button
+ className={style.deleteButton}
+ onClick={handleDelete}
+ disabled={isLoadDelete}
+ >
{isLoadDelete && <Spinner size='xs' />}
{!isLoadDelete && <Trash2Icon size={16} />}
</button>
@@ -106,7 +153,7 @@ const CartItemAction = ({ item }: Props) => {
</Tooltip>
</div>
</div>
- )
-}
+ );
+};
-export default CartItemAction \ No newline at end of file
+export default CartItemAction;
diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx
index 70b656ec..f580f81d 100644
--- a/src-migrate/modules/cart/components/ItemSelect.tsx
+++ b/src-migrate/modules/cart/components/ItemSelect.tsx
@@ -109,7 +109,7 @@ const CartItemSelect = ({ item }: Props) => {
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, // Ensure null for numeric fields
});
// Reload cart to ensure consistency
diff --git a/src-migrate/pages/shop/cart/index.tsx b/src-migrate/pages/shop/cart/index.tsx
index eefe8d09..798ad318 100644
--- a/src-migrate/pages/shop/cart/index.tsx
+++ b/src-migrate/pages/shop/cart/index.tsx
@@ -329,24 +329,52 @@ const CartPage = () => {
if (typeof auth !== 'object' || !cart) return;
setIsLoadDelete(true);
- checkboxUpdateState.startUpdate('delete_operation'); // Use special ID for delete
+ checkboxUpdateState.startUpdate('delete_operation');
try {
const itemsToDelete = cart.products.filter((item) => item.selected);
const itemIdsToDelete = itemsToDelete.map((item) => item.id);
+ const cartIdsToDelete = itemsToDelete.map((item) => item.cart_id);
+ // Step 1: Delete from server first
for (const item of itemsToDelete) {
await deleteUserCart(auth.id, [item.cart_id]);
}
- // Remove deleted items from cookie
- removeSelectedItemsFromCookie(itemIdsToDelete);
+ // Step 2: Update local cart state immediately (optimistic update)
+ const updatedProducts = cart.products.filter((item) => !item.selected);
+ const updatedCart = {
+ ...cart,
+ products: updatedProducts,
+ product_total: updatedProducts.length,
+ };
+ updateCartItem(updatedCart);
- await loadCart(auth.id);
+ // Step 3: Clean up cookies AFTER state update
+ removeSelectedItemsFromCookie(itemIdsToDelete);
+ removeCartItemsFromCookie(cartIdsToDelete);
+
+ // Step 4: Reload from server to ensure consistency (but don't wait for it to complete UI update)
+ loadCart(auth.id)
+ .then(() => {
+ console.log('Cart reloaded from server');
+ })
+ .catch((error) => {
+ console.error('Error reloading cart:', error);
+ // If reload fails, at least we have the optimistic update
+ });
+
+ // Step 5: Trigger context refresh
setRefreshCart(true);
+
+ // Success feedback
+ toast.success('Item berhasil dihapus');
} catch (error) {
console.error('Failed to delete cart items:', error);
toast.error('Gagal menghapus item');
+
+ // If deletion failed, reload cart to restore proper state
+ loadCart(auth.id);
} finally {
setIsLoadDelete(false);
checkboxUpdateState.endUpdate('delete_operation');
diff --git a/src-migrate/utils/cart.js b/src-migrate/utils/cart.js
index f474cbde..1ddc5446 100644
--- a/src-migrate/utils/cart.js
+++ b/src-migrate/utils/cart.js
@@ -297,26 +297,10 @@ export const removeCartItemsFromCookie = (cartIds) => {
* Hapus item selected dari cookie berdasarkan product IDs
* @param {Array} productIds Array product IDs untuk dihapus
*/
-export const removeSelectedItemsFromCookie = (productIds) => {
- try {
- const selectedItems = getSelectedItemsFromCookie();
-
- // Hapus dari selectedItems
- productIds.forEach((productId) => {
- if (selectedItems[productId] !== undefined) {
- delete selectedItems[productId];
- }
- });
-
- // Simpan kembali ke cookie
- setSelectedItemsToCookie(selectedItems);
-
- return { selectedItems };
- } catch (error) {
- console.error('Error removing selected items from cookie:', error);
- return {};
- }
-};
+/**
+ * Hapus item selected dari cookie berdasarkan product IDs dan juga hapus dari cart data
+ * @param {Array} productIds Array product IDs untuk dihapus
+ */
/**
* Force reset semua selected items ke unselected state
@@ -386,3 +370,47 @@ export const syncSelectedItemsWithCookie = (cartProducts) => {
// Export the checkbox update state for use in components
export { checkboxUpdateState };
+
+/**
+ * Hapus item selected dari cookie berdasarkan product IDs dan juga hapus dari cart data
+ * @param {Array} productIds Array product IDs untuk dihapus
+ */
+/**
+ * Hapus item selected dari cookie berdasarkan product IDs dan juga hapus dari cart data
+ * @param {Array} productIds Array product IDs untuk dihapus
+ */
+export const removeSelectedItemsFromCookie = (productIds) => {
+ try {
+ const selectedItems = getSelectedItemsFromCookie();
+ const cartData = getCartDataFromCookie();
+ const cartIdsToRemove = [];
+
+ // Find cart IDs that match the product IDs
+ for (const cartId in cartData) {
+ if (productIds.includes(cartData[cartId].id)) {
+ cartIdsToRemove.push(cartId);
+ }
+ }
+
+ // Remove from selectedItems
+ productIds.forEach((productId) => {
+ if (selectedItems[productId] !== undefined) {
+ delete selectedItems[productId];
+ }
+ });
+
+ // Remove from cartData
+ cartIdsToRemove.forEach((cartId) => {
+ delete cartData[cartId];
+ });
+
+ // Save both cookies
+ setSelectedItemsToCookie(selectedItems);
+ setCartDataToCookie(cartData);
+
+ return { selectedItems, cartData };
+ } catch (error) {
+ console.error('Error removing selected items from cookie:', error);
+ return {};
+ }
+};