UNPKG

@salla.sa/twilight-components

Version:
182 lines (181 loc) 6.83 kB
/*! * Crafted with ❤ by Salla */ import { DisplayType } from "../salla-product-options/interfaces"; 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}`; } export function cloneOrderEditProduct(product) { if (product == null) { return product; } return typeof structuredClone === 'function' ? structuredClone(product) : JSON.parse(JSON.stringify(product)); } export function buildSavePayload(payload) { return { items: { update: payload.items.update, remove: payload.items.remove, add: payload.items.add.map(({ itemId, ...addItem }) => addItem), }, }; } export 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; }, {}); } export function getOrderItemSelectedOptions(item) { if (hasSelectedOptions(item?.selectedOptions)) { return item.selectedOptions; } const productSelectedOptions = getProductOptionSelectedOptions(item?.product?.options); if (hasSelectedOptions(productSelectedOptions)) { return productSelectedOptions; } return getOrderDetailsSelectedOptions(item); } export function findMergeableItem(items = [], productId, selectedOptions = {}) { const targetSelectedOptions = normalizeSelectedOptions(selectedOptions); return items.find(item => String(item.product?.id) === String(productId) && normalizeSelectedOptions(getOrderItemSelectedOptions(item)) === targetSelectedOptions); } export 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; } export function clampOrderEditQuantity(quantity, maxQuantity) { if (!Number.isFinite(quantity) || quantity < 1) { return 1; } if (maxQuantity && quantity > maxQuantity) { return maxQuantity; } return quantity; } export 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, }; } export function updateOrderItems(items = [], itemId, quantity, optionDefinitions, selectedOptions) { return items.map(item => item.id === itemId ? patchOrderItem(item, quantity, optionDefinitions, selectedOptions) : item); } export function removeOrderItems(items = [], itemId) { return items.filter(item => item.id !== itemId); } export function mergePayloadItems(items, patch) { return { ...items, ...patch, }; } export function upsertPayloadUpdateList(updateList = [], itemId, quantity, options = {}) { const nextUpdateList = updateList.filter(item => item.id !== itemId); nextUpdateList.push({ id: itemId, quantity, options }); return nextUpdateList; } export function updateAddedPayloadList(addList = [], itemId, quantity, options) { return addList.map(item => item.itemId === itemId ? { ...item, quantity, options: options ?? item.options, } : item); }