UNPKG

@salla.sa/twilight-components

Version:
220 lines (214 loc) 13.4 kB
/*! * Crafted with ❤ by Salla */ import { r as registerInstance, h, H as Host, a as getElement, F as Fragment } from './index-Dbv0I4re.js'; const sallaMultipleBundleProductCartCss = ""; const SallaMultipleBundleProductCart = class { constructor(hostRef) { registerInstance(this, hostRef); /** The list of sections belonging to a bundle product. */ this.sections = []; this.itemNumber = ''; } deleteItem(sectionId, product) { const form = this.host.closest('form'); if (form) { const formId = form.getAttribute('id'); if (formId && typeof formId === 'string') { const itemNumber = formId.match(/item-(\d+)/)?.[1]; this.itemNumber = itemNumber || ''; const selectedAccordion = this.host.querySelector(`#accordion-${product.id}`); salla.cart .deleteItem(`${this.itemNumber}?product_id=${product.id}&section_id=${sectionId}`) .then(() => selectedAccordion?.remove()); } } } renderRemoveButton(sectionId, product, isText = false) { return (h("salla-button", { type: "button", shape: isText ? 'btn' : 'icon', fill: isText ? 'outline' : 'solid', size: "small", color: "danger", "aria-label": "Remove from the cart", onClick: () => this.deleteItem(sectionId, product) }, isText ? salla.lang.get('common.elements.delete') : h("i", { class: "sicon-cancel" }))); } renderAccordionHeader(sectionId, product) { const hasOptions = product?.options && product?.options?.length > 0; // undefined or empty array return (h("div", { slot: "html", class: "s-multiple-bundle-product-cart-header-wrapper" }, h("div", { class: `s-multiple-bundle-product-cart-header ${hasOptions ? '' : 's-multiple-bundle-product-cart-header-no-options'}` }, h("div", { class: "s-multiple-bundle-product-cart-header-content" }, h("a", { href: product?.url, class: "s-multiple-bundle-product-cart-header-image-wrapper" }, h("img", { src: product?.image?.url, alt: product?.image?.alt || product?.name, class: "s-multiple-bundle-product-cart-header-image" })), h("div", { class: "s-multiple-bundle-product-cart-header-content-details" }, h("h2", { class: "s-multiple-bundle-product-cart-header-content-details-title" }, h("a", { href: product?.url, class: "s-multiple-bundle-product-cart-header-content-details-title-link" }, product?.name)), h("div", { class: "s-multiple-bundle-product-cart-header-content-details-price" }, h("span", { class: "s-multiple-bundle-product-cart-header-content-details-price-regular" }, h("span", { innerHTML: product?.price ? salla.money(product?.price) : '' })), product?.sale_price > 0 && (h("span", { class: "s-multiple-bundle-product-cart-header-content-details-price-sale" }, h("span", { innerHTML: salla.money(product?.sale_price) })))), product?.quantity_in_group > 0 && product?.quantity !== 0 && (h("p", { class: "s-multiple-bundle-product-cart-header-content-details-quantity" }, h("span", null, salla.lang.get('pages.products.number_of_pieces')), h("span", null, product?.quantity_in_group))))), !hasOptions && (h("div", { class: "s-multiple-bundle-product-cart-header-remove-button" }, this.renderRemoveButton(sectionId, product, false)))))); } render() { return (h(Host, { key: 'df5a1f17db16a85222a239fa507912f38749909a', class: "s-multiple-bundle-product-wrapper" }, h("div", { key: '52a0c1480c1ac65225491eea9f467a35677365f2', class: "s-multiple-bundle-product-wrapper-sections" }, this.sections.map((section, sectionIndex) => { return section.products.map(product => { const bundleContext = { sectionId: section.id, sectionIndex: sectionIndex, productId: product.id, }; return (h("salla-accordion", { key: product.id, collapsed: false, bordered: true, collapsible: product.options && product.options.length > 0 ? true : false, size: "sm", id: `accordion-${product.id}` }, h("salla-accordion-head", null, this.renderAccordionHeader(String(section.id), product)), product.options && product.options.length > 0 && (h("salla-accordion-body", null, h("salla-product-options", { options: JSON.stringify(product.options), key: `${product.id}-persistent`, "product-id": product.id, "bundle-context": JSON.stringify(bundleContext) }), h("div", { class: "s-multiple-bundle-product-cart-body-remove-button" }, this.renderRemoveButton(String(section.id), product, true)))))); }); })))); } get host() { return getElement(this); } }; SallaMultipleBundleProductCart.style = sallaMultipleBundleProductCartCss; const sallaMultipleBundleProductDetailsCss = ""; const SallaMultipleBundleProductDetails = class { constructor(hostRef) { registerInstance(this, hostRef); /** The list of sections belonging to a bundle product. */ this.sections = []; // store selected product IDs per section (can be string or number) this.selectedProducts = {}; // Event handler reference for cleanup this.productSelectedHandler = null; // handle selecting a product (toggle) this.onSelectProduct = (sectionId, product) => { this.selectedProducts = { ...this.selectedProducts, [sectionId]: new Set(this.selectedProducts[sectionId] || []), }; const productId = product.id; const wasSelected = this.selectedProducts[sectionId].has(productId); if (wasSelected) { // Product is being deselected this.selectedProducts[sectionId].delete(productId); // Clear form data and modal options for this product in this specific section this.clearProductFormData(productId, sectionId); this.clearProductModalOptions(productId, sectionId); } else { // Product is being selected this.selectedProducts[sectionId].add(productId); } // force re-render this.selectedProducts = { ...this.selectedProducts }; // still dispatch event salla.event.dispatch('on-bundle-product-selected', { id: product.id, name: product.name, options: product.options, wasSelected: wasSelected, isSelected: !wasSelected, }); }; // ensure product is selected (only add if not already selected) this.ensureProductSelected = (sectionId, product) => { this.selectedProducts = { ...this.selectedProducts, [sectionId]: new Set(this.selectedProducts[sectionId] || []), }; const productId = product.id; // Only add if not already selected if (!this.selectedProducts[sectionId].has(productId)) { this.selectedProducts[sectionId].add(productId); // force re-render this.selectedProducts = { ...this.selectedProducts }; // dispatch event salla.event.dispatch('on-bundle-product-selected', { id: product.id, name: product.name, options: product.options, }); } }; // open product options modal this.onSelectProductOptions = (product, sectionId) => { // Find the section index from the sectionId const sectionIndex = this.sections.findIndex(section => section.id == sectionId); // Find the product index within the section const section = this.sections.find(section => section.id == sectionId); const productIndex = section?.products?.findIndex(p => p.id == product.id) ?? 0; salla.event.dispatch('multiple-bundle-product-modal::open', { product, sectionId, sectionIndex, productIndex, }); }; // Event handlers for bundle slider component this.handleBundleSliderProductSelected = (event) => { const { product, sectionId } = event.detail; this.onSelectProduct(sectionId, product); }; this.handleBundleSliderProductOptionsSelected = (event) => { const { product, sectionId } = event.detail; this.onSelectProductOptions(product, sectionId); }; } // Clear form data for a specific product in specific section clearProductFormData(productId, sectionId) { const form = this.host.closest('form'); if (sectionId) { // Remove inputs for specific section/productIndex combination const productInputPattern = `bundle[${sectionId}][`; const inputsToRemove = Array.from(form.querySelectorAll('input')).filter((input) => input.getAttribute('data-product-id') === String(productId) && input.name && input.name.startsWith(productInputPattern)); inputsToRemove.forEach(input => input.remove()); } else { // Fallback: Remove all hidden inputs related to this product (legacy behavior) const inputsToRemove = form.querySelectorAll(`[data-product-id="${productId}"]`); inputsToRemove.forEach(input => input.remove()); } } // Clear modal options state for a specific product clearProductModalOptions(productId, sectionId) { let sectionIndex = null; let productIndex = null; if (sectionId != null) { sectionIndex = this.sections.findIndex(section => section.id == sectionId); if (sectionIndex > -1) { const section = this.sections[sectionIndex]; if (section) { const foundIndex = section.products?.findIndex(product => product.id == productId); productIndex = typeof foundIndex === 'number' && foundIndex > -1 ? foundIndex : null; } } } // Emit event to notify modal to reset its state for this product salla.event.dispatch('multiple-bundle-product-modal::clear-options', { productId, sectionId, sectionIndex, productIndex, }); } renderAccordionHeader(section, selectedCount) { return (h(Fragment, null, h("h2", { slot: "title" }, section?.name), section?.obligatory_products ? (h("span", { slot: "note" }, salla.lang.get('pages.products.obligatory_products', { count: section?.obligatory_products || 0, }))) : '', h("span", { slot: "progress" }, selectedCount, "/", section?.products?.length || 0))); } componentDidLoad() { // Listen for product selected event from modal const modal = this.host.querySelector('salla-multiple-bundle-product-options-modal'); if (modal) { this.productSelectedHandler = (e) => { const { productId, sectionId, product, fromModal } = e.detail; if (fromModal) { // When called from modal, only add to selection if not already selected this.ensureProductSelected(sectionId, product || { id: productId }); } else { // Normal toggle behavior this.onSelectProduct(sectionId, product || { id: productId }); } }; modal.addEventListener('productSelected', this.productSelectedHandler); } } disconnectedCallback() { // Clean up event listener to prevent memory leaks if (this.productSelectedHandler) { const modal = this.host.querySelector('salla-multiple-bundle-product-options-modal'); if (modal) { modal.removeEventListener('productSelected', this.productSelectedHandler); } this.productSelectedHandler = null; } } render() { return (h(Host, { key: '25ed3fad5e1252a6a22739927c209689c111ef8b', class: "s-multiple-bundle-product-wrapper" }, h("div", { key: 'e2738635e77e740c47307130efff6c6d8d7dbb1e', class: "s-multiple-bundle-product-wrapper-sections" }, this.sections.map((section, index) => { const selectedCount = this.selectedProducts[section.id]?.size || 0; return (h("salla-accordion", { key: section.id, collapsed: index === 0 ? false : true }, h("salla-accordion-head", null, this.renderAccordionHeader(section, selectedCount)), h("salla-accordion-body", null, h("salla-multiple-bundle-product-slider", { section: section, sectionIndex: index, selectedProducts: this.selectedProducts, onProductSelected: this.handleBundleSliderProductSelected, onProductOptionsSelected: this.handleBundleSliderProductOptionsSelected })))); })), h("salla-multiple-bundle-product-options-modal", { key: '6359eb293af8feb486884f4d7d3182543c062430' }))); } get host() { return getElement(this); } }; SallaMultipleBundleProductDetails.style = sallaMultipleBundleProductDetailsCss; export { SallaMultipleBundleProductCart as salla_multiple_bundle_product_cart, SallaMultipleBundleProductDetails as salla_multiple_bundle_product_details };