UNPKG

@etsoo/appscript

Version:

Applications shared TypeScript framework

500 lines (499 loc) 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ShoppingCart = void 0; const shared_1 = require("@etsoo/shared"); const ShoppingCartKeyField = "ETSOO-CART-KEYS"; /** * Shopping cart * 购物篮 */ class ShoppingCart { /** * Create identifier key * 创建识别键 * @param currency Currency * @param culture Culture * @param key Additional key * @returns Result */ static createKey(currency, culture, key) { return `ETSOO-CART-${culture}-${key}-${currency}`; } /** * Clear shopping cart * 清除购物篮 * @param identifier Identifier * @param storage Storage */ static clear(identifier, storage) { try { storage.setData(identifier, null); storage.setPersistedData(identifier, null); } catch (error) { console.warn(`ShoppingCart clear ${identifier} error`, error); } } /** * Get cart data * 获取购物篮数据 * @param storage Storage * @param id Cart id * @returns Result */ static getCartData(storage, id) { try { return (storage.getPersistedObject(id) ?? storage.getObject(id)); } catch (error) { console.warn(`ShoppingCart getCartData ${id} error`, error); } } /** * ISO currency id * 标准货币编号 */ get currency() { return this._currency; } set currency(value) { this._currency = value; } /** * ISO culture id, like zh-Hans * 标准语言文化编号 */ get culture() { return this._culture; } set culture(value) { this._culture = value; } /** * Items * 项目 */ get items() { return this._items; } set items(value) { this._items = value; } /** * Order level promotions * 订单层面促销 */ get promotions() { return this._promotions; } set promotions(value) { this._promotions = value; } /** * Currency symbol * 币种符号 */ get symbol() { return this._symbol; } set symbol(value) { this._symbol = value; } /** * Cart identifier * 购物篮标识 */ get identifier() { const o = this.owner; return ShoppingCart.createKey(this.currency, this.culture, this.key); } /** * All data keys * 所有的数据键 */ get keys() { return this.storage.getPersistedData(ShoppingCartKeyField, []); } set keys(items) { this.storage.setPersistedData(ShoppingCartKeyField, items); } /** * Lines count * 项目数量 */ get lines() { return this.items.length; } /** * Total qty * 总数量 */ get totalQty() { return this.items.map((item) => item.qty).sum(); } /** * Total amount * 总金额 */ get totalAmount() { const subtotal = this.items .map((item) => item.subtotal - item.discount) .sum(); const discount = this.promotions.sum("amount"); return subtotal - discount; } /** * Total amount string * 总金额字符串 */ get totalAmountStr() { return this.formatAmount(this.totalAmount); } /** * Constructor * 构造函数 * @param key Key for identifier * @param currency Currency ISO code * @param storage Data storage */ constructor(key, currencyOrState, storage = new shared_1.WindowStorage()) { this.storage = storage; this._items = []; this._promotions = []; /** * Cached prices * 缓存的价格 */ this.prices = {}; this.key = key; if (Array.isArray(currencyOrState)) { this.reset(currencyOrState[0], currencyOrState[1]); } else { this.setCartData(currencyOrState); this.changeCurrency(currencyOrState.currency); this.changeCulture(currencyOrState.culture); } } getCartData() { return (this.storage.getPersistedObject(this.identifier) ?? this.storage.getObject(this.identifier)); } setCartData(state) { const { owner, items = [], promotions = [], formData, cache } = state ?? {}; this.owner = owner; this.items = items; this.promotions = promotions; this.formData = formData; this.cache = cache; } doChange(reason, changedItems) { if (this.onChange) this.onChange(reason, changedItems); } /** * Add item * 添加项目 * @param item New item */ addItem(item) { this.addItems([item]); } /** * Add items * @param items New items */ addItems(items) { this.items.push(...items); this.doChange("add", items); } /** * Cache price * @param id Item id * @param price Price * @param overrideExisting Override existing price */ cachePrice(id, price, overrideExisting = false) { if (overrideExisting || this.prices[id] == null) this.prices[id] = price; } /** * Change currency * @param currency Currency */ changeCurrency(currency) { this.currency = currency; this.symbol = shared_1.NumberUtils.getCurrencySymbol(this.currency); } /** * Change culture * @param culture Culture */ changeCulture(culture) { this.culture = culture; } /** * Clear storage * @param keepOwner Keep owner data */ clear(keepOwner) { this.items.length = 0; this.promotions.length = 0; this.prices = {}; this.cache = undefined; if (keepOwner) { this.save(); } else { ShoppingCart.clear(this.identifier, this.storage); this.keys.remove(this.identifier); } this.doChange("clear", []); } /** * Format amount * @param amount Amount * @returns Result */ formatAmount(amount) { return shared_1.NumberUtils.formatMoney(amount, this.currency); } /** * Get item * @param id Item id * @returns Result */ getItem(id) { return this.items.find((item) => item.id === id); } /** * Push item * 推送项目 * @param data Item data * @returns Added or not */ pushItem(data) { if (this.items.some((item) => item.id === data.id)) { return false; } else { this.addItem(data); return true; } } /** * Reset currency and culture * @param currency New currency * @param culture New culture */ reset(currency, culture) { this.changeCurrency(currency); this.changeCulture(culture); this.setCartData(this.getCartData()); } /** * Remove item from the index * @param index Item index */ removeItem(index) { const removedItems = this.items.splice(index, 1); this.doChange("remove", removedItems); } /** * Reset item * @param item Shopping cart item */ resetItem(item) { item.discount = 0; item.currentPrice = undefined; item.promotions = []; } /** * Save cart data * @param persisted For persisted storage */ save(persisted = true) { if (this.owner == null) return; const { currency, culture, owner, items, promotions, formData, cache } = this; const data = { currency, culture, owner, items, promotions, formData, cache }; try { if (persisted) { this.storage.setPersistedData(this.identifier, data); const keys = this.keys; if (!keys.includes(this.identifier)) { keys.push(this.identifier); this.keys = keys; } } else { this.storage.setData(this.identifier, data); } } catch (error) { console.warn(`ShoppingCart save ${this.identifier} error`, error); } return data; } /** * Trigger update * 触发更新 */ update() { this.doChange("update", []); } /** * Update discount * @param item Shopping cart item */ updateDiscount(item) { item.discount = item.promotions.sum("amount"); } /** * Update asset item * 更新资产项目 * @param id Product id * @param qty Asset qty * @param itemCreator New item creator * @returns Updated or not */ updateAssetItem(id, assetQty, itemCreator) { if (assetQty == null || assetQty <= 0) assetQty = 1; const index = this.items.findIndex((item) => item.id === id); if (index === -1) { // New if (itemCreator) { const price = this.prices[id]; const data = itemCreator(); const qty = data.qty; const newItem = { ...data, id, price, assetQty, subtotal: price * qty * assetQty, discount: 0, promotions: Array() }; this.addItem(newItem); } return false; } else { // Update const item = this.items[index]; // Price may be cached first const price = this.prices[id] ?? item.price; const qty = item.qty; const newItem = { ...item, price, assetQty, subtotal: price * qty * assetQty, discount: 0 }; this.items.splice(index, 1, newItem); this.doChange("update", [item, newItem]); } return true; } /** * Update item * 更新项目 * @param id Product id * @param qty Qty * @param itemCreator New item creator * @returns Updated or not */ updateItem(id, qty, itemCreator) { const index = this.items.findIndex((item) => item.id === id); if (qty == null) { // Remove the item if (index !== -1) { this.removeItem(index); } } else if (index === -1) { // New if (itemCreator) { const price = this.prices[id]; const data = itemCreator(); const newItem = { ...data, id, price, qty, subtotal: price * qty * (data.assetQty || 1), discount: 0, promotions: Array() }; this.addItem(newItem); } return false; } else { // Update const item = this.items[index]; // Price may be cached first const price = this.prices[id] ?? item.price; const newItem = { ...item, qty, price, subtotal: price * qty * (item.assetQty || 1), discount: 0 }; this.items.splice(index, 1, newItem); this.doChange("update", [item, newItem]); } return true; } /** * Update price * @param id Item id * @param price New price */ updatePrice(id, price) { this.cachePrice(id, price, true); const index = this.items.findIndex((item) => item.id === id); if (index !== -1) { const item = this.items[index]; const qty = item.qty; const assetQty = item.assetQty || 1; const newItem = { ...item, price, subtotal: price * qty * assetQty }; this.items.splice(index, 1, newItem); this.doChange("update", [item, newItem]); } } /** * Update title * @param id Item id * @param title New title */ updateTitle(id, title) { const index = this.items.findIndex((item) => item.id === id); if (index !== -1) { const item = this.items[index]; const newItem = { ...item, title }; if (newItem.name === newItem.title) newItem.title = undefined; this.items.splice(index, 1, newItem); this.doChange("title", [item, newItem]); } } } exports.ShoppingCart = ShoppingCart;