var miniCart = { jsonCart: null, idCart: null, component: document.querySelector(".store-minicart-component"), currency : '€', errorCodes: { 'noError' : 'NO_ERROR', 'noStockUnits': 'NO_STOCK_UNITS', 'fewStockUnits': 'FEW_STOCK_UNITS', 'cartOutdated' : 'CART_OUTDATED', 'cartInactive' : 'CART_INACTIVE', 'customerTokenOutdated' : 'CUSTOMER_TOKEN_OUTDATED', 'updatedProductStockError' : 'UPDATED_PRODUCT_STOCK_ERROR', 'shippingAddressNotSelected' : 'SHIPPING_ADDRESS_NOT_SELECTED', 'placeOrderError' : 'PLACE_ORDER_ERROR', 'unhandledError' : 'UNHANDLED_ERROR', }, scrollToTop: false, init: function () { miniCart.setPosition(); miniCart.checkLocalStorageCart(); miniCart.events(); miniCart.resetStoreCookie(); }, setPosition: () =>{ let component = miniCart.component; let headerMiniCart = component.closest(".header-es").querySeleor(".header-store .minicart"); if(headerMiniCart && component){ headerMiniCart.after(component); } }, events: function () { let component = miniCart.component; document.querySelector(".header .header-store .minicart").addEventListener("click", (e) =>{ let target = e.target; if (window.matchMedia("(min-width: 1024px)").matches) { miniCart.redirectToCart() }else{ if(component.classList.contains("minicart-products")){ miniCart.redirectToCart() }else{ if(component.classList.contains("show")){ miniCart.hideCart(); }else{ miniCart.showCart(); } } } }) document.addEventListener("click", (e) =>{ let target = e.target; if(!target.closest(".header-store")){ if(component.classList.contains("show")){ miniCart.hideCart(); } } }) let openCart = false; document.querySelector(".header .header-store .minicart").addEventListener("mouseover", (e) =>{ if (window.matchMedia("(min-width: 1024px)").matches) { let target = e.target; if(!openCart){ miniCart.showCart(); openCart = true; } } }) document.querySelector(".header .header-store").addEventListener("mouseleave", (e) =>{ let target = e.target; if(!target.closest(".store-minicart-component")){ miniCart.hideCart(); openCart = false; } }) component.querySelector(".minicart-header .rp-close").addEventListener("click", (e) =>{ e.stopImmediatePropagation(); let target = e.target; miniCart.hideCart(); Repsol.Analytics.Store.clickCartClose($(target)) }) component.querySelector(".js-show-login").addEventListener("click", (e) =>{ e.preventDefault(); miniCart.hideCart(); RepsolRegisterLoginModal.showModal(); RepsolLoginStore.open(); }) }, showCart: async function () { let component = miniCart.component; component.classList.add("show"); document.querySelector("body").classList.add("minicart-open"); if(component.classList.contains("minicart-products")){ miniCart.checkScrollProductsList() } RepsolHeaderMenu.hideUserDropdowns(); }, hideCart: function () { let component = miniCart.component; component.classList.remove("show"); document.querySelector("body").classList.remove("minicart-open"); }, checkLocalStorageCart: async function() { const activeCart = localStorage.getItem("activeCart"); if(activeCart === 'true'){ let component = miniCart.component; const storageCartId = window.localStorage?.cartId; const cartId = storageCartId ? JSON.parse(storageCartId)?.id : undefined; if(cartId) { Repsol.utils.setLoader(true, $(component)) let cartResponse, cart cartResponse = await RepsolStore.getCartOverlay(); const errors = cartResponse?.errors; if(errors) { await miniCart.handleMiniCartErrors(errors); cartResponse = await RepsolStore.getCartOverlay(); } cart = cartResponse?.data?.cart; RepsolStore.saveCartToLocalStorage(cart); miniCart.loadProductsToMiniCart(); Repsol.utils.setLoader(false, $(component)) } else { miniCart.createEmptyCart(); } }else{ miniCart.emptyCart(); } }, showWayletMessage: () => { let component = miniCart.component; let total = component.querySelector('.grand_total')?.getAttribute('data-price') let currency = miniCart.currency; let percentageNotLogged = component.getAttribute('data-percentage-not-logged'); let percentageLoggedNotWaylet = component.getAttribute('data-percentage-logged-not-waylet'); let percentageLoggedNotWaylet2 = component.getAttribute('data-percentage-2-logged-not-waylet'); let data = { 'total' : total, 'currency': currency, 'percentageNotLogged': percentageNotLogged, 'percentageLoggedNotWaylet' : percentageLoggedNotWaylet, 'percentageLoggedNotWaylet2' : percentageLoggedNotWaylet2 } RepsolConecta.showWayletMessage($(component), data); }, handleMiniCartErrors: async function(errors) { const error = RepsolStoreErrors.checkHandledErrorType(errors) const errorCodes = miniCart.errorCodes if(error === errorCodes.cartOutdated) { await RepsolStore.handleOutdatedCart(); } if(error === errorCodes.cartInactive) { miniCart.createEmptyCart(); } if(error === errorCodes.customerTokenOutdated) { await RepsolStore.loginUserOnMagento(); await RepsolStore.restoreUserCart(); } if (error === errorCodes.updatedProductStockError) { miniCart.showProductFewStockError(errors); } if(error === errorCodes.shippingAddressNotSelected) { const errorMesage = 'Selecciona una direccion de envio antes de tramitar el pedido'; } if(error === errorCodes.placeOrderError) { miniCart.showUnhandledErrorMessage(); } if(error === errorCodes.unhandledError) { miniCart.showUnhandledErrorMessage(); } }, showUnhandledErrorMessage: function() { let component = miniCart.component; const errorMessage = component.getAttribute('data-unhandled-error-msg') RpAlert.msgError(errorMessage) Repsol.Analytics.Store.errorRpAlert(errorMessage); var myObj = $('.store-minicart-component'); var params = { error_type: errorMessage, error_description: errorMessage, }; Repsol.AnalyticsRomProd.errorRomProd(myObj, params); }, loginUserOnMagento: async function() { const magentoLoginResponse = await RepsolLoginStore.magentoLogin(); const errorCode = magentoLoginResponse?.errorCode; if (errorCode === 0) { const customerToken = magentoLoginResponse?.customerToken; localStorage.setItem("ct", JSON.stringify(customerToken)); } }, createEmptyCart: async function() { try { await RepsolStore.createNewCart(); miniCart.updateCart(); } catch(error) { RepsolStore.showUnhandledErrorMessage(); } }, createCart: function () { var settings = { "url": "/api/graphql" + RepsolGraphql.generateQueryParamRequest(), "method": "POST", "timeout": 5000, "headers": { "content-type": "application/json" }, "data": JSON.stringify({ query: `mutation { createEmptyCart }` }), "success": function (data, textStatus, request) { }, "error": function (request, textStatus, errorThrown) { } } $.ajax(settings).done(function (response) { if (response.errors && response.errors.length > 0) { console.log("error al crear carrito") } else { let date = new Date(); date.setDate(date.getDate() + 1); localStorage.setItem("cartId", `{"id": "${response.data.createEmptyCart}", "expDate":${date.getTime()}}`) miniCart.idCart = response.data.createEmptyCart; miniCart.updateCart(); } }).fail(function (jqXHR, textStatus, errorThrown) { console.log('Error:', errorThrown); }); }, newUserCart: function () { let url = "/bin/repsol-ecommerce/store/cart"; let token = miniCart.getLocalData("ct"); let data = { "operation": "getCustomerCart", "token": token } localStorage.setItem("cart", ""); localStorage.setItem("cartId", ""); RepsolLoginStore.isLoggedMagento() .then(resp => { let xhr = new XMLHttpRequest(); xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { if (this.status == 200) { let response = JSON.parse(this.responseText); if (response.errorCode == 0) { let date = new Date(); date.setDate(date.getDate() + 1); localStorage.setItem("cartId", `{"id": "${response.magentoResponse.magentoCartId}", "expDate":${date.getTime()}}`) miniCart.idCart = response.magentoResponse.magentoCartId; miniCart.loadProducts(); } else { } } else { console.log("servlet error: " + this.responseText) } } miniCart.updateCart(); }); xhr.open("POST", url); xhr.setRequestHeader("Content-Type", "application/json"); xhr.send(JSON.stringify(data)); }).catch(err => { console.log(err) }) }, updateCart: function (event) { let url = "/bin/repsol-ecommerce/store/cart"; let data = { "operation": "update", "cartId": miniCart.idCart, "token": miniCart.getLocalData("ct") || null }; var cart = miniCart.getLocalData("cart"); var jsonCart = ""; var products = "" var status = true; if (!event && cart && cart != "" && (cart != "undefined" || cart != undefined)) { if (cart.cart && cart.cart != "") { jsonCart = cart.cart; } else { jsonCart = cart } products = jsonCart.items ? jsonCart.items : ""; miniCart.updateCartFn(jsonCart, products); } else { RepsolLoginStore.isLoggedMagento().then(resp => { let xhr = new XMLHttpRequest(); xhr.addEventListener("readystatechange", function () { if (this.readyState === 4) { if (this.status == 200) { let response = JSON.parse(this.responseText); if (response.errorCode == 0) { jsonCart = response.magentoResponse; products = response.magentoResponse.cart.items; miniCart.updateCartFn(jsonCart, products); miniCart.setStorageProducts(products) if(sessionStorage.getItem('products') == 0) { miniCart.redirectCheckoutWithoutProducts() } } else { status = false; console.log("servlet error: " + response.errorCode) } } else { status = false; console.log("servlet error: " + this.responseText) } } }); xhr.open("POST", url); xhr.setRequestHeader("Content-Type", "application/json"); xhr.send(JSON.stringify(data)); }).catch(error => { var settings = { "url": "/api/graphql" + RepsolGraphql.generateQueryParamRequest(), "method": "POST", "timeout": 5000, "headers": { "content-type": "application/json" }, "data": JSON.stringify({ query: `{ cart(cart_id: "${miniCart.idCart}") { items { id uid product { stock_status name sku salable_quantity thumbnail{ url } price_range { minimum_price { final_price { value currency } } } ... on SimpleProduct{ capacidad_label talla_label } } quantity errors { code message } } prices { grand_total { value currency } } } }` }), "success": function (data, textStatus, request) { }, "error": function (request, textStatus, errorThrown) { } } $.ajax(settings).done(function (response) { jsonCart = response.data; if (response.errors) { miniCart.createCart(); localStorage.removeItem("cart"); } else { if (response.data && response.data.cart && response.data.cart.items) { products = response.data.cart.items; } miniCart.updateCartFn(jsonCart, products); } }).fail(function (jqXHR, textStatus, errorThrown) { console.log('Error:', errorThrown); }); }); } }, updateCartFn: function (jsonCart, products) { if (jsonCart.errors && response.errors.length > 0) { for (i = 0; i < products.length; i++) { if (products[i] == null) { products.splice(i, 1); } } if (products.length) { localStorage.setItem("cart", JSON.stringify(cart)); miniCart.loadProducts(); } } else if ((!!jsonCart && jsonCart.cart) || (!!jsonCart && jsonCart.items)) { localStorage.setItem("cart", JSON.stringify(jsonCart)); if (products.length > 0) { miniCart.loadProducts(); } else { miniCart.emptyCart(); miniCart.checkSummaryCount() } } else { miniCart.emptyCart(); } }, checkSummaryCount: function () { let component = miniCart.component; const $emptyMiniCart = component.querySelector(".minicart-empty"); const items = component.querySelectorAll('.minicart-product') let productCount = [] if($emptyMiniCart.classList.contains('d-none') && items.length > 0){ items.forEach((item) => { const productQty = parseInt(item.getAttribute("data-quantity")) productCount.push(productQty) }) const productTotal = productCount.reduce((a, b) => a + b, 0) if (productTotal > 0) { document.querySelector(".header .js-summary").innerText = productTotal; document.querySelector(".header .js-summary").classList.remove("d-none") }else{ document.querySelector(".header .js-summary").classList.add("d-none") } } else { document.querySelector(".header .js-summary").classList.add("d-none") miniCart.emptyCart(); } }, loadProducts: function () { let jsonCart = miniCart.getLocalData("cart"); let items = []; if (jsonCart && jsonCart != "") { if (jsonCart.items && jsonCart.items != "") { items = jsonCart.items; } else if (jsonCart.cart && jsonCart.cart != "") { items = jsonCart.cart.items ? jsonCart.cart.items : []; } if (items.length > 0) { miniCart.printProducts(items); miniCart.printTotalPrices(jsonCart); miniCart.showWayletMessage(); miniCart.checkSummaryCount(); miniCart.showStockErrorMessage() miniCart.updateButtonsStatus(); } } }, printProducts: (items) => { let component = miniCart.component; let miniCartProducts = component.querySelector(".minicart-products"); let miniCartProductsList = miniCartProducts.querySelector(".minicart-products-list"); miniCartProductsList.innerHTML = ""; let sizeText = component.getAttribute("data-size-text") let capacityText = component.getAttribute("data-capacity-text") let quantityText = component.getAttribute("data-quantity-text") const currency = miniCart.currency; let fragment = document.createDocumentFragment() const template = component.querySelector('#template-minicart-product').content for (let i = 0; i < items.length; i++) { let cloneTemplate = template.cloneNode(true) let item = items[i]; const productId = item.id; const productUid = item.uid; const productSku = item.product.sku; const productParentSku = item.product.parent_sku ? item.product.parent_sku[0] : ''; const productH1 = item.product.h1_label; const productNameCart = item.name; const productName = item.product.name; const itemName = productNameCart ? productNameCart : (productH1 ? productH1 : productName); const productImageAlt = productName; const damImageURL = RepsolStore.generateDAMImageURL(items[i]); const productImage = imgSrc = damImageURL ?? item.product?.thumbnail?.url; const productPrice = item?.product?.price_range?.minimum_price?.final_price?.value ?? 0; let productPriceRegular = item?.product?.price_range?.minimum_price?.regular_price?.value != productPrice ? item?.product?.price_range?.minimum_price?.regular_price?.value : ''; const reservationPriceItem = item.product?.reservation_price ? item.product.reservation_price : 0; const analyticsPriceToShow = reservationPriceItem ? reservationPriceItem : (productPriceRegular ? productPriceRegular : productPrice); const productQty = item.quantity ?? 0; const productVariant = RepsolStore.getVariant(item); const productCapacity = item.product?.capacidad_label; const productSize = item.product?.talla_label; const productTotal = item.prices?.row_total_including_tax?.value.toFixed(2).replace('.', ',') ?? 0 const productStock = item.product?.stock_status; const productSalableQuantity = (item.product?.salable_quantity && item.product?.salable_quantity >= 0) ? item.product.salable_quantity : 0; const productDescription = item.product?.short_description ? RepsolEcommerce.utils.removeHTMLTags(item?.product?.short_description.html) : ""; const productDiscount = item?.product?.price_range?.minimum_price?.discount?.amount_off.toFixed(2) ?? 0; const productCategories = item?.product?.category_ids ?? []; const categoriesList = Repsol.Analytics.Store.getProductCategories(productCategories); const productBrand = item.product?.manufacturer_label ? item.product?.manufacturer_label : ""; const productIndex = Repsol.Analytics.Store.getProductDataStorage('index', productSku); const productListName = Repsol.Analytics.Store.getProductDataStorage('item_list_name', productSku); //Bundle options const bundleOptions = item.bundle_options ? item.bundle_options : []; const bundleItems = item.product?.items ? item.product?.items : []; const error = item.errors ? true : false; let errorType = ''; const errorCodes = miniCart.errorCodes; let bundleOptionStockError = false; cloneTemplate.querySelector('.minicart-product').dataset.magentoId = productId cloneTemplate.querySelector('.minicart-product').dataset.id = productUid cloneTemplate.querySelector('.minicart-product').dataset.sku = productSku cloneTemplate.querySelector('.minicart-product').dataset.stock = productStock cloneTemplate.querySelector('.minicart-product').dataset.salableQuantity = productSalableQuantity cloneTemplate.querySelector('.minicart-product').dataset.listIndex = productIndex ? productIndex - 1 : "" cloneTemplate.querySelector('.minicart-product').dataset.quantity = productQty cloneTemplate.querySelector('.minicart-product').dataset.error = error cloneTemplate.querySelector('.product-image img').src = productImage cloneTemplate.querySelector('.product-image img').alt = productImageAlt cloneTemplate.querySelector('.product-description-name').textContent = itemName // Display product capacity label if (productCapacity && productCapacity.length > 0) { cloneTemplate.querySelector('.product-description-size').textContent = `${capacityText} ${productCapacity}` cloneTemplate.querySelector('.product-description-size').classList.remove('d-none'); } else if (productSize && productSize.length > 0) { cloneTemplate.querySelector('.product-description-size').textContent = `${sizeText} ${productSize}` cloneTemplate.querySelector('.product-description-size').classList.remove('d-none'); } else { cloneTemplate.querySelector('.product-description-size').textContent = '' cloneTemplate.querySelector('.product-description-size').classList.add('d-none'); } cloneTemplate.querySelector('.product-description-quantity').textContent = `${quantityText} ${productQty}` cloneTemplate.querySelector('.product-description-price').textContent = `${productTotal} ${currency}` if(productPriceRegular){ let finalProductPriceRegular = productPriceRegular; if (productQty > 1) { finalProductPriceRegular = (productPriceRegular * productQty); } finalProductPriceRegular = finalProductPriceRegular.toFixed(2).replace('.', ',') cloneTemplate.querySelector('.product-description-secondary-price').textContent = `${finalProductPriceRegular} ${currency}` cloneTemplate.querySelector('.product-description-secondary-price').classList.remove("d-none") }else{ cloneTemplate.querySelector('.product-description-secondary-price').textContent = "" cloneTemplate.querySelector('.product-description-secondary-price').classList.add("d-none") } //Analytics cloneTemplate.querySelector('.js-analytics-store-product').dataset.id = productParentSku ? productParentSku : productSku cloneTemplate.querySelector('.js-analytics-store-product').dataset.name = itemName cloneTemplate.querySelector('.js-analytics-store-product').dataset.price = analyticsPriceToShow cloneTemplate.querySelector('.js-analytics-store-product').dataset.quantity = productQty cloneTemplate.querySelector('.js-analytics-store-product').dataset.category = categoriesList cloneTemplate.querySelector('.js-analytics-store-product').dataset.brand = productBrand cloneTemplate.querySelector('.js-analytics-store-product').dataset.variant = productVariant cloneTemplate.querySelector('.js-analytics-store-product').dataset.image = productImage cloneTemplate.querySelector('.js-analytics-store-product').dataset.discount = productDiscount cloneTemplate.querySelector('.js-analytics-store-product').dataset.description = productDescription cloneTemplate.querySelector('.js-analytics-store-product').dataset.salableQuantity = productSalableQuantity cloneTemplate.querySelector('.js-analytics-store-product').dataset.sku = productSku cloneTemplate.querySelector('.js-analytics-store-product').dataset.listName = productListName //Bundle options if(bundleOptions.length > 0){ let bundleLabelOptions = []; bundleOptions.forEach((option) =>{ let valueOption = option.values && option.values.length > 0 ? option.values[0] : {}; let uidOption = valueOption.uid ? valueOption.uid : ""; let labelOption = valueOption.label ? valueOption.label : ""; if (uidOption) { let found = false; bundleLabelOptions.push(labelOption); bundleItems.forEach((item) =>{ let optionsItem = item.options ? item.options : []; optionsItem.forEach((option) => { if(uidOption == option.uid){ found = true; } }); }) //Bundle option out of stock if(error && !found){ bundleOptionStockError = true; } } }) if(bundleLabelOptions.length > 0){ let itemHtml = ""; bundleLabelOptions.forEach((label) =>{ itemHtml += `
  • ${label}
  • `; }) cloneTemplate.querySelector('.product-description-bundle-options').innerHTML = itemHtml; cloneTemplate.querySelector('.product-description-bundle-options').classList.remove("d-none") } } if(error && (productStock === 'OUT_OF_STOCK' || bundleOptionStockError)) { errorType = errorCodes.noStockUnits } else if(error && productStock === 'IN_STOCK') { errorType = errorCodes.fewStockUnits } else { errorType = errorCodes.noError } cloneTemplate.querySelector('.minicart-product').dataset.errorCode = errorType fragment.appendChild(cloneTemplate) miniCartProductsList.appendChild(fragment); } miniCartProducts.classList.remove("d-none") miniCart.removeEmptyCartBlock(); component.classList.add("minicart-products") }, printTotalPrices: (cart) => { let component = miniCart.component; let currency = miniCart.currency; cart = cart.cart ? cart.cart : cart; const items = cart.items; const prices = cart.prices ? cart.prices : ''; const totalPrice = prices.grand_total.value ? prices.grand_total.value.toFixed(2) : 0; const coupon = cart?.applied_coupons ? cart?.applied_coupons[0]?.code : undefined const appliedCouponText = component.getAttribute('data-coupon-label-text') ? component.getAttribute('data-coupon-label-text').trim() : ''; const giftCard = cart.applied_gift_cards ? cart.applied_gift_cards[0] : undefined; const appliedGiftCardText = component.getAttribute('data-gift-card-label-text'); let appliedDiscountText = ''; let grandTotalElem = component.querySelector(".grand_total"); let grandTotalSecondaryElem = component.querySelector(".grand_total_secondary"); let discountCouponElem = component.querySelector(".minicart-footer-discount-coupon"); grandTotalElem.innerText = `${totalPrice} ${currency}` grandTotalElem.setAttribute("data-price", totalPrice) let totalPriceSecondary = 0; for (const item of items) { let productQty = item.quantity ? item.quantity : 1; let productPrice = item?.product?.price_range?.minimum_price?.final_price?.value.toFixed(2) ?? 0 let productPriceRegular = item?.product?.price_range?.minimum_price?.regular_price?.value.toFixed(2) != productPrice ? item?.product?.price_range?.minimum_price?.regular_price?.value.toFixed(2) : 0; const reservationPrice = item?.product?.reservation_price ? item.product.reservation_price : 0; if(reservationPrice > 0){ totalPriceSecondary+= parseFloat(reservationPrice) * productQty }else if(productPriceRegular){ totalPriceSecondary+= parseFloat(productPriceRegular) * productQty }else{ totalPriceSecondary+= parseFloat(productPrice) * productQty } } totalPriceSecondary = totalPriceSecondary.toFixed(2) if(totalPriceSecondary != totalPrice){ grandTotalSecondaryElem.innerText = `${totalPriceSecondary} ${currency}` grandTotalSecondaryElem.classList.remove("d-none") }else{ grandTotalSecondaryElem.innerText = '' grandTotalSecondaryElem.classList.add("d-none") } // const totalNum = prices.grand_total.value; // Display cost-shipping-progress const totalNum = prices.subtotal_including_tax?.value; const dataList = miniCart.component.dataset.constants ? JSON.parse(miniCart.component.dataset.constants) : ''; const manualCostMinFreeShipping = miniCart.component.dataset.freeshipping ? JSON.parse(miniCart.component.dataset.freeshipping) : ''; let costMinFreeShipping = dataList && dataList.coste_min_envio ? dataList.coste_min_envio : ''; if (manualCostMinFreeShipping && manualCostMinFreeShipping != ''){ costMinFreeShipping = manualCostMinFreeShipping; } // console.log('Envio gratis a partir de' + costMinFreeShipping); if(totalNum){ const progress = Math.min(1, totalNum / costMinFreeShipping); const remaining = totalNum < costMinFreeShipping ? costMinFreeShipping - totalNum : 0; const barProgress = miniCart.component.querySelector('.bar-progress'); const shippingText = miniCart.component.querySelector('.cost-shipping-title'); if (totalNum >= costMinFreeShipping) { barProgress.style.width = `100%`; shippingText.innerHTML = `¡Envío gratis!`; } else { barProgress.style.width = `${progress * 100}%`; const remainingText = `Faltan ${remaining.toFixed(2).replace('.', ',')} € para el `; shippingText.innerHTML = `${remainingText}envío gratis!`; } }else{ component.querySelector('.cart-cost-shipping').classList.add('d-none'); } const discounts = prices?.discounts ?? []; let discountsArray = [] let discountLabel let discountLabelLower let discountValue let discountPercent let numberFind if (discounts && discounts.length > 0) { discountPercent = discounts[0]?.label; var match = discountPercent.match(/\d+/); if (match) { numberFind = parseInt(match[0], 10); } discounts.map(discount => discountsArray.push(discount?.label)) discountLabelLower = discountsArray.join(' - ') discountLabel = discountLabelLower.toUpperCase() discountValue = discounts.reduce((sum, discount) => sum + discount?.amount?.value, 0).toFixed(2) appliedDiscountText = appliedCouponText.replace("{0}", discountLabelLower);; } if(giftCard){ const gifCardValue = giftCard.applied_balance?.value; const gifCardCode = giftCard.code; const giftCardType = currency; appliedDiscountText = appliedGiftCardText.replace("{0}", `${gifCardValue}${giftCardType}`); } if((discounts && discounts.length > 0) || giftCard){ discountCouponElem.querySelector('.amount-title').textContent = appliedDiscountText; discountCouponElem.classList.remove('d-none') } else{ discountCouponElem.classList.add('d-none'); discountCouponElem.querySelector('.amount-title').textContent = ""; } miniCart.replacePriceDotForComma(component) }, updateButtonsStatus: () =>{ let component = miniCart.component; let storeBtn = component.querySelector(".cart-btn-store"); let isStorePage = miniCart.isStorePage() if(isStorePage){ storeBtn.classList.add("d-none") }else{ storeBtn.classList.remove("d-none") } }, emptyCart: function () { let component = miniCart.component; let isStorePage = miniCart.isStorePage() let isLogged = Repsol.utils.getCookie("isLogged"); component.querySelector(".minicart-description").classList.add("d-none"); if (isLogged === "true") { component.querySelector(".minicart-empty .js-show-login").classList.add("d-none"); if(isStorePage){ component.querySelector(".minicart-empty .js-show-news").classList.remove("d-none"); component.querySelector(".minicart-description-logged-store-pages").classList.remove("d-none"); }else{ component.querySelector(".minicart-empty .js-show-go-to-store").classList.remove("d-none"); component.querySelector(".minicart-description-logged").classList.remove("d-none"); } }else{ component.querySelector(".minicart-empty .js-show-login").classList.remove("d-none"); if (isStorePage) { component.querySelector(".minicart-empty .js-show-news").classList.remove("d-none"); component.querySelector(".minicart-description-unlogged-store-pages")?.classList.remove("d-none"); } else { component.querySelector(".minicart-empty .js-show-go-to-store").classList.remove("d-none"); component.querySelector(".minicart-description-unlogged")?.classList.remove("d-none"); } } component.querySelector(".minicart-empty").classList.remove("d-none"); component.querySelector(".minicart-products").classList.add("d-none"); component.classList.remove("minicart-products") }, removeEmptyCartBlock: function () { let component = miniCart.component; component.querySelector('.minicart-empty').classList.add('d-none'); }, replacePriceDotForComma: (obj) => { obj.querySelectorAll('.js-format-price').forEach( (item) => { let itemPrice = item.innerText.replace('.', ',') item.innerText = itemPrice }) }, getLocalData: function (nameSesion) { data = window.localStorage.getItem(nameSesion); try { return JSON.parse(data); } catch (e) { return data; } }, setStorageProducts: function(data) { let locationPath = window.location.href let checkout = locationPath.includes('tienda/checkout') ? true : false let productsLength = data.length if(checkout && productsLength == 0) { sessionStorage.setItem('products', 0) } }, redirectCheckoutWithoutProducts: function() { let locationPath = window.location.href let checkout = locationPath.includes('tienda/checkout') ? true : false let productsLength = sessionStorage.getItem('products') let pathOrigin = window.location.origin if(checkout && productsLength == 0) { sessionStorage.removeItem('products') window.location.href = `${pathOrigin}/tienda/carrito` } }, addProductAnalytics: function() { let component = miniCart.component; let sku = document.querySelector(".product-detail-component .product-detail-card")?.getAttribute("data-product-sku"); let analyticProduct = component.querySelector(`.js-analytics-store-product[data-sku='${sku}']`); if (analyticProduct) { const cartProduct = analyticProduct.closest(".minicart-product"); cartProduct.setAttribute("data-event", Repsol.Analytics.Store.event.addToCart); //Analytics Repsol.Analytics.Store.getProductsDataLayer(Repsol.Analytics.Store.event.addToCart, $(cartProduct)); cartProduct.removeAttribute("data-event"); } }, isSelectedOption: (productId) =>{ let isSelectedOption = false; let bundleSelectors = document.querySelectorAll(".product-detail-component .product-detail__dropdown.is-checked"); bundleSelectors.forEach((selector) => { let uid = selector.getAttribute("data-uid"); if(productId == uid){ isSelectedOption = true; } }) return isSelectedOption; }, addProduct: async function() { let component = miniCart.component; let productDetailComponent = document.querySelector(".product-detail-component"); let addCartBtn = productDetailComponent?.querySelector(".product-detail__cart-actions .button-repsol"); try { Repsol.utils.setLoader(true, $(productDetailComponent)) let item = productDetailComponent.querySelector(".product-detail-card").getAttribute("data-product-sku") let qty = 1 let productJson = document.querySelector('.product-json') && document.querySelector('.product-json').getAttribute('data-product') ? JSON.parse(document.querySelector('.product-json').getAttribute('data-product')) : '' let productType = productJson.__typename ? productJson.__typename : '' let bundleOptions = []; let selectOption = $(".product-detail__dropdown.is-checked").attr("data-uid"); if(productType == 'BundleProduct'){ let itemsBundle = productJson.items && productJson.items.length > 0 ? productJson.items : []; itemsBundle.forEach((item) => { let optionsItem = item.options ? item.options : [] optionsItem.forEach((option) => { if (optionsItem.length > 1) { if(miniCart.isSelectedOption(option.uid)){ bundleOptions.push(option.uid) } } else if (optionsItem.length == 1) { bundleOptions.push(option.uid); } }); }) } const cartId = localStorage?.cartId ? JSON.parse(localStorage.getItem('cartId'))?.id : undefined; if(!cartId){ await miniCart.createEmptyCart(); } let addProductToCartResponse, cart addProductToCartResponse = await RepsolStore.addProductsToCart(qty, item, bundleOptions) const errors = addProductToCartResponse?.errors if(errors) { await miniCart.handleMiniCartErrors(errors) addProductToCartResponse = await RepsolStore.addProductsToCart(qty, item) } cart = addProductToCartResponse?.data?.addProductsToCart?.cart RepsolStore.saveCartToLocalStorage(cart) miniCart.displayProductOnCart(addProductToCartResponse) localStorage.setItem("activeCart", true); } catch(error) { miniCart.showUnhandledErrorMessage(); } finally { Repsol.utils.setLoader(false, $(productDetailComponent)); } }, displayProductOnCart: function(response) { const cart = response?.data?.addProductsToCart?.cart const items = response?.data?.addProductsToCart?.cart?.items.length > 0 ? response?.data?.addProductsToCart?.cart?.items : [] const userErrors = response?.data?.addProductsToCart?.user_errors.length > 0 ? response?.data?.addProductsToCart?.user_errors : null if(items.length > 0) { miniCart.removeEmptyCartBlock(); miniCart.loadProducts(); miniCart.addProductAnalytics(); if (userErrors) { const cartItemWithStockError = checkCartItemWithStockError(items) const userErrorsArray = RepsolStoreErrors.checkUserErrorTypes(userErrors) const stockErrorCount = countDuplicateStrings(userErrorsArray, 'PRODUCT_WITH_STOCK_ERROR') const productNotAvailable = userErrorsArray.some(error => error === 'PRODUCT_NOT_AVAILABLE') function checkCartItemWithStockError(items) { function hasStockErrors(item) { return ( item?.product?.stock_status === 'IN_STOCK' && item?.errors !== null && item.quantity > item?.product?.salable_quantity ); } return items?.some(hasStockErrors) ?? false; } function countDuplicateStrings(array, string) { let count = 0; array.forEach(item => { if (item === string) { count++; } }); return count; } function countItemsWithErrors(items) { let itemsErrorCount = 0; items.forEach((item) => { if (item.product.stock_status === "IN_STOCK" && item.errors !== null && item.quantity > item.product.salable_quantity ) { itemsErrorCount++; } }); return itemsErrorCount; } if(stockErrorCount === 2 || productNotAvailable) { miniCart.showProductError() } else if(stockErrorCount === 1) { if(cartItemWithStockError) { miniCart.showAddProductSuccessMsg() } else { miniCart.showProductError() } } else { miniCart.showAddProductSuccessMsg() } } else { miniCart.showAddProductSuccessMsg() } } else { miniCart.emptyCart(); document.querySelector(".header .js-summary").classList.add("d-none") } }, showAddProductSuccessMsg: () =>{ let component = miniCart.component let info = { "type": 'rp-warning-success', "text": component.getAttribute("data-add-to-cart-success-msg-text"), "icon": component.getAttribute("data-add-to-cart-success-msg-icon") } RpAlert.msgContainer(info, undefined, false, true) const time = 3000; var obj = $(document).find(".warning-block-alert").eq(0); setTimeout(function(){ RpAlert.removeAlert(obj); }, time); document.querySelector(".warning-block-alert .warning-component").classList.add("rp-warning-add-product") miniCart.setPositionAddProductSuccessMsg(); window.scroll({ top: 0, behavior: "smooth", }); const pageScroll = document.documentElement.scrollTop; if(pageScroll == 0){ miniCart.scrollToTop = false; }else{ miniCart.scrollToTop = true; } }, setPositionAddProductSuccessMsg: () =>{ let isMegaMenuHeader = document.querySelector("header.header-megamenu") ? true: false let isMenuHeader2024 = document.querySelector("header.header-2024") ? true: false if(isMegaMenuHeader){ var heightHeader = document.querySelector("header").offsetHeight; }else if(isMenuHeader2024 && window.matchMedia("(min-width: 1024px)").matches){ var heightHeaderTop = document.querySelector("header").offsetHeight; if(document.querySelector("header-bottom")){ var heightHeaderBottom = document.querySelector("header-bottom").offsetHeight; }else{ var heightHeaderBottom = 57; } var heightHeader = heightHeaderTop + heightHeaderBottom; }else{ var heightHeader = document.getElementById("headTop").offsetHeight; } let linksBarElement = document.querySelector(".linksbar-ecommerce-component"); if(linksBarElement && linksBarElement.style.display !== "none"){ linksBarHeight = 64; heightHeader += linksBarHeight; } let storeMessage = document.querySelector(".store-message-component") ? document.querySelector(".store-message-component").offsetHeight : 0; let topPosition = heightHeader + storeMessage; let warningMsg = document.querySelector(".warning-block-alert .warning-component"); if(warningMsg){ warningMsg.style.cssText = `top: ${topPosition}px !important;` } }, showProductError: function() { const $product = $('.product-detail-component').find('.product-detail-card') const $productWithVariantError = $('.store-minicart-component').attr('msg-stock-var') const $productError = $('.store-minicart-component').attr('msg-stock') const $productWithVariants = $product.find(".product-detail__options").length > 0 ? true : false let errorMessage if ($productWithVariants) { errorMessage = $productWithVariantError textActive = $product.find(".product-detail__options").find(".active").find('span').html() let textReplace = errorMessage.replace("{0}", textActive) errorMessage = textReplace } else { errorMessage = $productError } $product.find('.product-detail__cart-actions .error-msg').removeClass('d-none') $product.find('.product-detail__cart-actions .error-msg').text(errorMessage) $product.find('.product-detail__cart-actions .js-add-cart .rp-btn').addClass('disabled') $product.find('.product-detail__stock-actions').addClass('d-none'); //Analytics Repsol.Analytics.Store.errorStock(errorMessage); let params = { error_type: 'out of stock', error_description: errorMessage, } Repsol.AnalyticsRomProd.errorRomProd($(minicart.component), params); }, showStockErrorMessage: function() { const component = miniCart.component; const products = component.querySelectorAll('.minicart-product') const noStockErrorMsg = component.getAttribute("data-no-stock-error-msg") const fewStockErrorMsg = component.getAttribute("data-few-stock-error-msg") const repeatedProductFewStockErrorMsg = component.getAttribute('data-repeated-product-few-stock-error-msg') const errorCodes = miniCart.errorCodes; let productErrors = [] const template = component.querySelector('#template-minicart-product-error').content let fragment = document.createDocumentFragment() products.forEach((item) => { let errorMessage = ""; const errorCode = item.getAttribute('data-error-code') const error = item.getAttribute('data-error') const salableQuantity = item.getAttribute('data-salable-quantity') const productSku = item.getAttribute('data-sku'); const repeatedProducts = component.querySelectorAll(`.minicart-product[data-sku="${productSku}"]`); if(errorCode === errorCodes.noStockUnits) { errorMessage = noStockErrorMsg } if(errorCode === errorCodes.fewStockUnits) { errorMessage = fewStockErrorMsg.replace('{0}', salableQuantity) if(repeatedProducts.length > 1){ errorMessage = repeatedProductFewStockErrorMsg } } item.querySelector(".warning-block-alert")?.remove(); if(errorCode != errorCodes.noError){ productErrors.push(error) template.querySelector(".warning-text").textContent = errorMessage const cloneTemplate = template.cloneNode(true) fragment.appendChild(cloneTemplate) let div = document.createElement('div') div.appendChild(fragment) html = div.innerHTML item.querySelector(".minicart-product-content-botton").innerHTML += html Repsol.Analytics.Store.errorStock(errorMessage); let params = { error_type: 'out of stock', error_description: errorMessage, } Repsol.AnalyticsRomProd.errorRomProd($(item), params); } }) }, getProductsFromLocalStorageCart: function() { const localStorageCart = JSON.parse(localStorage.getItem('cart')); return localStorageCart?.cart?.items || localStorageCart?.items; }, loadProductsToMiniCart: function() { let component = miniCart.component; const products = miniCart.getProductsFromLocalStorageCart(); if (products && products.length > 0) { miniCart.loadProducts(); } else { miniCart.emptyCart(); miniCart.checkSummaryCount(); } }, showProductFewStockError: function(errors) { let component = miniCart.component; let message = errors[0]?.message.toString() let products = document.querySelectorAll('.minicart-product') let pattern = /SKU (\d+)/ let match = message.match(pattern) let sku = match ? match[1] : '' let productErrorMsg = component.getAttribute('msg-stock') const errorCodes = miniCart.errorCodes; let productErrors = [] const template = component.querySelector('#template-minicart-product-error').content let fragment = document.createDocumentFragment() products.forEach(product => { let productSku = product.getAttribute('data-sku') item.querySelector(".warning-block-alert")?.remove(); if(sku === productSku) { template.querySelector(".warning-text").textContent = productErrorMsg const cloneTemplate = template.cloneNode(true) fragment.appendChild(cloneTemplate) let div = document.createElement('div') div.appendChild(fragment) html = div.innerHTML product.querySelector(".minicart-product-content").innerHTML += html product.setAttribute('data-error', true) product.setAttribute('data-error-code', errorCodes.fewStockUnits) const error = product.getAttribute('data-error') productErrors.push(error) Repsol.Analytics.Store.errorStock(productErrorMsg); let params = { error_type: 'out of stock', error_description: productErrorMsg, } Repsol.AnalyticsRomProd.errorRomProd($(product), params); } }) }, redirectToCart: () =>{ let component = miniCart.component; let cartPage = component.getAttribute("data-cart-page"); if(cartPage){ window.location.href = cartPage } }, checkScrollProductsList: () =>{ let component = miniCart.component; let minicartBody = component.querySelector(".minicart-products .minicart-body") minicartBodyHeight = minicartBody.offsetHeight; let productsList = component.querySelector(".minicart-products-list") productsListHeight = productsList.offsetHeight; if(productsListHeight > minicartBodyHeight){ minicartBody.classList.add("minicart-body--scroll") }else{ minicartBody.classList.remove("minicart-body--scroll") } }, isStorePage: () =>{ let locationPath = window.location.href let isStorePage = locationPath.includes('tienda') ? true : false return isStorePage; }, resetStoreCookie: () => { RepsolLoginStore.close(); } } if(window.performance) { let data = window.performance.getEntriesByType("navigation")[0].type if(data == 'reload') { miniCart.redirectCheckoutWithoutProducts() } } $(document).ready(function () { miniCart.init(); }); window.addEventListener("scroll", (event) => { const pageScroll = document.documentElement.scrollTop; if(pageScroll == 0){ miniCart.scrollToTop = false; } if(!miniCart.scrollToTop){ let addProductSuccessMsg = document.querySelector(".rp-warning-add-product") let isMegaMenuHeader = document.querySelector("header.header-megamenu") ? true: false let isHeader2024 = document.querySelector("header.header-2024") ? true: false if (addProductSuccessMsg){ if(pageScroll > 0 && (isMegaMenuHeader || isHeader2024)){ document.querySelector(".warning-block-alert .warning-component").style.cssText = `top: 0px !important; z-index: 1500;` }else{ miniCart.setPositionAddProductSuccessMsg(); } } } })