UNPKG

@salla.sa/twilight-components

Version:
362 lines (357 loc) 15.5 kB
/*! * Crafted with ❤ by Salla */ import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client'; import { D as DisplayType, d as defineCustomElement$3 } from './salla-product-options2.js'; import { d as defineCustomElement$c } from './salla-booking-field2.js'; import { d as defineCustomElement$b } from './salla-button2.js'; import { d as defineCustomElement$a } from './salla-color-picker2.js'; import { d as defineCustomElement$9 } from './salla-conditional-fields2.js'; import { d as defineCustomElement$8 } from './salla-datetime-picker2.js'; import { d as defineCustomElement$7 } from './salla-file-upload2.js'; import { d as defineCustomElement$6 } from './salla-loading2.js'; import { d as defineCustomElement$5 } from './salla-map2.js'; import { d as defineCustomElement$4 } from './salla-modal2.js'; import { d as defineCustomElement$2 } from './salla-progress-bar2.js'; import { d as defineCustomElement$1 } from './salla-quantity-input2.js'; let addedOrderItemCounter = 0; function generateAddedOrderItemId(productId) { const cryptoRef = (typeof globalThis !== 'undefined' ? globalThis.crypto : undefined); if (cryptoRef && typeof cryptoRef.randomUUID === 'function') { return `new-${productId}-${cryptoRef.randomUUID()}`; } addedOrderItemCounter += 1; return `new-${productId}-${Date.now()}-${addedOrderItemCounter}`; } function cloneOrderEditProduct(product) { if (product == null) { return product; } return typeof structuredClone === 'function' ? structuredClone(product) : JSON.parse(JSON.stringify(product)); } function buildSavePayload(payload) { return { items: { update: payload.items.update, remove: payload.items.remove, add: payload.items.add.map(({ itemId, ...addItem }) => addItem), }, }; } function createAddedOrderItem(product, quantity, optionDefinitions, selectedOptions = {}) { const productData = cloneOrderEditProduct(product); return { id: generateAddedOrderItemId(product.id), quantity, isNew: true, selectedOptions, product: { ...productData, options: cloneOrderEditProduct(optionDefinitions), }, }; } function normalizeOrderEditOptionValue(value) { if (typeof File !== 'undefined' && value instanceof File) { return value.name; } return String(value); } function normalizeSelectedOptions(selectedOptions = {}) { return JSON.stringify(Object.entries(selectedOptions) .filter(([, value]) => value != null && normalizeOrderEditOptionValue(value).length > 0) .map(([optionId, value]) => [String(optionId), normalizeOrderEditOptionValue(value)]) .sort(([leftId], [rightId]) => leftId.localeCompare(rightId))); } function hasSelectedOptions(selectedOptions) { return Boolean(selectedOptions && Object.values(selectedOptions).some(value => value != null && normalizeOrderEditOptionValue(value).length > 0)); } const detailIdOptionTypes = new Set([ DisplayType.COLOR, DisplayType.COUNTRY, DisplayType.DIGITAL_CARD_VALUE, DisplayType.MULTIPLE_OPTIONS, DisplayType.RADIO, DisplayType.SINGLE_OPTION, DisplayType.THUMBNAIL, ]); function getProductOptionSelectedOptions(options = []) { return options.reduce((acc, option) => { if (option?.id == null) { return acc; } const selectedDetails = option.details?.filter(detail => detail?.is_selected) || []; const selectedDetail = selectedDetails[selectedDetails.length - 1]; const value = selectedDetail?.id ?? option.value; if (value == null || String(value).length === 0) { return acc; } acc[String(option.id)] = String(value); return acc; }, {}); } function getOrderDetailSelectedOptionValue(item, optionId, value) { const productOption = item?.product?.options?.find(option => String(option.id) === String(optionId)); const normalizedValue = String(value); if (!productOption?.details?.length || !detailIdOptionTypes.has(productOption.type)) { return normalizedValue; } const selectedDetail = productOption.details.find(detail => [ detail.id, detail.name, detail.option_value, detail.color, detail.image, detail.code, detail.display_value, ].some(detailValue => detailValue != null && String(detailValue) === normalizedValue)); return selectedDetail ? String(selectedDetail.id) : normalizedValue; } function getOrderDetailsSelectedOptions(item) { return (item?.options || []).reduce((acc, option) => { if (option?.id == null) { return acc; } const value = option.value ?? option.display_value; if (value == null || String(value).length === 0) { return acc; } acc[String(option.id)] = getOrderDetailSelectedOptionValue(item, option.id, value); return acc; }, {}); } function getOrderItemSelectedOptions(item) { if (hasSelectedOptions(item?.selectedOptions)) { return item.selectedOptions; } const productSelectedOptions = getProductOptionSelectedOptions(item?.product?.options); if (hasSelectedOptions(productSelectedOptions)) { return productSelectedOptions; } return getOrderDetailsSelectedOptions(item); } function findMergeableItem(items = [], productId, selectedOptions = {}) { const targetSelectedOptions = normalizeSelectedOptions(selectedOptions); return items.find(item => String(item.product?.id) === String(productId) && normalizeSelectedOptions(getOrderItemSelectedOptions(item)) === targetSelectedOptions); } function getOrderEditProductMaxQuantity(product) { const rawQuantity = product?.max_quantity ?? product?.max_quantity_per_order; const parsedQuantity = Number(rawQuantity); return Number.isFinite(parsedQuantity) && parsedQuantity > 0 ? parsedQuantity : undefined; } function clampOrderEditQuantity(quantity, maxQuantity) { if (!Number.isFinite(quantity) || quantity < 1) { return 1; } if (maxQuantity && quantity > maxQuantity) { return maxQuantity; } return quantity; } function patchOrderItem(item, quantity, optionDefinitions, selectedOptions) { return { ...item, quantity, selectedOptions: selectedOptions ?? getOrderItemSelectedOptions(item), product: item.product ? { ...item.product, options: optionDefinitions ?? item.product.options, } : item.product, }; } function updateOrderItems(items = [], itemId, quantity, optionDefinitions, selectedOptions) { return items.map(item => item.id === itemId ? patchOrderItem(item, quantity, optionDefinitions, selectedOptions) : item); } function removeOrderItems(items = [], itemId) { return items.filter(item => item.id !== itemId); } function mergePayloadItems(items, patch) { return { ...items, ...patch, }; } function upsertPayloadUpdateList(updateList = [], itemId, quantity, options = {}) { const nextUpdateList = updateList.filter(item => item.id !== itemId); nextUpdateList.push({ id: itemId, quantity, options }); return nextUpdateList; } function updateAddedPayloadList(addList = [], itemId, quantity, options) { return addList.map(item => item.itemId === itemId ? { ...item, quantity, options: options ?? item.options, } : item); } const sallaOrderEditItemCss = ":host{display:block}"; const SallaOrderEditItem = /*@__PURE__*/ proxyCustomElement(class SallaOrderEditItem extends HTMLElement { constructor() { super(); this.__registerHost(); this.orderItemUpdated = createEvent(this, "orderItemUpdated", 7); this.orderItemRemoved = createEvent(this, "orderItemRemoved", 7); this.quantityInput = null; this.productOptions = null; this.handleQuantityChange = (event) => { const detail = event.detail; const newQuantity = detail?.quantity ?? parseInt(event.target.value, 10); if (isNaN(newQuantity) || newQuantity < 1) return; if (newQuantity === this.quantity) return; this.quantity = newQuantity; this.emitUpdate(newQuantity); }; this.handleOptionsChange = () => { this.emitUpdate(this.quantity); }; } componentWillLoad() { this.quantity = this.item?.quantity || 1; } handleItemChange(newItem) { const newQuantity = newItem?.quantity || 1; if (newQuantity === this.quantity) return; this.quantity = newQuantity; this.quantityInput?.setValue?.(newQuantity, false); } get hasOptions() { return (this.item.product?.options?.length || 0) > 0; } async getSelectedOptions() { return (await this.productOptions?.getSelectedOptionsData?.()) || {}; } async getOptionsData() { return (await this.productOptions?.getOptionsData?.()) || this.item.product?.options || []; } async emitUpdate(quantity) { const itemId = this.item?.id; if (itemId == null) return; const detail = { itemId, quantity }; if (this.hasOptions) { detail.options = await this.getSelectedOptions(); detail.optionDefinitions = await this.getOptionsData(); } this.orderItemUpdated.emit(detail); } removeItem() { const itemId = this.item?.id; if (itemId == null) return; this.orderItemRemoved.emit({ itemId }); } render() { if (!this.item) return null; const product = this.item.product; const productName = this.item.name || product?.name || ''; const imageUrl = product?.image?.url || ''; const imageAlt = product?.image?.alt || productName; const productUrl = product?.url || '#'; const price = product?.price; const maxQuantity = getOrderEditProductMaxQuantity(product); const weightLabel = product?.weight_label; const options = this.item.product?.options; const optionsInstanceKey = `order-edit-item-${this.item.id}-${product?.id}`; const quantityAttrs = { value: this.quantity }; if (maxQuantity) { quantityAttrs.max = maxQuantity; } return (h(Host, null, h("div", null, h("div", { class: "s-order-edit-item-header" }, h("div", { class: "s-order-edit-item-media" }, imageUrl && (h("a", { href: productUrl }, h("img", { src: imageUrl, alt: imageAlt, class: "s-order-edit-item-image" }))), h("div", { class: "s-order-edit-item-details" }, h("h2", { class: "s-order-edit-item-name" }, h("a", { href: productUrl, class: "s-order-edit-item-link" }, productName)), price != null && (h("span", { class: "s-order-edit-item-price", innerHTML: salla.money(price) })), weightLabel && (h("p", { class: "s-order-edit-item-weight" }, salla.lang.getWithDefault('pages.products.weight', 'الوزن'), " ", weightLabel)))), h("salla-button", { type: "button", shape: "icon", size: "small", color: "danger", "aria-label": salla.lang.getWithDefault('common.elements.delete', 'حذف'), onClick: () => this.removeItem() }, h("i", { class: "sicon-cancel" }))), h("div", { class: "s-order-edit-item-quantity" }, h("h3", { class: "s-order-edit-item-quantity-label" }, salla.lang.getWithDefault('common.elements.quantity', 'الكمية')), h("div", { class: "s-order-edit-item-quantity-input" }, h("salla-quantity-input", { ref: el => (this.quantityInput = el), ...quantityAttrs, onChange: this.handleQuantityChange }))), this.hasOptions && (h("form", { class: "s-order-edit-item-options", onSubmit: e => e.preventDefault() }, h("salla-product-options", { ref: el => (this.productOptions = el), onChange: this.handleOptionsChange, "product-id": product.id, "unique-key": optionsInstanceKey, options: JSON.stringify(options), key: `${optionsInstanceKey}-options` })))))); } static get watchers() { return { "item": ["handleItemChange"] }; } static get style() { return sallaOrderEditItemCss; } }, [0, "salla-order-edit-item", { "item": [16], "orderId": [8, "order-id"], "quantity": [32] }, undefined, { "item": ["handleItemChange"] }]); function defineCustomElement() { if (typeof customElements === "undefined") { return; } const components = ["salla-order-edit-item", "salla-booking-field", "salla-button", "salla-color-picker", "salla-conditional-fields", "salla-datetime-picker", "salla-file-upload", "salla-loading", "salla-map", "salla-modal", "salla-product-options", "salla-progress-bar", "salla-quantity-input"]; components.forEach(tagName => { switch (tagName) { case "salla-order-edit-item": if (!customElements.get(tagName)) { customElements.define(tagName, SallaOrderEditItem); } break; case "salla-booking-field": if (!customElements.get(tagName)) { defineCustomElement$c(); } break; case "salla-button": if (!customElements.get(tagName)) { defineCustomElement$b(); } break; case "salla-color-picker": if (!customElements.get(tagName)) { defineCustomElement$a(); } break; case "salla-conditional-fields": if (!customElements.get(tagName)) { defineCustomElement$9(); } break; case "salla-datetime-picker": if (!customElements.get(tagName)) { defineCustomElement$8(); } break; case "salla-file-upload": if (!customElements.get(tagName)) { defineCustomElement$7(); } break; case "salla-loading": if (!customElements.get(tagName)) { defineCustomElement$6(); } break; case "salla-map": if (!customElements.get(tagName)) { defineCustomElement$5(); } break; case "salla-modal": if (!customElements.get(tagName)) { defineCustomElement$4(); } break; case "salla-product-options": if (!customElements.get(tagName)) { defineCustomElement$3(); } break; case "salla-progress-bar": if (!customElements.get(tagName)) { defineCustomElement$2(); } break; case "salla-quantity-input": if (!customElements.get(tagName)) { defineCustomElement$1(); } break; } }); } defineCustomElement(); export { SallaOrderEditItem as S, getOrderEditProductMaxQuantity as a, cloneOrderEditProduct as b, clampOrderEditQuantity as c, defineCustomElement as d, updateAddedPayloadList as e, findMergeableItem as f, getOrderItemSelectedOptions as g, upsertPayloadUpdateList as h, createAddedOrderItem as i, buildSavePayload as j, mergePayloadItems as m, removeOrderItems as r, updateOrderItems as u };