1class CustomRecommendations{constructor(container){this.container=container,this.relatedIds=JSON.parse(this.container.getAttribute("data-related-ids")),this.sectionId=this.container.getAttribute("data-section-id"),this.relatedProductsContainer=this.container.querySelector("#related-products"),this.storefrontAccessToken=this.container.getAttribute("data-storefront-access-token"),this.graphqlEndpoint="/api/2023-10/graphql.json",this.loadingText=this.container.dataset.loadingText||"Loading related products...",this.noRecommendationsText=this.container.dataset.noRecommendationsText||"No related products found",this.init()}init(){if(!this.relatedIds||!this.relatedIds.length)return;const sliderElement=document.createElement("slider-element");sliderElement.id=`Slider-${this.sectionId}`,sliderElement.className=this.container.getAttribute("data-slider-class")||"grid slider",sliderElement.setAttribute("selector",".card-grid>.card");const motionList=document.createElement("motion-list");motionList.className=this.container.getAttribute("data-grid-class")||"card-grid grid",sliderElement.appendChild(motionList),this.relatedProductsContainer.innerHTML=`<div class="text-center py-8">${this.loadingText}</div>`,this.motionList=motionList,this.sliderElement=sliderElement,this.fetchProductsByIds(this.relatedIds).then(products=>this.renderProducts(products)).catch(error=>{console.error("Error processing products:",error),this.relatedProductsContainer.innerHTML=`<div class="text-center py-8">${this.noRecommendationsText}</div>`})}async fetchProductsByIds(productIds){const skuQuery=productIds.join(" OR "),query=` 2 query getProductsBySKU { 3 products(first: ${productIds.length}, query: "${skuQuery}") { 4 nodes { 5 id 6 title 7 handle 8 vendor 9 availableForSale 10 metafield(namespace: "custom", key: "pack_skus") { 11 value 12 } 13 featuredImage { 14 url(transform: { maxWidth: 800 }) 15 } 16 images(first: 2) { 17 edges { 18 node { 19 url(transform: { maxWidth: 800 }) 20 } 21 } 22 } 23 variants(first: 1) { 24 edges { 25 node { 26 id 27 price { 28 amount 29 currencyCode 30 } 31 compareAtPrice { 32 amount 33 currencyCode 34 } 35 availableForSale 36 } 37 } 38 } 39 } 40 } 41 } 42 `;try{const result=await(await fetch(this.graphqlEndpoint,{method:"POST",headers:{"Content-Type":"application/json","X-Shopify-Storefront-Access-Token":this.storefrontAccessToken},body:JSON.stringify({query})})).json();if(result.errors)throw console.error("GraphQL errors:",result.errors),new Error("Error fetching products via GraphQL");return result.data.products.nodes.filter(node=>node!==null)}catch(error){throw console.error("Error fetching products with GraphQL:",error),error}}renderProducts(products){if(!products||products.length===0){this.relatedProductsContainer.innerHTML=`<div class="text-center py-8">${this.noRecommendationsText}</div>`;return}this.relatedProductsContainer.innerHTML="",this.relatedProductsContainer.appendChild(this.sliderElement),products.forEach(product=>this.renderProductCard(product)),typeof window.initializeSlider=="function"&&window.initializeSlider(this.sliderElement)}renderProductCard(product){const card=document.createElement("div");card.className="card product-card product-card--standard product-card--thickness flex flex-col leading-none relative overflow-hidden";const productId=product.id.split("/").pop(),productUrl=`/products/${product.handle}`,productTitle=product.title,productVendor=product.vendor,imageUrl=product.featuredImage?product.featuredImage.url:"",isAvailable=product.availableForSale,variantId=product.variants.edges[0]?.node.id.split("/").pop()||"",packSelector=this.renderPackSelector(product,productId),quickAddAvailableHidden=isAvailable?"":"hidden",quickAddSoldoutHidden=isAvailable?"hidden":"";let cardHtml=` 43 <div class="product-card__media relative h-auto overflow-hidden"> 44 <button type="button" class="quick-view__button button button--secondary z-2 absolute top-0 right-0 opacity-0" is="hover-button" aria-controls="Quickview-${this.sectionId}-${productId}" aria-expanded="false">
45 <span class="btn-fill" data-fill></span> 46 <span class="btn-text"> 47 <svg class="icon icon-eye icon-sm" viewBox="0 0 20 20" stroke="currentColor" fill="none" xmlns="http://www.w3.org/2000/svg"> 48 <path stroke-linecap="round" d="M18.3334 10C18.3334 12.0833 15.8334 16.6667 10 16.6667C4.16669 16.6667 1.66669 12.0833 1.66669 10C1.66669 7.91668 4.16669 3.33334 10 3.33334C15.8334 3.33334 18.3334 7.91668 18.3334 10Z"></path> 49 <path stroke-linecap="round" d="M12.5 10C12.5 11.3807 11.3807 12.5 10 12.5C8.61931 12.5 7.50002 11.3807 7.50002 10C7.50002 8.6193 8.61931 7.50001 10 7.50001C11.3807 7.50001 12.5 8.6193 12.5 10Z"></path> 50 </svg> 51 <span class="sr-only">Ver</span> 52 </span> 53 <span class="btn-loader"> 54 <span></span> 55 <span></span> 56 <span></span> 57 </span> 58 </button> 59 60 <quick-view id="Quickview-${this.sectionId}-${productId}" class="quick-view x-modal drawer z-40 fixed bottom-0 left-0 h-full w-full pointer-events-none" data-product-url="${productUrl}" role="dialog" aria-label="Elegir opciones para ${productTitle}" aria-modal="true"> 61 <overlay-element class="overlay fixed-modal invisible opacity-0 fixed bottom-0 left-0 w-full h-screen pointer-events-none" aria-controls="Quickview-${this.sectionId}-${productId}" aria-expanded="false"></overlay-element> 62 <div class="drawer__inner z-10 absolute top-0 flex flex-col w-full h-full overflow-hidden"> 63 <gesture-element class="drawer__header flex justify-between opacity-0 invisible relative"> 64 <button class="button button--secondary button--close drawer__close z-1 absolute top-0 right-0 flex items-center justify-center opacity-0" type="button" is="hover-button" aria-controls="Quickview-${this.sectionId}-${productId}" aria-expanded="false" aria-label="Cerrar"> 65 <span class="btn-fill" data-fill></span> 66 <span class="btn-text"> 67 <svg class="icon icon-close icon-sm" viewBox="0 0 20 20" stroke="currentColor" fill="none" xmlns="http://www.w3.org/2000/svg"> 68 <path stroke-linecap="round" stroke-linejoin="round" d="M5 15L15 5M5 5L15 15"></path> 69 </svg> 70 </span> 71 <span class="btn-loader"> 72 <span></span> 73 <span></span> 74 <span></span> 75 </span> 76 </button> 77 </gesture-element> 78 <div class="quick-view__content drawer__content opacity-0 invisible flex flex-col h-full grow shrink"></div> 79 </div> 80 </quick-view> 81 82 <div class="badges z-2 absolute grid gap-3 pointer-events-none"></div> 83 84 <a class="block relative media media--${this.container.getAttribute("data-image-ratio")||"portrait"} overflow-hidden" href="${productUrl}" aria-label="${productTitle}" tabindex="-1"> 85 ${imageUrl?`<img src="${imageUrl}" alt="${productTitle}" loading="lazy" is="lazy-image">`:""} 86 </a> 87 88 <div class="quick-add flex justify-end md:justify-center absolute w-full z-1 pointer-events-none quick-add-available ${quickAddAvailableHidden}"> 89 <form method="post" action="/cart/add" id="QuickAddProductForm-${this.sectionId}-${productId}" accept-charset="UTF-8" class="shopify-product-form" enctype="multipart/form-data" is="product-form"> 90 <input type="hidden" name="form_type" value="product"> 91 <input type="hidden" name="utf8" value="\u2713"> 92 <input type="hidden" name="id" value="${variantId}"> 93 <button type="submit" class="button button--primary pointer-events-auto md:opacity-0" is="hover-button" data-variant-id="${variantId}" aria-label="Agregar al carrito"> 94 <span class="btn-fill" data-fill></span> 95 <span class="btn-text"> 96 <svg class="icon icon-cart icon-sm md:hidden" viewBox="0 0 24 24" stroke="currentColor" fill="none" xmlns="http://www.w3.org/2000/svg"> 97 <path stroke-miterlimit="10" d="M7.1802 7.58C7.1802 4.36 9.2402 1.75 11.7902 1.75C14.3402 1.75 16.4002 4.36 16.4002 7.58M11.7902 7.58C2.0402 7.58 0.690197 6.97 2.3502 16.18C3.3002 21.48 3.9802 22.22 11.7902 22.22C19.6002 22.22 20.2802 21.47 21.2302 16.18C22.8902 6.97 21.5502 7.58 11.7902 7.58Z"></path> 98 </svg>
99 <span class="hidden md:block" data-sold-out="Agotado">Agregar al carrito</span> 100 </span> 101 <span class="btn-loader"> 102 <span></span> 103 <span></span> 104 <span></span> 105 </span> 106 </button> 107 <input type="hidden" name="product-id" value="${productId}"> 108 <input type="hidden" name="section-id" value="${this.sectionId}"> 109 </form> 110 </div> 111 <div class="quick-add flex justify-end md:justify-center absolute w-full z-1 pointer-events-none quick-add-soldout ${quickAddSoldoutHidden}"> 112 <button type="button" class="button button--secondary button--blur" disabled="disabled"> 113 Agotado 114 </button> 115 </div> 116 </div> 117 118 <div class="product-card__content grow flex flex-col justify-start text-left"> 119 <div class="product-card__top w-full"> 120 <span class="sr-only">Proveedor:</span> 121 <a class="caption reversed-link uppercase leading-none tracking-widest" href="/collections/vendors?q=${encodeURIComponent(productVendor)}" title="${productVendor}">${productVendor}</a> 122 </div> 123 124 <div class="product-card__details flex flex-col lg:flex-row items-baseline gap-2 w-full"> 125 <p class="grow"> 126 <a class="product-card__title reversed-link text-base-xl font-medium leading-tight" href="${productUrl}">${productTitle}</a> 127 </p> 128 129 <div class="price flex flex-wrap lg:flex-col lg:items-end gap-2 md:gap-1d5"> 130 ${this.getPriceHtml(product)} 131 </div> 132 </div> 133 134 ${packSelector} 135 </div> 136 `;card.innerHTML=cardHtml,this.motionList.appendChild(card)}renderPackSelector(product,productId){if(!product.metafield||!product.metafield.value)return"";const elementId=`${this.sectionId}-${productId}`,formId=`QuickAddProductForm-${this.sectionId}-${productId}`,price=product.variants.edges[0]?.node.price?.amount||"0",compareAtPrice=product.variants.edges[0]?.node.compareAtPrice?.amount||"";return` 137 <div class="product-pack-variant-selector" data-pack-variant-selector data-context="card" style="display:none"> 138 <div class="form__label flex items-center justify-between gap-2 w-full"> 139 <label class="flex gap-2">Packs:</label> 140 </div> 141 <pack-variant-selects 142 id="PackVariantSelector-${elementId}" 143 class="pack-variant-selects" 144 data-section-id="${this.sectionId}" 145 data-product-id="${productId}" 146 data-product-handle="${product.handle}" 147 data-product-form-id="${formId}" 148 data-storefront-access-token="${this.storefrontAccessToken}" 149 data-context="card"> 150 <div class="pack-radio-group"> 151 <div class="pack-radio-item"> 152 <input type="radio" 153 id="pack-default-${elementId}" 154 name="pack-option-${elementId}" 155 value="${product.handle}" 156 class="sr-only pack-radio" 157 data-is-default="true" 158 data-available="${product.availableForSale}" 159 data-variant-id="${product.variants.edges[0]?.node.id.split("/").pop()||""}" 160 data-product-title="${product.title}" 161 data-product-image="${product.featuredImage?.url||""}" 162 data-product-price="${price}" 163 data-product-compare-at-price="${compareAtPrice}" 164 checked> 165 <label for="pack-default-${elementId}" class="active">1 unidad</label> 166 </div> 167 168 <template data-pack-data>${product.metafield.value}</template> 169 </div> 170 </pack-variant-selects> 171 </div> 172 `}getPriceHtml(product){if(!product.variants||!product.variants.edges||
172!product.variants.edges.length)return"";const variant=product.variants.edges[0].node,price=window.theme.formatMoney(parseFloat(variant.price.amount)*100,window.theme.moneyFormat);return variant.compareAtPrice&&parseFloat(variant.compareAtPrice.amount)>parseFloat(variant.price.amount)?` 173 <span class="price__sale whitespace-nowrap">${window.theme.formatMoney(parseFloat(variant.compareAtPrice.amount)*100,window.theme.moneyFormat)}</span> 174 <span class="price__regular whitespace-nowrap">${price}</span> 175 `:`<span class="price__regular whitespace-nowrap">${price}</span>`}}document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll("[data-custom-recommendations]").forEach(container=>{new CustomRecommendations(container)})}); 176//# sourceMappingURL=/cdn/shop/t/11/assets/custom-recommendations.js.map?v=153808704974993533371751288551
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.