// cart-cookie-utils.js import Cookies from 'js-cookie'; import checkboxUpdateState from './checkBoxState'; // Constants const CART_ITEMS_COOKIE = 'cart_data'; const SELECTED_ITEMS_COOKIE = 'cart_selected_items'; const COOKIE_EXPIRY_DAYS = 7; // Cookie akan berlaku selama 7 hari /** * Mengambil data cart lengkap dari cookie * @returns {Object} Object dengan key cart_id dan value cart item data lengkap */ export const getCartDataFromCookie = () => { try { const storedData = Cookies.get(CART_ITEMS_COOKIE); return storedData ? JSON.parse(storedData) : {}; } catch (error) { console.error('Error reading cart data from cookie:', error); return {}; } }; /** * Menyimpan data cart lengkap ke cookie * @param {Object} cartData Object dengan key cart_id dan value cart item data lengkap */ export const setCartDataToCookie = (cartData) => { try { Cookies.set(CART_ITEMS_COOKIE, JSON.stringify(cartData), { expires: COOKIE_EXPIRY_DAYS, path: '/', sameSite: 'strict', }); } catch (error) { console.error('Error saving cart data to cookie:', error); } }; /** * Mengambil state selected items dari cookie * @returns {Object} Object dengan key product id dan value boolean selected status */ export const getSelectedItemsFromCookie = () => { try { const storedItems = Cookies.get(SELECTED_ITEMS_COOKIE); return storedItems ? JSON.parse(storedItems) : {}; } catch (error) { console.error('Error reading selected items from cookie:', error); return {}; } }; /** * Menyimpan state selected items ke cookie * @param {Object} items Object dengan key product id dan value boolean selected status */ export const setSelectedItemsToCookie = (items) => { try { Cookies.set(SELECTED_ITEMS_COOKIE, JSON.stringify(items), { expires: COOKIE_EXPIRY_DAYS, path: '/', sameSite: 'strict', }); } catch (error) { console.error('Error saving selected items to cookie:', error); } }; /** * Transform cart items dari format API ke format yang lebih simpel untuk disimpan di cookie * @param {Array} cartItems Array cart items dari API * @returns {Object} Object dengan key cart_id dan value cart item data */ export const transformCartItemsForCookie = (cartItems) => { if (!cartItems || !Array.isArray(cartItems)) return {}; const cartData = {}; cartItems.forEach((item) => { // Skip items yang tidak memiliki cart_id if (!item.cart_id) return; cartData[item.cart_id] = { id: item.id, cart_id: item.cart_id, cart_type: item.cart_type, product: item.product_id ? { id: item.product_id, name: item.product_name || '', } : null, program_line: item.program_line_id ? { id: item.program_line_id, name: item.program_line_name || '', } : null, quantity: item.quantity, selected: item.selected, price: item.price, package_price: item.package_price, source: item.source || 'add_to_cart', }; }); return cartData; }; /** * Sinkronisasi cart data dan selected items dari server dengan cookie * @param {Object} cart Cart object dari API * @returns {Object} Object yang berisi updated cartData dan selectedItems */ export const syncCartWithCookie = (cart) => { try { if (!cart || !cart.products) return { needsUpdate: false }; // Transform data API ke cookie const serverCartData = transformCartItemsForCookie(cart.products); // Ambil data lama dari cookie const existingCartData = getCartDataFromCookie(); // Ambil selected status dari cookie const selectedItems = getSelectedItemsFromCookie(); // Gabungkan data cart, (prioritize data server) const mergedCartData = { ...existingCartData, ...serverCartData }; // Periksa apakah ada perbedaan status selected let needsUpdate = false; // Update selected status berdasarkan cookie jika ada for (const cartId in mergedCartData) { const item = mergedCartData[cartId]; if (item.id && selectedItems[item.id] !== undefined) { // Jika status di cookie berbeda dengan di cart if (item.selected !== selectedItems[item.id]) { needsUpdate = true; item.selected = selectedItems[item.id]; } } else if (item.id) { selectedItems[item.id] = item.selected; } } // Simpan ke cookie setCartDataToCookie(mergedCartData); setSelectedItemsToCookie(selectedItems); return { cartData: mergedCartData, selectedItems, needsUpdate, }; } catch (error) { console.error('Error syncing cart with cookie:', error); return { needsUpdate: false }; } }; /** * Update selected status item di cookie * @param {number} productId ID produk * @param {boolean} isSelected Status selected baru * @param {boolean} notifyUpdate Whether to notify checkbox update state (default: true) */ export const updateSelectedItemInCookie = ( productId, isSelected, notifyUpdate = true ) => { try { // Notify checkbox update state if requested if (notifyUpdate) { checkboxUpdateState.startUpdate(); } const selectedItems = getSelectedItemsFromCookie(); selectedItems[productId] = isSelected; setSelectedItemsToCookie(selectedItems); // Update juga di cart data const cartData = getCartDataFromCookie(); for (const cartId in cartData) { const item = cartData[cartId]; if (item.id === productId) { item.selected = isSelected; } } setCartDataToCookie(cartData); return { selectedItems, cartData }; } catch (error) { console.error('Error updating selected item in cookie:', error); return {}; } finally { // End update notification if requested if (notifyUpdate) { checkboxUpdateState.endUpdate(); } } }; /** * Set semua item menjadi selected atau unselected di cookie * @param {Array} productIds Array product IDs * @param {boolean} isSelected Status selected baru * @param {boolean} notifyUpdate Whether to notify checkbox update state (default: true) */ export const setAllSelectedInCookie = ( productIds, isSelected, notifyUpdate = true ) => { try { // Notify checkbox update state if requested if (notifyUpdate) { checkboxUpdateState.startUpdate(); } const selectedItems = getSelectedItemsFromCookie(); productIds.forEach((id) => { if (id) selectedItems[id] = isSelected; }); setSelectedItemsToCookie(selectedItems); // Update juga di cart data const cartData = getCartDataFromCookie(); for (const cartId in cartData) { if (productIds.includes(cartData[cartId].id)) { cartData[cartId].selected = isSelected; } } setCartDataToCookie(cartData); return { selectedItems, cartData }; } catch (error) { console.error('Error setting all selected in cookie:', error); return {}; } finally { // End update notification if requested if (notifyUpdate) { checkboxUpdateState.endUpdate(); } } }; /** * Hapus item dari cookie * @param {Array} cartIds Array cart IDs untuk dihapus */ export const removeCartItemsFromCookie = (cartIds) => { try { const cartData = getCartDataFromCookie(); const selectedItems = getSelectedItemsFromCookie(); const productIdsToRemove = []; // Hapus item dari cartData dan catat product IDs cartIds.forEach((cartId) => { if (cartData[cartId]) { if (cartData[cartId].id) { productIdsToRemove.push(cartData[cartId].id); } delete cartData[cartId]; } }); // Hapus dari selectedItems productIdsToRemove.forEach((productId) => { if (selectedItems[productId] !== undefined) { delete selectedItems[productId]; } }); // Simpan kembali ke cookie setCartDataToCookie(cartData); setSelectedItemsToCookie(selectedItems); return { cartData, selectedItems }; } catch (error) { console.error('Error removing cart items from cookie:', error); return {}; } }; /** * Hapus item selected dari cookie berdasarkan product IDs * @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 */ /** * Force reset semua selected items ke unselected state */ export const forceResetAllSelectedItems = () => { try { checkboxUpdateState.startUpdate(); const cartData = getCartDataFromCookie(); const selectedItems = {}; // Reset semua selected status di cartData for (const cartId in cartData) { cartData[cartId].selected = false; if (cartData[cartId].id) { selectedItems[cartData[cartId].id] = false; } } // Simpan kembali ke cookie setCartDataToCookie(cartData); setSelectedItemsToCookie(selectedItems); return { cartData, selectedItems }; } catch (error) { console.error('Error resetting all selected items:', error); return {}; } finally { checkboxUpdateState.endUpdate(); } }; /** * Sync selected items between cookie and cart data * @param {Array} cartProducts Products array from cart */ export const syncSelectedItemsWithCookie = (cartProducts) => { try { if (!cartProducts || !Array.isArray(cartProducts)) { return { items: {}, needsUpdate: false }; } const selectedItems = getSelectedItemsFromCookie(); let needsUpdate = false; // Check if we need to update any items based on cookie values cartProducts.forEach((product) => { if (product.id && selectedItems[product.id] !== undefined) { if (product.selected !== selectedItems[product.id]) { needsUpdate = true; } } else if (product.id) { // If not in cookie, add with current value selectedItems[product.id] = product.selected; } }); // Update the cookie with the latest values setSelectedItemsToCookie(selectedItems); return { items: selectedItems, needsUpdate }; } catch (error) { console.error('Error syncing selected items with cookie:', error); return { items: {}, needsUpdate: false }; } }; // 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 {}; } }; class QuantityUpdateState { constructor() { this.updateItems = new Set(); this.listeners = new Set(); } startUpdate(itemId) { this.updateItems.add(itemId); this.notifyListeners(); } endUpdate(itemId) { this.updateItems.delete(itemId); this.notifyListeners(); } isAnyQuantityUpdating() { return this.updateItems.size > 0; } isItemUpdating(itemId) { return this.updateItems.has(itemId); } addListener(callback) { this.listeners.add(callback); } removeListener(callback) { this.listeners.delete(callback); } notifyListeners() { const isUpdating = this.isAnyQuantityUpdating(); this.listeners.forEach(callback => callback(isUpdating)); } } export const quantityUpdateState = new QuantityUpdateState();