// Ported from legacy henza_admin/src/store/cart/cart.js // // The admin-side order builder's basket. Behaviour is preserved exactly, // including the two guards legacy applied: // - ADD_TO_CART refuses an out-of-stock variant that is not a pre-order // (`!variant.is_pre_order && variant.qty === 0`) // - init() re-fetches every cart product and drops any that became // out-of-stock while the basket sat in localStorage // // Storage key differs per mode ('admin_cart_items' vs 'branch_cart_items'), // as in legacy. import { defineStore } from 'pinia'; import api from '../api/client'; import { isBranch } from '../utils'; const cartKey = isBranch() ? 'branch_cart_items' : 'admin_cart_items'; export interface CartVariant { id: string; is_pre_order?: boolean; qty?: number; price?: number; price_with_discount?: number; grams?: number; title?: string; } export interface CartProduct { id: string; variants_all: CartVariant[]; promotion?: { id: string } | null; [k: string]: unknown; } export interface CartItem { vid: string; pid: string; product: CartProduct; qty: number; promotion_id?: string | null; } export const useCartStore = defineStore('cart', { state: () => ({ items: [] as CartItem[], }), actions: { /** legacy mutation ADD_TO_CART */ addToCart(data: CartItem) { const index = this.items.findIndex((item) => item.pid == data.pid && item.vid == data.vid); const variant = data.product.variants_all.filter((x) => x.id === data.vid)[0]; // legacy guard: reject an out-of-stock, non-pre-order variant if (variant && !(!variant.is_pre_order && variant.qty === 0)) { if (index == -1) { this.items.push(data); } else { this.items[index].product = data.product; this.items[index].qty = data.qty; } } }, /** legacy mutation INIT — also persists to localStorage */ setItems(res: CartItem[]) { this.items = res; localStorage.setItem(cartKey, JSON.stringify(res)); }, add(data: CartItem) { this.addToCart(data); this.setItems(this.items); }, remove(item: { pid: string; vid: string }) { const index = this.items.findIndex((v) => v.pid == item.pid && v.vid == item.vid); if (index > -1) this.items.splice(index, 1); this.setItems(this.items); }, updateItemQuantity(payload: { index: number; quantity: number }) { this.items[payload.index].qty = payload.quantity; this.setItems(this.items); }, clear() { this.items = []; this.setItems(this.items); }, /** * legacy init(): rehydrate from localStorage, then re-fetch each product so * prices and stock are current, dropping anything now out of stock. */ async init() { try { const items: CartItem[] = JSON.parse(localStorage.getItem(cartKey) ?? '[]') || []; const ids = items.map((item) => item.product.id); if (ids.length === 0) { this.setItems([]); return; } const { data } = await api.post('product/variant', { products_id: ids }); if (data) { const exp: CartItem[] = []; for (const cartItem of items) { const product = (data as CartProduct[]).find((item) => item.id == cartItem.product.id); if (!product) continue; if (!(!product.variants_all[0].is_pre_order && product.variants_all[0].qty === 0)) { exp.push({ vid: cartItem.vid, pid: product.id, product, qty: cartItem.qty, promotion_id: product.promotion && product.promotion.id ? product.promotion.id : null, }); } } this.setItems(exp); } } catch (e) { console.log('error in cart', e); } }, }, });