import { create } from 'zustand'; import { CartItem, CartProps } from '~/types/cart'; import { getUserCart } from '~/services/cart'; import { syncCartWithCookie, getCartDataFromCookie, getSelectedItemsFromCookie, forceResetAllSelectedItems, } from '~/utils/cart'; interface Summary { subtotal: number; discount: number; total: number; tax: number; grandTotal: number; } interface SyncResult { cartData?: Record; selectedItems?: Record; needsUpdate: boolean; } interface State { cart: CartProps | null; isLoadCart: boolean; summary: Summary; } interface Action { loadCart: (userId: number) => Promise; updateCartItem: (updateCart: CartProps) => void; forceResetSelection: () => void; clearCart: () => void; } export const useCartStore = create((set, get) => ({ cart: null, isLoadCart: false, summary: { subtotal: 0, discount: 0, total: 0, tax: 0, grandTotal: 0, }, loadCart: async (userId: number): Promise => { if (get().isLoadCart) return; set({ isLoadCart: true }); try { const cart: CartProps = (await getUserCart(userId)) as CartProps; // Sync with cookie data const syncResult = syncCartWithCookie(cart) as SyncResult; if (syncResult?.needsUpdate && cart.products) { const selectedItems = getSelectedItemsFromCookie() as Record< number, boolean >; const updatedCart: CartProps = { ...cart, products: cart.products.map((item) => ({ ...item, selected: selectedItems[item.id] !== undefined ? selectedItems[item.id] : item.selected, })), }; set({ cart: updatedCart }); } else { set({ cart }); } // Update summary const summary = computeSummary(get().cart!); set({ summary }); } catch (error) { console.error('Failed to load cart:', error); // Fallback to cookie data await handleFallbackFromCookie(); } finally { set({ isLoadCart: false }); } }, updateCartItem: (updatedCart: CartProps): void => { set({ cart: updatedCart }); syncCartWithCookie(updatedCart); const summary = computeSummary(updatedCart); set({ summary }); }, forceResetSelection: (): void => { const { cart } = get(); if (!cart) return; forceResetAllSelectedItems(); const updatedCart: CartProps = { ...cart, products: cart.products.map((item) => ({ ...item, selected: false })), }; set({ cart: updatedCart }); const summary = computeSummary(updatedCart); set({ summary }); }, clearCart: (): void => { set({ cart: null, summary: { subtotal: 0, discount: 0, total: 0, tax: 0, grandTotal: 0, }, }); }, })); // Helper function for cookie fallback const handleFallbackFromCookie = async (): Promise => { try { const cartData = getCartDataFromCookie() as Record; if (Object.keys(cartData).length === 0) return; const products: CartItem[] = Object.values(cartData).map( transformCookieItemToProduct ); const fallbackCart: CartProps = { product_total: products.length, products, }; useCartStore.setState({ cart: fallbackCart }); const summary = computeSummary(fallbackCart); useCartStore.setState({ summary }); } catch (error) { console.error('Cookie fallback failed:', error); } }; // Helper function to transform cookie item to product format const transformCookieItemToProduct = (item: any): CartItem => ({ image_program: item.image_program || '', cart_id: item.cart_id, quantity: item.quantity, selected: item.selected, can_buy: true, cart_type: item.cart_type, id: item.id, name: item.product?.name || item.program_line?.name || '', stock: 0, is_in_bu: false, on_hand_qty: 0, available_quantity: 0, weight: 0, attributes: [], parent: { id: 0, name: '', image: '', }, price: item.price || { price: 0, discount_percentage: 0, price_discount: 0, }, manufacture: { id: 0, name: '', }, has_flashsale: false, subtotal: 0, code: item.code, image: item.image, package_price: item.package_price, }); const computeSummary = (cart: CartProps): Summary => { if (!cart?.products) { return { subtotal: 0, discount: 0, total: 0, grandTotal: 0, tax: 0 }; } const PPN = parseFloat(process.env.NEXT_PUBLIC_PPN || '1.11'); let subtotal = 0; let discount = 0; for (const item of cart.products) { if (!item.selected) continue; const price = item.cart_type === 'promotion' ? (item?.package_price || 0) * item.quantity : item.price.price * item.quantity; subtotal += price; discount += price - item.price.price_discount * item.quantity; } const total = subtotal - discount; // PERBAIKAN: const tax = total * (PPN - 1); const grandTotal = total + tax; return { subtotal, discount, total, grandTotal, tax }; };