@etsoo/appscript
Version:
Applications shared TypeScript framework
500 lines (499 loc) • 13.1 kB
JavaScript
"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;