Files
tehran_taj/apps/admin-panel/src/stores/cart.ts
T

126 lines
3.8 KiB
TypeScript

// 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);
}
},
},
});