UNPKG

@salla.sa/twilight-components

Version:
661 lines (655 loc) 35.2 kB
/*! * Crafted with ❤ by Salla */ import { r as registerInstance, c as createEvent, h, H as Host, a as getElement } from './index-BHYtfMwX.js'; import { A as ArrowLeftIcon, a as ArrowRightIcon } from './keyboard_arrow_right-Vqpj4CWE.js'; const sallaMultipleBundleProductOptionsModalCss = ":host{display:block}"; const SallaMultipleBundleProductOptionsModal = class { constructor(hostRef) { registerInstance(this, hostRef); this.optionsSaved = createEvent(this, "optionsSaved"); this.productSelected = createEvent(this, "productSelected"); this.product = null; this.sectionId = null; this.sectionIndex = 0; this.productIndex = 0; this.selectedOptions = {}; this.optionsResetTokens = {}; this.isLoading = false; this.hasUnsavedChanges = false; this.validationErrors = []; this.isProductAlreadySelected = false; } /** * Generate a unique cache key for selected options using section ID, product index, and product ID */ generateCacheKey(sectionId, productIndex, productId) { return `${sectionId || 'unknown'}-${productIndex || 0}-${productId || 'unknown'}`; } handleProductChange(newValue) { // Use setTimeout to ensure modal is ready setTimeout(() => { if (this.modal && newValue) { const title = newValue.name || ''; this.modal.setTitle(title); } }, 100); // Reset validation errors when product changes this.validationErrors = []; this.hasUnsavedChanges = false; } /** Opens the modal manually. */ async open() { if (!this.modal) { requestAnimationFrame(() => this.open()); return; } this.isLoading = true; // Set the title before opening if (this.product?.name) { this.modal.setTitle(this.product.name); } this.modal.open(); // Initialize selectedOptions with current selections from the component setTimeout(async () => { if (this.product?.id) { await this.initializeSelectedOptions(); } // Set title again after modal is fully loaded if (this.product?.name) { this.modal.setTitle(this.product.name); } this.modal.stopLoading(); this.isLoading = false; }, 300); } /** Closes the modal manually. */ async close() { if (this.modal) { this.modal.close(); } } /** Refreshes the internal options tracking state manually. */ async refreshOptionsState() { // Force re-render by updating the component state this.selectedOptions = { ...this.selectedOptions }; } componentDidLoad() { this.modalOpenListener = (data) => { this.product = data.product; this.sectionId = data.sectionId || null; this.sectionIndex = data.sectionIndex || 0; this.productIndex = data.productIndex || 0; this.isProductAlreadySelected = !!data.isProductAlreadySelected; this.open(); }; salla.event.on('multiple-bundle-product-modal::open', this.modalOpenListener); // Listen for clear-options event when a product is deselected this.clearOptionsListener = (data) => { if (!data || !data.productId) return; this.clearProductOptions(data.productId, data.sectionId, data.productIndex); }; salla.event.on('multiple-bundle-product-modal::clear-options', this.clearOptionsListener); // Create and store the option change listener for proper cleanup this.optionChangeListener = (e) => { const data = e.detail || e; const { option, detail } = data; // If data is a detail object (has option_id), find the option from product const actualOption = option || (data.option_id && this.product?.options?.find(opt => opt.id === data.option_id || String(opt.id) === String(data.option_id))); const actualDetail = detail || (data.id ? data : null); if (this.product?.id && actualOption) { this.handleOptionChange(Number(this.product.id), actualOption, actualDetail); } }; salla.event.on('product-options::change', this.optionChangeListener); // Create and store the checkbox change listener for proper cleanup this.checkboxChangeListener = (e) => { const target = e.target; // Check if this is a product selection checkbox if (target && target.type === 'checkbox' && target.name && target.name.includes('bundle[') && target.name.includes('][id]')) { // Extract section info from the checkbox name: bundle[sectionId][productIndex][id] const nameMatch = target.name.match(/^bundle\[([^\]]+)\]\[([^\]]+)\]\[id\]$/); if (nameMatch && !target.checked) { if (target.getAttribute('data-selection-locked') === 'true') { target.checked = true; return; } const [, sectionId, productIndex] = nameMatch; const productId = target.value; const form = this.host.closest('form'); this.cleanupProductDeselection({ sectionId, productIndex: parseInt(productIndex, 10), productId, form, uncheckedInput: target, }); } } }; // Listen for product checkbox changes to reset options when product is deselected document.addEventListener('change', this.checkboxChangeListener); } disconnectedCallback() { // Clean up event listeners to prevent memory leaks if (this.checkboxChangeListener) { document.removeEventListener('change', this.checkboxChangeListener); } if (this.optionChangeListener) { salla.event.off('product-options::change', this.optionChangeListener); } if (this.modalOpenListener) { salla.event.off('multiple-bundle-product-modal::open', this.modalOpenListener); } if (this.clearOptionsListener) { salla.event.off('multiple-bundle-product-modal::clear-options', this.clearOptionsListener); } } cleanupProductDeselection(params) { const { sectionId, productIndex, productId, form, uncheckedInput } = params; this.clearProductOptions(productId, sectionId, productIndex); if (form) { const productInputPattern = `bundle[${sectionId}][${productIndex}]`; Array.from(form.querySelectorAll(`input[name^="${productInputPattern}"]`)).forEach(input => { if (input === uncheckedInput) { return; } const shouldRemoveHidden = input.type === 'hidden'; const shouldRemoveByDataset = input.getAttribute('data-product-id') === String(productId) && input.name?.startsWith(productInputPattern); if (shouldRemoveHidden || shouldRemoveByDataset) { input.remove(); } }); requestAnimationFrame(() => { const changeEvent = new window.Event('change', { bubbles: true }); form.dispatchEvent(changeEvent); }); } } generateFormInputName(sectionId, productIndex, optionParentId) { return `bundle[${sectionId}][${productIndex}][options][${optionParentId}]`; } async initializeSelectedOptions() { if (!this.product?.id) return; const productId = this.product.id; const cacheKey = this.generateCacheKey(this.sectionId, this.productIndex, productId); const optionsEl = document.querySelector(`salla-product-options[product-id="${productId}"]`); if (optionsEl) { try { const selectedOptions = await optionsEl.getSelectedOptions(); if (selectedOptions && selectedOptions.length > 0) { this.selectedOptions = { ...this.selectedOptions, [cacheKey]: selectedOptions, }; } } catch (e) { console.warn('Could not initialize selected options:', e); } } } // Clear options state for a specific product clearProductOptions(productId, sectionId, productIndex) { const updatedSelectedOptions = { ...this.selectedOptions }; if (sectionId != null && productIndex != null && !Number.isNaN(productIndex)) { const cacheKey = this.generateCacheKey(sectionId, productIndex, productId); delete updatedSelectedOptions[cacheKey]; this.bumpOptionsResetToken(cacheKey); } else { const productSuffix = `-${String(productId)}`; const affectedKeys = []; Object.keys(updatedSelectedOptions).forEach(key => { if (key.endsWith(productSuffix)) { delete updatedSelectedOptions[key]; affectedKeys.push(key); } }); affectedKeys.forEach(key => this.bumpOptionsResetToken(key)); } this.selectedOptions = updatedSelectedOptions; // Reset validation errors and unsaved changes this.validationErrors = []; this.hasUnsavedChanges = false; } bumpOptionsResetToken(cacheKey) { if (!cacheKey) return; this.optionsResetTokens = { ...this.optionsResetTokens, [cacheKey]: (this.optionsResetTokens[cacheKey] || 0) + 1, }; } async handleOptionChange(productId, option, detail) { const cacheKey = this.generateCacheKey(this.sectionId, this.productIndex, productId); // Get the current state from the component to ensure we have the latest selections const optionsEl = document.querySelector(`salla-product-options[product-id="${productId}"]`); let currentComponentSelections = []; if (optionsEl) { try { currentComponentSelections = (await optionsEl.getSelectedOptions()) || []; } catch (e) { console.warn('Could not get current selections from component:', e); } } // If component returns data, use it; otherwise, fall back to manual tracking if (currentComponentSelections.length > 0) { // Component returned data, use it this.selectedOptions = { ...this.selectedOptions, [cacheKey]: currentComponentSelections, }; } else { // If we have existing selections in internal state and component returns empty, // it might be a deselection, so we should use manual tracking if (this.selectedOptions[cacheKey] && this.selectedOptions[cacheKey].length > 0) { // Component didn't return data, use manual tracking const currentSelected = this.selectedOptions[cacheKey] || []; const updatedSelected = [...currentSelected]; // Find existing selection for this specific option (by option_id) const existingIndex = updatedSelected.findIndex(opt => opt.option_id === option.id); if (existingIndex > -1) { // Check if this is a deselection (detail might be null or undefined) if (!detail || detail.id === null || detail.id === undefined) { // Remove the option (deselection) updatedSelected.splice(existingIndex, 1); } else { // Replace existing selection for this option updatedSelected[existingIndex] = { ...detail, option_id: option.id }; } } else { // Only add if detail exists (not a deselection) if (detail && detail.id !== null && detail.id !== undefined) { updatedSelected.push({ ...detail, option_id: option.id }); } } this.selectedOptions = { ...this.selectedOptions, [cacheKey]: updatedSelected, }; } else { // No existing selections, component returned empty, and we're trying to add // This might be the first selection, so add it manually if (detail && detail.id !== null && detail.id !== undefined) { this.selectedOptions = { ...this.selectedOptions, [cacheKey]: [{ ...detail, option_id: option.id }], }; } } } this.hasUnsavedChanges = true; this.validationErrors = []; // Clear validation errors when user makes changes } async validateOptions() { if (!this.product?.options) return true; const errors = []; const productId = this.product.id; const cacheKey = this.generateCacheKey(this.sectionId, this.productIndex, productId); // Get the actual selected options from the component const optionsEl = document.querySelector(`salla-product-options[product-id="${productId}"]`); let currentSelected = []; if (optionsEl) { try { currentSelected = (await optionsEl.getSelectedOptions()) || []; // Also check our internal state as fallback const internalSelected = this.selectedOptions[cacheKey] || []; // Use whichever has more selections, or if component returns empty but internal has data, use internal if (internalSelected.length > currentSelected.length || (currentSelected.length === 0 && internalSelected.length > 0)) { currentSelected = internalSelected; } } catch (e) { // Fallback to internal state currentSelected = this.selectedOptions[cacheKey] || []; } } else { // Fallback to internal state currentSelected = this.selectedOptions[cacheKey] || []; } // Check if any options are selected at all if (currentSelected.length === 0) { errors.push(salla.lang.get('pages.products.no_options_selected')); } // Check required options this.product.options.forEach(option => { if (option.required) { const hasSelection = currentSelected.some(selected => { return selected.option_id == option.id; // Use == instead of === for type flexibility }); if (!hasSelection) { errors.push(salla.lang.get('pages.products.required_option_missing', { option: option.name, })); } } }); this.validationErrors = errors; return errors.length === 0; } async onSave(e) { e.preventDefault(); const productId = this.product?.id; if (!productId) return; const cacheKey = this.generateCacheKey(this.sectionId, this.productIndex, productId); // Small delay to ensure component state is updated await new Promise(resolve => setTimeout(resolve, 100)); // Validate options before saving const isValid = await this.validateOptions(); if (!isValid) { salla.notify.error(this.validationErrors.join(', ')); return; } if (!this.isProductAlreadySelected && this.sectionId != null) { const details = this.host.closest('salla-multiple-bundle-product-details'); const canSelect = await details?.canSelectBundleProduct(this.sectionId, productId); if (!canSelect) { salla.notify.error(salla.lang.getWithDefault('pages.products.bundle_selection_limit_reached', 'لا يمكنك اختيار المزيد من المنتجات في هذا القسم')); return; } } this.isLoading = true; try { // please don't change this with this.host.querySelector it will return null const optionsEl = document.querySelector(`salla-product-options[product-id="${productId}"]`); let selectedOptions = await optionsEl?.getSelectedOptions(); // If component returns empty but we have internal state, use internal state if ((!selectedOptions || selectedOptions.length === 0) && this.selectedOptions[cacheKey]?.length > 0) { selectedOptions = this.selectedOptions[cacheKey]; } if (!selectedOptions || selectedOptions.length === 0) { this.isLoading = false; return; } // Store the selected options for this product using cache key this.selectedOptions = { ...this.selectedOptions, [cacheKey]: selectedOptions, }; const form = this.host.closest('form'); if (!form) { this.isLoading = false; return; } // remove old inputs for this specific product in this specific section/index only const productInputPattern = `bundle[${this.sectionId}][${this.productIndex}]`; // Remove only hidden inputs and inputs with data-product-id, but preserve visible checkboxes Array.from(form.querySelectorAll(`input[name^="${productInputPattern}"][type="hidden"]`)).forEach(el => el.remove()); // Also remove any inputs with data-product-id that match this specific pattern Array.from(form.querySelectorAll(`[data-product-id="${productId}"][name^="${productInputPattern}"]`)).forEach(el => el.remove()); // Ensure the actual checkbox in the UI is checked to reflect the selection visually const checkboxId = `bundle[${this.sectionId}][${this.productIndex}][id]`; const checkbox = document.getElementById(checkboxId); if (checkbox) { checkbox.checked = true; // Don't dispatch change event here to avoid double API calls } else { // If checkbox doesn't exist, create a hidden input as fallback const productSelectionInput = document.createElement('input'); productSelectionInput.type = 'hidden'; productSelectionInput.name = `bundle[${this.sectionId}][${this.productIndex}][id]`; productSelectionInput.value = String(productId); productSelectionInput.dataset.productId = String(productId); form.appendChild(productSelectionInput); } // append new hidden inputs for options selectedOptions.forEach((option) => { // how to get option parent id? const optionParentId = option.option_id; const hidden = document.createElement('input'); hidden.type = 'hidden'; // Use productIndex for the form input name hidden.name = this.generateFormInputName(this.sectionId, this.productIndex ?? 0, optionParentId); hidden.value = String(option.id); hidden.dataset.productId = String(productId); form.appendChild(hidden); }); // Trigger single form change event with all updates (product selection + options) const changeEvent = new window.Event('change', { bubbles: true }); form.dispatchEvent(changeEvent); // Emit custom event this.optionsSaved.emit({ productId: Number(productId), selectedOptions, sectionId: this.sectionId, productIndex: this.productIndex, }); // Emit product selected event to check the card if (this.sectionId) { this.productSelected.emit({ productId: Number(productId), sectionId: this.sectionId, product: this.product, fromModal: true, }); } // Show success message salla.notify.success(salla.lang.get('pages.products.options_saved')); this.hasUnsavedChanges = false; this.validationErrors = []; // close modal this.modal.close(); } catch (error) { salla.notify.error(salla.lang.get('pages.products.options_save_error')); } finally { this.isLoading = false; } } // Method to get options with selected state preserved getOptionsWithSelectedState() { if (!this.product?.options) return []; const cacheKey = this.generateCacheKey(this.sectionId, this.productIndex, this.product.id); const savedOptions = this.selectedOptions[cacheKey] || []; return this.product.options.map(option => ({ ...option, details: option.details.map(detail => { const isSelected = savedOptions.some(saved => { return saved.id === detail.id; }); return { ...detail, is_selected: isSelected, }; }), })); } render() { const productId = this.product?.id; const optionsWithSelectedState = this.getOptionsWithSelectedState(); const cacheKey = this.generateCacheKey(this.sectionId, this.productIndex, productId); const resetToken = this.optionsResetTokens[cacheKey] || 0; const isDisabled = this.isLoading || optionsWithSelectedState.some(opt => opt.details.some(d => d.is_selected && d.is_out === true)); return (h(Host, { key: '6c1d1d3911867e30240676f3e2b7353e9ecf76c3' }, h("salla-modal", { key: 'b02110d80cd422d64962d78812ae0b0637c56237', isLoading: this.isLoading, ref: el => (this.modal = el), width: "md", centered: false, id: `s-multiple-bundle-product-options-modal-options-${productId}`, class: "s-multiple-bundle-product-options-modal-wrapper" }, h("div", { key: '20a52bbc732c6edfffde86577e99bbe300a1a4c8', slot: "loading" }, h("salla-skeleton", { key: '3a69fc75939d8b8f8639983d0f2f8dd8bf961152', height: "100%", width: "100%" })), this.product?.images && this.product?.images.length > 0 && (h("salla-slider", { key: '185639c54f79188093df98ac1cece1958879f71d', id: `details-slider-${this.product?.id}`, type: "thumbs", loop: false, "auto-height": true, "listen-to-thumbnails-option": true, showThumbsControls: false, controlsOuter: false, showControls: false, class: "s-multiple-bundle-product-options-modal-slider", verticalThumbs: true, thumbsConfig: { centeredSlides: true, centeredSlidesBounds: true, slidesPerView: Math.min(5, Math.max(1, this.product?.images.length)), watchOverflow: true, watchSlidesProgress: true, direction: 'vertical', spaceBetween: 10, } }, h("div", { key: '3b6a88fe3862870d674dadc31967df6cc8fac365', slot: "items" }, this.product?.images && this.product?.images.map((image, index) => (h("div", { key: index, class: "swiper-slide" }, h("img", { src: image.url, alt: image.alt || `${this.product?.name} - Image ${index + 1}`, loading: "lazy", onError: e => { e.target.style.display = 'none'; } }))))), this.product?.images && this.product?.images.length > 1 && (h("div", { key: '6fce48b5b035cc61866aaf6c339866fa2314be87', slot: "thumbs" }, this.product?.images && this.product?.images.map((image, index) => (h("div", { key: index, "data-caption": `${this.product?.name} - Image ${index + 1}` }, h("img", { src: image.url, loading: "eager", class: "s-multiple-bundle-product-options-modal-slider-thumb", title: `${this.product?.name} - ${index + 1}`, alt: image.alt || `${this.product?.name} - ${index + 1}`, onError: e => { e.target.style.display = 'none'; } })))))))), h("salla-product-options", { options: JSON.stringify(optionsWithSelectedState), key: `${cacheKey}-reset-${resetToken}`, "product-id": productId, "unique-key": `${cacheKey}-reset-${resetToken}` }), h("div", { key: '3d555ea40fe5d9f3685fc6dafa4b6fad16732091', slot: "footer" }, h("div", { key: '1b4c6834899efbd09f3ea1db251999f50ec655b2', class: "s-multiple-bundle-product-options-modal-footer" }, h("salla-button", { key: '0818a75a444cca510c7f0cfea2ec53414c12db53', onClick: e => this.onSave(e), loading: this.isLoading, disabled: isDisabled }, this.isLoading ? salla.lang.get('common.elements.saving') : salla.lang.get('common.elements.save'))))))); } get host() { return getElement(this); } static get watchers() { return { "product": ["handleProductChange"] }; } }; SallaMultipleBundleProductOptionsModal.style = sallaMultipleBundleProductOptionsModalCss; const sallaMultipleBundleProductSliderCss = ""; const SallaMultipleBundleProductSlider = class { constructor(hostRef) { registerInstance(this, hostRef); this.productSelected = createEvent(this, "productSelected"); this.productOptionsSelected = createEvent(this, "productOptionsSelected"); /** A dictionary tracking which product IDs are currently selected per section. */ this.selectedProducts = {}; /** When true, the selected product cannot be deselected (single-product section with min = 1). */ this.isSelectionLocked = false; /** Maximum selectable products for this section (empty max → all products in section). */ this.selectionLimit = 0; this.savedOptionsByInstance = {}; this.handleProductClick = (product, productIndex) => { const isChecked = this.selectedProducts[this.section.id]?.has(product.id) || false; const checkbox = this.getCheckbox(this.section.id, productIndex); if (isChecked && this.isSelectionLocked) { if (checkbox) { checkbox.checked = true; } return; } if (!isChecked && this.isMaxSelectionReached() && this.selectionLimit !== 1) { return; } // max = 1: parent replaces selection and syncs all checkboxes in the section if (this.selectionLimit === 1 && !isChecked) { this.productSelected.emit({ product, sectionId: this.section.id, }); return; } if (!checkbox) return; const willBeChecked = !checkbox.checked; if (!willBeChecked) { this.dispatchClearOptionsEvent(product, productIndex); this.clearSavedOptionsState(this.section.id, productIndex); } checkbox.checked = willBeChecked; requestAnimationFrame(() => { const changeEvent = new window.Event('change', { bubbles: true }); checkbox.dispatchEvent(changeEvent); }); this.productSelected.emit({ product, sectionId: this.section.id, }); }; this.handleOptionsClick = (product) => { const isChecked = this.selectedProducts[this.section.id]?.has(product.id) || false; if (!isChecked && this.isMaxSelectionReached() && this.selectionLimit !== 1) { return; } this.productOptionsSelected.emit({ product, sectionId: this.section.id, }); }; } getSelectedCount() { return this.selectedProducts[this.section?.id]?.size ?? 0; } isMaxSelectionReached() { return this.selectionLimit > 1 && this.getSelectedCount() >= this.selectionLimit; } isProductSelectionDisabled(product, isChecked) { if (product.quantity === 0) { return true; } return !isChecked && this.isMaxSelectionReached(); } getProductInstanceKey(sectionId, productIndex) { return `${sectionId}::${productIndex}`; } dispatchClearOptionsEvent(product, productIndex) { salla.event.dispatch('multiple-bundle-product-modal::clear-options', { productId: product.id, sectionId: this.section.id, sectionIndex: this.sectionIndex, productIndex, }); } handleOptionsSaved(event) { const detail = event.detail; if (!detail) return; const { sectionId, productIndex, selectedOptions } = detail; if (sectionId == null || sectionId !== this.section?.id) return; if (productIndex == null || Number.isNaN(productIndex)) return; const key = this.getProductInstanceKey(sectionId, productIndex); const hasOptions = !!selectedOptions?.length; if (hasOptions) { this.savedOptionsByInstance = { ...this.savedOptionsByInstance, [key]: true, }; } else if (this.savedOptionsByInstance[key]) { const updatedState = { ...this.savedOptionsByInstance }; delete updatedState[key]; this.savedOptionsByInstance = updatedState; } } clearSavedOptionsState(sectionId, productIndex) { const key = this.getProductInstanceKey(sectionId, productIndex); if (!this.savedOptionsByInstance[key]) return; const updatedState = { ...this.savedOptionsByInstance }; delete updatedState[key]; this.savedOptionsByInstance = updatedState; } generateEventName(sectionId, productIndex) { return `bundle[${sectionId}][${productIndex}][id]`; } getCheckbox(sectionId, productIndex) { const name = this.generateEventName(sectionId, productIndex); return this.host.querySelector(`input.s-multiple-bundle-product-checkbox[name="${name}"]`); } preventLockedDeselect(event, isChecked) { if (!this.isSelectionLocked || !isChecked) { return; } event.preventDefault(); event.stopPropagation(); const checkbox = event.target; if (checkbox?.type === 'checkbox') { checkbox.checked = true; } } render() { return (h(Host, { key: 'd52eb26454606df2526fa4c086110a54f7466644' }, h("salla-slider", { key: '1aa1fce5943c3721a8e4f762171c864d9097bb28', type: "carousel", controlsOuter: false, showControls: false, id: `accordion-multiple-bundle-product-${this.section.id}`, pagination: true, class: "s-multiple-bundle-product-wrapper-slider", sliderConfig: { spaceBetween: 0 } }, h("div", { key: '9342381bc43389bae48b906a1ab23a4f3cf8d00a', slot: "items" }, this?.section?.products?.map((product, productIndex) => { const isChecked = this.selectedProducts[this.section.id]?.has(product.id) || false; const isLocked = isChecked && this.isSelectionLocked; const isDisabled = this.isProductSelectionDisabled(product, isChecked); const hasSavedOptions = this.savedOptionsByInstance[this.getProductInstanceKey(this.section.id, productIndex)]; const optionsButtonLabel = hasSavedOptions ? salla.lang.getWithDefault('pages.products.edit_selected_options', 'تعديل الخيارات') : salla.lang.get('pages.products.choose_from_options'); let optionsArrowIcon = salla.config.get('theme.is_rtl', true) ? ArrowLeftIcon : ArrowRightIcon; return (h("div", { class: `s-multiple-bundle-product-slide-one-third${isDisabled ? ' s-multiple-bundle-product-slide-one-third-disabled' : ''}`, key: product.id }, h("div", { class: "s-multiple-bundle-product-card" }, h("div", { class: "s-multiple-bundle-product-image-wrapper", onClick: () => this.handleProductClick(product, productIndex) }, h("input", { id: this.generateEventName(this.section.id, productIndex), type: "checkbox", class: "s-multiple-bundle-product-checkbox", checked: isChecked, "data-selection-locked": isLocked ? 'true' : undefined, name: this.generateEventName(this.section.id, productIndex), value: product.id, onClick: event => this.preventLockedDeselect(event, isChecked), onChange: event => this.preventLockedDeselect(event, isChecked) }), h("img", { src: product.image.url || salla.url.cdn('images/s-empty.png'), loading: "lazy", alt: product.image.alt || product.name, class: "s-multiple-bundle-product-image" })), h("div", { class: "s-multiple-bundle-product-content-wrapper" }, h("div", { class: "s-multiple-bundle-product-content" }, h("div", { class: "s-multiple-bundle-product-details" }, h("div", { class: "s-multiple-bundle-product-title-wrapper" }, h("h2", { class: "s-multiple-bundle-product-title" }, h("a", { href: product?.url || '#', target: "_blank", rel: "noopener noreferrer" }, product.name))), h("div", { class: "s-multiple-bundle-product-price-wrapper" }, h("span", { class: "s-multiple-bundle-product-price" }, h("span", { innerHTML: salla.money(product.price) })), product.sale_price > 0 && (h("span", { class: "s-multiple-bundle-product-price-discount" }, h("span", { innerHTML: salla.money(product.regular_price) }))))), product.quantity_in_group > 0 && product.quantity !== 0 && (h("span", { class: "s-multiple-bundle-product-badge" }, salla.lang.get('pages.products.pieces'), h("span", null, product.quantity_in_group))), product.quantity === 0 && (h("span", { class: "s-multiple-bundle-product-badge" }, salla.lang.get('pages.products.quantity_in_group_finished')))), product.options?.length > 0 && (h("button", { class: "s-multiple-bundle-product-button", onClick: () => this.handleOptionsClick(product), type: "button" }, optionsButtonLabel, h("span", { class: "s-multiple-bundle-product-button-icon", innerHTML: optionsArrowIcon }))))))); }))))); } get host() { return getElement(this); } }; SallaMultipleBundleProductSlider.style = sallaMultipleBundleProductSliderCss; export { SallaMultipleBundleProductOptionsModal as salla_multiple_bundle_product_options_modal, SallaMultipleBundleProductSlider as salla_multiple_bundle_product_slider };