{"version":3,"file":"tag.js","mappings":";;;;AAAA;AACA;AACA;AACA;AACO;;AAEP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA,IAAI;AACJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACO;;AAEP;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,qBAAqB,UAAU,GAAG,YAAY;AAC9C;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACO;AACP;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;AACO;AACP;AACA,8CAA8C,UAAU;AACxD;;AAEA;AACA;AACA;AACO;AACP;;AAEA,mCAAmC,YAAY;AAC/C,8CAA8C,UAAU;AACxD;;AAEA;AACA;AACA;AACO;AACP;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,mDAAmD,SAAS;AAC5D;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,WAAW;AACX;AACA;AACA,WAAW;AACX;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEO;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,EAAE;AAC7B;AACA;;AAEA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACO;AACP;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACO;;AAEP;AACA;AACA;AACA;AACA;AACA,6CAA6C,IAAI;AACjD;AACA;;AAEA;AACA;AACA;AACA,GAAG,IAAI,YAAY;;AAEnB;;;AChVmD;;AAEnD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,YAAY,iBAAiB;;AAE7B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA,YAAY,WAAW;AACvB,IAAI,QAAQ;AACZ,IAAI,QAAQ;AACZ,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,4BAA4B,qCAAqC;AACjE,GAAG;;AAEH;;AAEA,YAAY,OAAO;;AAEnB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA,MAAM;AACN;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA,YAAY,UAAU;;AAEtB;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;AACH;;AAEA,iDAAe,UAAU,EAAC;;;ACjHoB;AACE;;AAEhD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,qBAAqB,iBAAiB;AACtC;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,+DAA+D;AAC/D,gEAAgE;AAChE,WAAW;AACX;AACA,SAAS;;AAET;;AAEA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA,WAAW;AACX,SAAS;;AAET;;AAEA;AACA;AACA,YAAY,UAAU;AACtB;AACA,UAAU;AACV;AACA,YAAY,UAAU;AACtB;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,aAAa;AACb,GAAG;AACH;AACA;;AAEA;AACA;AACA,MAAM;AACN,2CAA2C,QAAQ;AACnD;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO;;AAEP,MAAM,UAAU;;AAEhB;AACA;AACA,UAAU,UAAU;AACpB,UAAU;AACV;AACA;AACA,WAAW;AACX;AACA,QAAQ;AACR;AACA,UAAU,UAAU;AACpB,UAAU;AACV;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA,4CAAe,KAAK,EAAC;;;AC7LrB;AACA;AAC4B;AAC0B;;AAEtD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,wDAAwD,UAAU;;AAElE;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8BAA8B,aAAa;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,oCAAoC,MAAM;AAC1C;;AAEA;AACA;AACA;AACA,kBAAkB,MAAM;AACxB;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,SAAS;;AAET;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,WAAW;;AAEX;AACA,UAAU;AACV;AACA;AACA;AACA;AACA,yEAAyE,MAAM,kBAAkB,MAAM;AACvG;AACA;AACA;AACA;AACA,+CAA+C,MAAM;AACrD;AACA;AACA,aAAa;AACb;AACA;AACA,OAAO;AACP;AACA,GAAG;;AAEH;AACA;AACA;AACA,wDAAwD,UAAU;;AAElE;AACA;AACA;AACA;AACA;;AAEA;;AAEA,wBAAwB,yBAAyB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,2DAA2D,UAAU,mBAAmB;AACxF;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,mDAAmD,SAAS;AAC5D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,4DAA4D,UAAU;;AAEtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,0BAA0B;;AAE1B,+CAA+C;AAC/C,+CAA+C;AAC/C,+CAA+C;;AAE/C;AACA;AACA,4BAA4B,oCAAoC;AAChE;AACA;AACA,uEAAuE,UAAU;AACjF;AACA,WAAW;;AAEX;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR,gDAAgD,mBAAmB;AACnE;AACA,QAAQ;AACR;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;AACA;;AAEA,OAAO;;AAEP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA,6CAA6C,WAAW;;AAExD;AACA,+DAA+D,WAAW;AAC1E,2DAA2D,WAAW;AACtE;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,8BAA8B,KAAK;AACnC;;AAEA;AACA,UAAU,KAAK;AACf,UAAU;AACV;AACA,UAAU,KAAK;AACf;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,iGAAiG;;AAE7G;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;;AAEX;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;;AAEX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,OAAO;AACP,GAAG;AACH;;AAEA,sDAAe,eAAe,EAAC;;;AC5oB6B;;AAE5D;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,OAAO;;AAEP;;AAEA,MAAM,eAAe;AACrB;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,YAAY;AACZ;AACA;AACA;AACA,GAAG;AACH;;AAEA,qDAAe,cAAc,EAAC;;;ACnG4B;AACI;;AAE9D;;AAEA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa;;AAEb;AACA;;AAEA;AACA;AACA,aAAa;AACb,WAAW;AACX,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,IAAI,gBAAgB;;AAEpB,IAAI,cAAc;;AAElB;AACA,GAAG;AACH;;AAEA;AACA;AACA,CAAC","sources":["webpack://build/../lovinwinev2/assets/javascripts/components/utilities.js","webpack://build/../lovinwinev2/assets/javascripts/common/cartDrawer.js","webpack://build/../lovinwinev2/assets/javascripts/components/store.js","webpack://build/../lovinwinev2/assets/javascripts/components/productPurchase.js","webpack://build/../lovinwinev2/assets/javascripts/components/infinityScroll.js","webpack://build/../lovinwinev2/assets/javascripts/pages/tag.js"],"sourcesContent":["// ===============================================================\n// ADIÇÃO MANUAL DE ASSET\n// ===============================================================\n// Usado para incluir assets no código de forma manual, conforme a necessidade\nexport function addAsset(source, onloadCallback) {\n\n if (!source || source === '') return console.error(`addAsset: caminho não definido.`)\n\n if (source.includes('.js')) {\n const scriptTag = document.createElement('script')\n scriptTag.setAttribute('src', source);\n\n if (onloadCallback && typeof onloadCallback === 'function') {\n scriptTag.onload = onloadCallback\n }\n\n return document.body.appendChild(scriptTag)\n\n } else if (source.includes('.css')) {\n const linkTag = document.createElement('link')\n linkTag.setAttribute('rel', 'stylesheet')\n linkTag.setAttribute('type', 'text/css')\n linkTag.setAttribute('href', source)\n return document.head.appendChild(linkTag)\n\n } else {\n const error = `addAsset: Erro ao criar o asset. Tipo de script não definido, ou não possui tratamento para este tipo de asset.`\n return console.error(error, source)\n }\n}\n\n// ===============================================================\n// BUSCA O CARRINHO ATIVO\n// ===============================================================\nexport async function getCart() {\n try {\n const response = await fetch('/carrinho');\n const cart = await response.json();\n return cart;\n } catch (error) {\n console.error('Erro ao buscar os dados do carrinho');\n console.error(error);\n }\n}\n\n// ===============================================================\n// SERIALIZE ARRAY\n// ===============================================================\nexport function serializeArray(form) {\n\n const formData = new FormData(form);\n const data = {};\n\n for (const [name, value] of formData) {\n data[name] = value\n }\n\n let formBody = [];\n\n for (const key in data) {\n const encodeKey = encodeURIComponent(key)\n const encodeValue = encodeURIComponent(data[key])\n formBody.push(`${encodeKey}=${encodeValue}`)\n }\n\n return formBody = formBody.join('&')\n \n}\n\n// ===============================================================\n// URL ENCODE FORM DATA\n// ===============================================================\nexport function urlencodeFormData(formData) {\n let string = '';\n\n function encode(s) {\n return encodeURIComponent(s).replace(/%20/g, '+');\n }\n\n for (const pair of formData.entries()) {\n if (typeof pair[1] == 'string') {\n string += (string ? '&' : '') + encode(pair[0]) + '=' + encode(pair[1]);\n }\n }\n return string;\n}\n\n// ===============================================================\n// SLIDE TOGGLE\n// ===============================================================\nexport function slideToggle(contentWrapper, content, duration = 500) {\n let initialHeight = window.getComputedStyle(contentWrapper).height;\n\n if (initialHeight == '0px') {\n return slideDown(contentWrapper, content, duration);\n } else {\n return slideUp(contentWrapper, duration);\n }\n}\n\n// ===============================================================\n// SLIDE UP\n// ===============================================================\nexport function slideUp(contentWrapper, duration = 500) {\n contentWrapper.style.height = '0px';\n contentWrapper.style.transition = `height ${duration} ease`;\n}\n\n// ===============================================================\n// SLIDE DOWN\n// ===============================================================\nexport function slideDown(contentWrapper, content, duration = 500) {\n let innerHeight = content.clientHeight;\n\n contentWrapper.style.height = `${innerHeight}px`;\n contentWrapper.style.transition = `height ${duration} ease`;\n}\n\n// ===============================================================\n// UPDATE DISCOUNT IN PRODUCT BLOCK\n// ===============================================================\nexport function updatePriceBlock() {\n const priceEls = document.querySelectorAll('[data-init-price]');\n\n if (priceEls == null) return;\n\n priceEls.forEach((priceEl) => {\n const discount = priceEl.dataset.discountPercent;\n\n priceEl.dispatchEvent(new Event('change'));\n\n // discount\n if (discount != '0') {\n priceEl.style.setProperty('--discount', `'-${discount}%'`);\n }\n });\n}\n\n// ===============================================================\n// PREÇO POR AJAX\n// ===============================================================\nexport function getPriceProd() {\n var selectors = document.querySelectorAll('[data-update-price]');\n var attr = 'update-price';\n\n if (selectors.length() > 0) {\n selectors.forEach((selector) => {\n var prodId = selector.dataset(attr);\n var url = '/produto/preco/' + prodId;\n\n if (prodId != '' && prodId != null) {\n $.ajax({\n url: url,\n type: 'GET',\n })\n .done((resp) => {\n selector.innerHTML = resp;\n })\n .fail((resp) => {\n console.error(resp);\n });\n }\n });\n }\n}\n\n// ===============================================================\n// DEBOUNCE\n// ===============================================================\n/*\n Debounce retorna uma função que enquanto continuar sendo chamada não é executada\n A função só será executada quando para de ser chamada por N milisegundos\n Útil para melhorar a performance de códigos que são executados muitas vezes por segundo, como o $(window).resize()\n\n Ex:\n \n $(window).resize(debounce(function() {\n // código a ser executado\n }, 500))\n \n No exemplo acima a função só será executada 500ms depois do último resize\n Abra o link abaixo e redimensione a janela branca e acompanhe o output do console\n Exemplo codepen: https://codepen.io/valkervieira/pen/oNgqyWY\n\n Um caso comum de uso é em lojas onde a seleção de um filtro na página de tag recarrega automáticamente a página\n Com o debounce o usuário pode escolher vários filtros rapidamente e a página só recarrega quando parar de escolher\n*/\n\nexport function debounce(func, wait, immediate) {\n var timeout;\n immediate || (immediate = true);\n\n return function () {\n var context = this,\n args = arguments;\n\n var later = function () {\n timeout = null;\n if (!immediate) func.apply(context, args);\n };\n\n var callNow = immediate && !timeout;\n\n clearTimeout(timeout);\n\n timeout = setTimeout(later, wait);\n\n if (callNow) func.apply(context, args);\n };\n}\n\n// ===============================================================\n// THROTTLE\n// ===============================================================\n/*\n Throttle diminui a frequencia que uma função é executada\n Enquanto no debounce a função só é executada quando para de ser chamada, no throttle ela\n continua sendo executada só que em um intervalo mínimo de N milisegundos (default = 250)\n\n Ex:\n\n $(window).resize(throttle() {\n // código a ser executado\n }, 500)\n\n No exemplo acima a função resize é chamada várias vezes por segundo mas só é executada 1 vez a cada 500ms\n Abra o link abaixo, redimensione a janela branca e acompanhe o console\n Exemplo codepen: https://codepen.io/valkervieira/pen/yLyKEPW\n\n Um caso comum de uso é checar se o scroll passou de um determinado ponto, para fixar um header ou alterar algum elemento do DOM\n*/\nexport function throttle(fn, threshhold, scope) {\n threshhold || (threshhold = 250);\n var last, deferTimer;\n return function () {\n var context = scope || this;\n\n var now = +new Date(),\n args = arguments;\n if (last && now < last + threshhold) {\n // hold on to it\n clearTimeout(deferTimer);\n deferTimer = setTimeout(function () {\n last = now;\n fn.apply(context, args);\n }, threshhold);\n } else {\n last = now;\n fn.apply(context, args);\n }\n };\n}\n\n// ===============================================================\n// FORMAT MONEY\n// ===============================================================\nexport function formatMoney(value) {\n // FORMATA UM VALOR\n return (\n 'R$ ' +\n value\n .toFixed(2)\n .replace('.', ',')\n .replace(/(\\d)(?=(\\d{3})+\\,)/g, '$1.')\n );\n}\n\n// ===============================================================\n// FORMAT VALUE\n// ===============================================================\n\nexport const formatValue = function (value = '') {\n let parsedValue = value;\n if (typeof value === 'number') {\n parsedValue = value.toFixed(2).toString();\n }\n return parsedValue.replace('.', ',');\n};\n\n// ===============================================================\n// VALIDA QUANTIDADE\n// ===============================================================\nexport function validateQuantity(_val) {\n // VALIDA SE A QUANTIDADE INFORMADA É UM NÚMERO\n if (!isNaN(_val)) {\n if (parseInt(_val) > 0) {\n return true;\n }\n }\n\n return false;\n}\n\n// ===============================================================\n// CLEAR NUMBER\n// ===============================================================\nexport function getClearNumber(_val) {\n // RETORNA UM NÚMERO LIMPO COMO INT\n if (!isNaN(_val)) {\n var clearNumber = parseInt(_val);\n\n return clearNumber;\n }\n\n return false;\n}\n\n// ===============================================================\n// LOADING MODAL\n// ===============================================================\nexport function modalLoading () {\n window.addEventListener('load', () => {\n document.body.classList.remove('-loading');\n document.querySelector('.modal__loading').style.display = 'none';\n });\n}\n\n// ===============================================================\n// LAZY IMAGE BACKGROUND\n// ===============================================================\nexport function setWhoBackground() {\n\n const setStyle = function () {\n window.hasWhoBackground = true;\n const element = document.querySelector('[data-who-bg]');\n if (element) {\n let img = element.getAttribute('data-who-bg');\n element.style.backgroundImage = `url(${img})`;\n }\n }\n\n const eventType = (window.innerWidth <= 1024) ? 'scroll' : 'mousemove'\n window.addEventListener(eventType, () => {\n setStyle()\n }, { once: true })\n\n}\n","import { addAsset } from \"../components/utilities\";\n\nconst CartDrawer = {\n root: document.querySelector('#component-cart-drawer-root'),\n buttons: document.querySelectorAll('[data-toggle-cart]'),\n countWrapper: document.querySelector('[data-cart-count]'),\n settings: window.cartDrawerSettings || false,\n instance: false,\n\n setCartDrawer: function() {\n const { settings, root } = CartDrawer;\n\n if (!root || !settings) return;\n \n // Define frete grátis\n const freeShipping = (settings.freeShippingValue > 1) ? settings.freeShippingValue : 0\n\n // Inicia o componente\n const componentCartDrawer = new Vnda.Component.CartDrawer({\n anchor: 'right',\n display: 'list',\n startOpen: false,\n titleCart: 'Carrinho de compras',\n disableShippingCalculation: false,\n freeShipping,\n suggestedProductsTag: 'relacionado-mini-cart',\n widthItemSuggested: 25,\n });\n\n // Renderiza o componente\n componentCartDrawer.render(root);\n\n // Salva instância em propriedade local\n CartDrawer.instance = componentCartDrawer;\n\n // dispara evento de carregamento, escutado por CartDrawer.show()\n root.dispatchEvent(new Event('vnda:cart-drawer-loaded'))\n },\n\n loadComponent: function() {\n const { settings } = CartDrawer;\n addAsset(settings.script, CartDrawer.setCartDrawer);\n addAsset(settings.styles);\n },\n\n handleCartButton: function(button) {\n // Evita múltiplos cliques caso o carrinho precisa ser instanciado primeiro\n if (button.classList.contains('-loading')) {\n return;\n }\n\n // Abre o cart drawer\n button.classList.add('-loading');\n CartDrawer.show(() => { button.classList.remove('-loading') })\n },\n\n show: function (callback) {\n\n const { root } = CartDrawer;\n\n // No mobile, fecha o menu primeiro\n if (window.mmenu) window.mmenu.close()\n\n // Instancia o componente, caso ainda não exista\n if (!CartDrawer.instance) CartDrawer.loadComponent();\n\n // Observa criação da instância inicial, caso não tenha\n if (CartDrawer.instance === false) {\n root.addEventListener('vnda:cart-drawer-loaded', () => {\n CartDrawer.instance.open()\n if (typeof callback === 'function') callback()\n })\n } else {\n // Já possui cart drawer instanciado, retorna abertura\n CartDrawer.instance.open();\n if (typeof callback === 'function') callback()\n }\n },\n\n getCartItens: async function () {\n try {\n const response = await fetch('/carrinho/itens');\n const itens = await response.json()\n return itens;\n\n } catch (error) {\n console.error('Erro ao buscar a quantidade de produtos do carrinho');\n console.error(error);\n }\n },\n\n updateCartCount: async function (_itemsCount = null) {\n let items = _itemsCount;\n if (_itemsCount == null) items = await CartDrawer.getCartItens();\n\n this.countWrapper.innerHTML = items;\n },\n\n init: function () {\n const _this = this;\n const { buttons } = _this;\n\n // Atualiza o contador de itens do carrinho\n _this.updateCartCount();\n\n if (buttons.length > 0) buttons.forEach(button => {\n button.addEventListener('click', () => {\n _this.handleCartButton(button)\n })\n })\n },\n};\n\nexport default CartDrawer;\n","import CartDrawer from '../common/cartDrawer';\nimport { urlencodeFormData } from './utilities';\n\nconst Store = {\n openCartDrawer: true,\n openCartDrawerMobile: true,\n\n addItem: async function (form, parent, callback) {\n const _this = this;\n const btnComprar = parent.querySelector('[data-action=\"add-cart\"]');\n const urlAdd = '/carrinho/adicionar';\n const formData = urlencodeFormData(new FormData(form));\n const boxResponse = parent.querySelector(\n '[data-form-product] .msg-response:not(.resp-validate)'\n );\n\n // console.info('addItem');\n // console.info(formData);\n\n if (!btnComprar.classList.contains('-adding')) {\n btnComprar.classList.add('-adding');\n\n try {\n const response = await fetch(urlAdd, {\n method: 'POST',\n headers: {\n 'Accept': 'application/json, text/javascript, */*; q=0.0',\n 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',\n },\n body: formData,\n });\n\n const html = await response.text();\n\n console.log('success');\n\n if (typeof callback == 'function') {\n callback('produto-adicionado', html, boxResponse, form);\n } else {\n _this.addItemResult('produto-adicionado', html, boxResponse, form);\n }\n } catch (error) {\n console.log('error');\n console.error(error);\n\n if (typeof callback == 'function') {\n callback('erro-adicionar', error, boxResponse, form);\n } else {\n _this.addItemResult('erro-adicionar', error, boxResponse, form);\n }\n }\n\n btnComprar.classList.remove('-adding');\n }\n },\n deleteItem: async function (itemId, item, removeItemResult) {\n const _this = this;\n\n if (!item.classList.contains('-removing')) {\n item.classList.add('-removing');\n\n try {\n const response = await fetch('/carrinho', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n _method: 'delete',\n item_id: itemId,\n }),\n });\n\n console.log('success');\n\n if (window.innerWidth > 768) {\n if (_this.openCartDrawer) {\n CartDrawer.updateCartCount();\n }\n } else {\n if (_this.openCartDrawerMobile) {\n CartDrawer.updateCartCount();\n }\n }\n\n if (typeof removeItemResult == 'function') {\n removeItemResult(item);\n }\n } catch (error) {\n console.log('Erro ao remover item do carrinho');\n console.log(error);\n }\n\n item.classList.remove('-removing');\n }\n },\n validateFormProduct: function (form) {\n // VALIDA O FORM DE PRODUTO PARA VER SE O PRODUTO PODE SER ADICIONADO\n var btnComprar = form.querySelector('[data-action=\"add-cart\"]');\n var validated = true;\n var errors = [];\n\n if (btnComprar.dataset.available == 'false') {\n validated = false;\n errors.push('');\n } else {\n // verifica se o sku foi selecionado\n if (form.querySelector('[name=\"sku\"]').value == '') {\n validated = false;\n errors.push('Selecione um atributo para o produto');\n }\n\n // verifica se a quantidade é válida\n if (form.querySelector('input[name=\"quantity\"]').value <= 0) {\n validated = false;\n errors.push('Quantidade indisponível');\n }\n }\n\n return { validated, errors };\n },\n setRespValidateProduct: function (resp, form, boxResponse) {\n let htmlErrors = '';\n\n if (resp.validated) {\n boxResponse.innerHTML = '';\n } else {\n for (var i = resp.errors.length - 1; i >= 0; i--) {\n htmlErrors += '' + resp.errors[i] + '';\n }\n boxResponse.innerHTML = htmlErrors;\n }\n },\n addItemResult: function (typeResult, result, boxResponse, form) {\n const _this = this;\n\n if (typeResult == 'produto-adicionado') {\n const btnComprar = form.querySelector('[data-action=\"add-cart\"]');\n\n if (btnComprar) btnComprar.classList.add('success');\n\n setTimeout(function () {\n if (btnComprar) btnComprar.classList.remove('success');\n if (btnComprar) btnComprar.innerHTML = btnComprar.dataset.textAvailable;\n }, 3500);\n\n CartDrawer.updateCartCount();\n\n if (window.innerWidth > 768) {\n if (_this.openCartDrawer) {\n CartDrawer.show();\n } else {\n setTimeout(() => {\n window.location.href = urlCart;\n }, 150);\n }\n } else {\n if (_this.openCartDrawerMobile) {\n CartDrawer.show();\n } else {\n setTimeout(() => {\n window.location.href = urlCart;\n }, 150);\n }\n }\n\n // Verifica se há popup de compra rápida ativo. Se tiver, fecha ele, retirar ou comentar se não for utilizado\n const popupPurchase = document.querySelector('[data-popup-purchase]');\n if (popupPurchase != null) {\n if (popupPurchase.classList.contains('-active')) {\n popupPurchase.querySelector('[data-close-popup-purchase]').click();\n }\n }\n } else if (typeResult == 'erro-adicionar') {\n if (typeof boxResponse != 'undefined' && boxResponse.length > 0) {\n window.scrollTo({\n top: boxResponse.offsetTop,\n behavior: 'smooth',\n });\n\n boxResponse.classList.add('error');\n boxResponse.classList.remove('success');\n boxResponse.querySelector('span').innerHTML =\n 'Ocorreu um erro, tente novamente.';\n }\n }\n },\n};\n\nexport default Store;\n","// \"productVariants\" é inicializado em layout.liquid, e todos os arquivos liquid que montam\n// product_block populam este objeto com as variantes dos produtos em tela\nimport Store from './store';\nimport { formatMoney } from '../components/utilities';\n\nconst ProductPurchase = {\n productVariants,\n products: document.querySelectorAll('[data-product-purchase]'),\n\n // Verifica as combinações possíveis entre os atributos, com base no atributo que foi clicado\n checkCombinations: function (currentProduct, selectedAttribute) {\n const productId = currentProduct.getAttribute('data-product-id');\n const selectedAttr = Number(selectedAttribute.getAttribute('data-attribute-index'));\n const variants = ProductPurchase.productVariants[`${productId}`];\n\n // Busca todos os atributos do produto\n const attributes = {\n attr1: [...currentProduct.querySelectorAll('[data-attribute-index=\"1\"]')],\n attr2: [...currentProduct.querySelectorAll('[data-attribute-index=\"2\"]')],\n attr3: [...currentProduct.querySelectorAll('[data-attribute-index=\"3\"]')],\n };\n\n // Busca os atuais atributos selecionados\n const selectedAttributes = {\n attr1: currentProduct.querySelector('[data-attribute=\"1\"] input:checked + label'),\n attr2: currentProduct.querySelector('[data-attribute=\"2\"] input:checked + label'),\n attr3: currentProduct.querySelector('[data-attribute=\"3\"] input:checked + label'),\n };\n\n // Altera o selected para o atributo que foi clicado\n selectedAttributes[`attr${selectedAttr}`] = selectedAttribute;\n\n // Atualiza as classes dos atributos disponíveis/indisponíveis\n // Ao clicar em uma opção de attr1, atualiza os attrs 2 e 3\n switch (selectedAttr) {\n case 1:\n ProductPurchase.markAttributes([...attributes.attr2], 2, variants, selectedAttributes, currentProduct);\n ProductPurchase.markAttributes([...attributes.attr3], 3, variants, selectedAttributes, currentProduct);\n break;\n\n case 2:\n ProductPurchase.markAttributes([...attributes.attr3], 3, variants, selectedAttributes, currentProduct);\n break;\n\n case 3:\n break;\n }\n },\n\n // Marca os atributos como disponiveis/indisponiveis com base nas combinações do checkCombinations\n markAttributes: function (attributes, index, variants, selectedAttributes, currentProduct) {\n if (attributes != null && attributes.length > 0) {\n // Remove os atributos já selecionados que não devem ser analizados,\n // com base no index do atributo que está sendo analizado. Usado para filtrar\n // as variantes e diminuir o número de possíveis combinações que definem como disponível/indisponível\n switch (index) {\n case 1:\n selectedAttributes.attr2 = null;\n selectedAttributes.attr3 = null;\n break;\n\n case 2:\n selectedAttributes.attr3 = null;\n break;\n\n case 3:\n break;\n }\n\n attributes.forEach((attr) => {\n const value = attr.getAttribute('data-attribute-value');\n const property = `property${index}`;\n let available = false;\n\n // Adiciona o atributo iterado nos atributos usados para buscar variantes válidas\n const attrsToCheck = {\n ...selectedAttributes,\n [`attr${index}`]: attr,\n };\n\n // Filtra as variantes para somente as que possuem a combinação de atributos válida\n const validVariants = variants.filter((variant) => {\n const properties = variant.properties;\n let validAttr1 = false;\n let validAttr2 = false;\n let validAttr3 = false;\n\n if (attrsToCheck.attr1 == null) validAttr1 = true;\n if (attrsToCheck.attr2 == null) validAttr2 = true;\n if (attrsToCheck.attr3 == null) validAttr3 = true;\n\n if (properties.property1 == null) validAttr1 = true;\n if (properties.property2 == null) validAttr2 = true;\n if (properties.property3 == null) validAttr3 = true;\n\n if (validAttr1 == false) {\n const valueToCheck = attrsToCheck.attr1.getAttribute('data-attribute-value');\n if (properties.property1.value == valueToCheck) validAttr1 = true;\n }\n\n if (validAttr2 == false) {\n const valueToCheck = attrsToCheck.attr2.getAttribute('data-attribute-value');\n if (properties.property2.value == valueToCheck) validAttr2 = true;\n }\n\n if (validAttr3 == false) {\n const valueToCheck = attrsToCheck.attr3.getAttribute('data-attribute-value');\n if (properties.property3.value == valueToCheck) validAttr3 = true;\n }\n\n if (validAttr1 && validAttr2 && validAttr3) return variant;\n });\n\n attr.classList.remove('-available');\n attr.classList.remove('-unavailable');\n attr.classList.remove('-disabled');\n\n if (validVariants.length > 0) {\n // Encontrou variantes, marca como disponível/indisponível com base nas variantes\n validVariants.forEach((variant) => {\n if (variant.properties[property]) {\n if (variant.properties[property].value == value) {\n variant.available == false ? (available = false) : (available = true);\n }\n } else {\n available = false;\n }\n });\n\n available ? attr.classList.add('-available') : attr.classList.add('-unavailable');\n } else if (validVariants.length === 0) {\n // Não encontrou nenhuma variante, então desabilita a opção.\n // Se esta opção estava selecionada, clica na primeira opção disponível entre os demais\n attr.classList.add('-disabled');\n const value = attr.getAttribute('data-attribute-value');\n const input = currentProduct.querySelector(`[data-attribute=\"${index}\"] input[value=\"${value}\"]`);\n if (input.checked) {\n input.checked = false;\n setTimeout(() => {\n const firstAvailable = currentProduct.querySelector(\n `label[data-attribute-index=\"${index}\"]:not(.-disabled)`\n );\n if (firstAvailable) firstAvailable.click();\n }, 50);\n }\n }\n });\n }\n },\n\n // Procura por SKU válido dentre os atributos escolhidos\n checkSelection: function (currentProduct) {\n const productId = currentProduct.getAttribute('data-product-id');\n const variants = ProductPurchase.productVariants[`${productId}`];\n\n const selectedAttrs = {\n attr1: currentProduct.querySelector('[data-attribute=\"1\"] input:checked'),\n attr2: currentProduct.querySelector('[data-attribute=\"2\"] input:checked'),\n attr3: currentProduct.querySelector('[data-attribute=\"3\"] input:checked'),\n };\n\n let available = false;\n\n for (let index = 0; index < variants.length; index++) {\n const variant = variants[index];\n let attr1 = false;\n let attr2 = false;\n let attr3 = false;\n let attr1Value = null;\n let attr2Value = null;\n let attr3Value = null;\n\n // Verifica se algum dos atributos é inexistente no cadastro\n if (variant.properties.property1 == null) attr1 = true;\n if (variant.properties.property2 == null) attr2 = true;\n if (variant.properties.property3 == null) attr3 = true;\n\n //Salva o valor de cada um dos atributos/propriedes da própria variante em questão\n if (variant.properties.property1) attr1Value = variant.properties.property1.value;\n if (variant.properties.property2) attr2Value = variant.properties.property2.value;\n if (variant.properties.property3) attr3Value = variant.properties.property3.value;\n\n // Verifica se a variante possui os atributos selecionados\n if (!attr1 && attr1Value != null && selectedAttrs.attr1 != null) {\n if (attr1Value == selectedAttrs.attr1.value) attr1 = true;\n }\n\n if (!attr2 && attr2Value != null && selectedAttrs.attr2 != null) {\n if (attr2Value == selectedAttrs.attr2.value) attr2 = true;\n }\n\n if (!attr3 && attr3Value != null && selectedAttrs.attr3 != null) {\n if (attr3Value == selectedAttrs.attr3.value) attr3 = true;\n }\n\n // Se achou variante compatível com os atributos selecionados, atualiza\n if (attr1 && attr2 && attr3) {\n available = true;\n const event = new CustomEvent('vnda:sku-change', { detail: { sku: variant.sku }})\n const productContainer = currentProduct.closest('[data-product-box]');\n\n currentProduct.querySelector('[name=\"sku\"]').value = variant.sku;\n currentProduct.dispatchEvent(event);\n if (productContainer) productContainer.dispatchEvent(event);\n\n // Reinicializa o input de quantidade para 1\n currentProduct.querySelector('[name=\"quantity\"]').value = 1;\n\n // Remove a mensagem de quantidade máxima quando altera a variante\n if (currentProduct.querySelector('.msg-response .msg-error').classList.contains('-visible')) {\n currentProduct.querySelector('.msg-response .msg-error').innerHTML = '';\n currentProduct.querySelector('.msg-response .msg-error').classList.remove('-visible');\n }\n\n // Configura a quantidade máxima do input conforme a variante selecionada\n currentProduct.querySelector('[name=\"quantity\"]').setAttribute('data-available-quantity', variant.quantity);\n // Configura produto disponível/indisponível\n if (variant.available) {\n ProductPurchase.setAvailable(currentProduct);\n } else {\n ProductPurchase.setUnavailable(currentProduct, true, variant.sku);\n }\n\n // Atualiza as últimas quantidades disponíveis\n ProductPurchase.setLastUnits(currentProduct, variant);\n\n // Atualiza o preço do componente\n ProductPurchase.updatePrice(currentProduct, variant);\n break;\n }\n }\n\n // Quando não encontra variante\n if (!available) ProductPurchase.setUnavailable(currentProduct, false);\n },\n\n // Define produto como disponível pra compra\n setAvailable: function (currentProduct) {\n const addButton = currentProduct.querySelector('[data-action=\"add-cart\"]');\n const currentProductWrapper = currentProduct.closest('[data-product-box]');\n let formNotify = null;\n\n if (currentProductWrapper) {\n formNotify = currentProductWrapper.querySelector('[data-form-notify]');\n }\n\n if (addButton) {\n // addButton.setAttribute('data-available', true);\n addButton.classList.add('-available');\n addButton.classList.remove('-unavailable');\n addButton.innerHTML = addButton.getAttribute('data-text-available');\n }\n\n if (formNotify) formNotify.classList.remove('-active');\n },\n\n // Define produto como indisponível pra compra\n setUnavailable: function (currentProduct, showNotify, sku) {\n const addButton = currentProduct.querySelector('[data-action=\"add-cart\"]');\n const currentProductWrapper = currentProduct.closest('[data-product-box]');\n const showFormNotify = showNotify || false;\n let formNotify = null;\n\n if (currentProductWrapper) {\n formNotify = currentProductWrapper.querySelector('[data-form-notify]');\n }\n\n if (addButton) {\n // addButton.setAttribute('data-available', false);\n addButton.classList.remove('-available');\n addButton.classList.add('-unavailable');\n addButton.innerHTML = addButton.getAttribute('data-text-unavailable');\n }\n\n if (formNotify) {\n if (showFormNotify && sku != undefined && sku != null) {\n formNotify.classList.add('-active');\n formNotify.querySelector('[name=\"sku\"]').value = sku;\n } else {\n formNotify.classList.remove('-active');\n }\n }\n },\n\n // Atualiza o componente de preço do produto\n updatePrice: function (currentProduct, variant) {\n const productMainContainer = currentProduct.closest('[data-product-box]');\n let productID = currentProduct.getAttribute('data-product-id');\n // console.log('updateprice', currentProduct, productID)\n if (productMainContainer == null) return;\n\n const priceEl = productMainContainer.querySelector('[data-init-price]');\n\n if (priceEl == null) return;\n\n const groupShop = productMainContainer.getAttribute('data-prod-group-shop');\n // console.log(variant)\n priceEl.setAttribute('data-sku', variant.sku);\n priceEl.setAttribute('data-price', variant.price);\n priceEl.dispatchEvent(new Event('change'));\n\n const discount = priceEl.dataset.discountPercent;\n window.price[productID] = variant.price\n // Coloca a porcentagem de desconto no produto\n if (discount != '0') {\n priceEl.style.setProperty('--discount', `'-${discount}%'`);\n }\n\n // atualiza preço final do compre junto se existir\n if (groupShop != null) {\n productMainContainer.setAttribute('data-price', variant.price);\n productMainContainer.setAttribute('data-sale-price', variant.sale_price);\n productMainContainer.setAttribute('data-available', variant.available);\n productMainContainer.dispatchEvent(new Event('vnda:group-shop-price-update'));\n }\n },\n\n // Marca o primeiro atributo como disponível/indisponível, e seleciona os atributos\n // da primeira variante disponível\n markFirstVariant: function (currentProduct) {\n const productId = currentProduct.getAttribute('data-product-id');\n const variants = [...ProductPurchase.productVariants[`${productId}`]];\n\n if (variants.length === 1) {\n // possui somente uma variante e não possui atributos,\n // define como disponível/indisponível com base na variante em si\n if (currentProduct.querySelectorAll('.prod-option').length === 0) {\n return variants[0].available\n ? ProductPurchase.setAvailable(currentProduct)\n : ProductPurchase.setUnavailable(currentProduct, true, variants[0].sku);\n }\n } else if (variants.length === 0) {\n // Produto não possui variantes, define como indisponível\n return ProductPurchase.setUnavailable(currentProduct);\n }\n\n if (variants.length > 0) {\n const allAttr1 = [...currentProduct.querySelectorAll('[data-attribute=\"1\"] [data-attribute-value]')];\n const allAttr2 = [...currentProduct.querySelectorAll('[data-attribute=\"2\"] [data-attribute-value]')];\n const allAttr3 = [...currentProduct.querySelectorAll('[data-attribute=\"3\"] [data-attribute-value]')];\n\n // Prepara para caso o atributo 1 não esteja em uso, scout por outros\n let attrToCheck = { index: false, options: [] };\n\n if (allAttr3.length > 0) attrToCheck = { index: 'property3', options: allAttr3 };\n if (allAttr2.length > 0) attrToCheck = { index: 'property2', options: allAttr2 };\n if (allAttr1.length > 0) attrToCheck = { index: 'property1', options: allAttr1 };\n\n // Baseado na ordem dos atributos, busca por variantes válidas\n if (attrToCheck.options.length > 0) {\n for (let index = 0; index < attrToCheck.options.length; index++) {\n const attribute = attrToCheck.options[index];\n const value = attribute.getAttribute('data-attribute-value');\n const availableVariants = ProductPurchase.productVariants[`${productId}`].filter((variant) => {\n if (variant.properties[attrToCheck.index].value == value && variant.available) return variant;\n });\n\n if (availableVariants.length > 0) {\n attribute.classList.add('-available');\n } else {\n // O produto não tem variantes disponíveis\n attribute.classList.add('-unavailable');\n }\n }\n\n // Marca os atributos da primeira variante disponível,\n //com base na ordem que os atributos se apresentam na tela\n let hasFirstAvailable = false;\n\n for (const attribute of attrToCheck.options) {\n if (attribute.classList.contains('-available')) {\n attribute.click();\n hasFirstAvailable = true;\n\n if (attrToCheck.index == 'property1') {\n for (const attr2 of allAttr2) {\n if (attr2.classList.contains('-available')) {\n attr2.click();\n break;\n }\n }\n\n for (const attr3 of allAttr3) {\n if (attr3.classList.contains('-available')) {\n attr3.click();\n break;\n }\n }\n }\n\n if (attrToCheck.index == 'property2') {\n for (const attr3 of allAttr3) {\n if (attr3.classList.contains('-available')) {\n attr3.click();\n break;\n }\n }\n }\n\n break;\n }\n }\n\n // Quando não há nenhuma first variant com estoque, marca a primeira\n //opção indisponível, para exibir como indisponível\n if (!hasFirstAvailable) {\n attrToCheck.options[0].click();\n if (attrToCheck.index == 'property1') {\n if (allAttr2.length > 0) allAttr2[0].click();\n if (allAttr3.length > 0) allAttr3[0].click();\n }\n\n if (attrToCheck.index == 'property2') {\n if (allAttr3.length > 0) allAttr3[0].click();\n }\n }\n }\n }\n },\n\n // Configura a mesagem de ultimas unidades disponíveis\n setLastUnits: function (currentProduct, variant) {\n var lastUnitsWrapper = currentProduct.querySelector('.last-units');\n var availableQuantity = variant.quantity;\n\n if (availableQuantity <= 5) {\n if (!availableQuantity) {\n lastUnitsWrapper.innerHTML = '';\n lastUnitsWrapper.classList.remove('-visible');\n } else if (availableQuantity > 1) {\n lastUnitsWrapper.innerHTML = `Últimas ${availableQuantity} unidades disponíveis`;\n lastUnitsWrapper.classList.add('-visible');\n } else {\n lastUnitsWrapper.innerHTML = 'Última unidade disponível';\n lastUnitsWrapper.classList.add('-visible');\n }\n } else {\n lastUnitsWrapper.innerHTML = '';\n lastUnitsWrapper.classList.remove('-visible');\n }\n },\n\n // Configura o seletor de quantidade e suas mensagens\n setQuantitySelector: function (currentProduct) {\n const error = currentProduct.querySelector('.msg-response .msg-error');\n const buttonPlus = currentProduct.querySelector('[data-qtd-plus]');\n const buttonMinus = currentProduct.querySelector('[data-qtd-minus]');\n const input = currentProduct.querySelector('[name=\"quantity\"]');\n const label = currentProduct.querySelector('.quantity .label');\n const labelText = label.dataset.label;\n\n if (buttonPlus != null && buttonMinus != null) {\n buttonPlus.addEventListener('click', () => {\n const current = Number(input.value) + 1;\n const availableQuantity = Number(input.dataset.availableQuantity);\n\n if (!availableQuantity) {\n error.innerHTML = 'Produto em falta no estoque';\n error.classList.add('-visible');\n } else if (current > availableQuantity) {\n // Se o produto atingiu a quantidade máxima em estoque mostra uma mensagem\n error.innerHTML = 'Quantidade máxima em estoque.';\n error.classList.add('-visible');\n } else {\n input.value = current;\n input.setAttribute('value', current);\n if (current > 1) label.innerHTML = labelText + 's'\n else label.innerHTML = labelText\n\n ProductPurchase.setUpdatePriceQuantity(currentProduct, current);\n }\n\n });\n\n buttonMinus.addEventListener('click', () => {\n const current = Number(input.value) - 1;\n\n if (current > 0) {\n input.value = current;\n input.setAttribute('value', current);\n\n if (current > 1) label.innerHTML = labelText + 's'\n else label.innerHTML = labelText\n \n ProductPurchase.setUpdatePriceQuantity(currentProduct, current);\n\n // Se está mostrando a mensagem de quantidade máxima, remove ela\n if (error.classList.contains('-visible')) {\n error.classList.remove('-visible');\n }\n }\n });\n }\n },\n\n setUpdatePriceQuantity: function (currentProduct, quantity){\n // console.log(currentProduct, $(currentProduct).closest('[data-product-box]'))\n const priceEl = $(currentProduct).closest('[data-product-box]').find('[data-price]').first();\n let productID = currentProduct.getAttribute('data-product-id');\n const priceValue = window.price[productID];\n const discountPercent = $(priceEl).data('discount-percent');\n\n $(priceEl).find('.cmp-price-price').html(formatMoney(priceValue*quantity));\n\n if (discountPercent){\n $(priceEl).find('.cmp-price-original-price .price').html(formatMoney(priceValue*quantity));\n $(priceEl).find('.cmp-price-sale-price .price').html(formatMoney((priceValue*(1-discountPercent/100))*quantity));\n }\n },\n\n // Envia o formulário de compra\n submitForm: function (currentProduct) {\n currentProduct.addEventListener('submit', (event) => {\n event.preventDefault();\n\n const groupShop = currentProduct.closest('[data-product-box]').getAttribute('data-prod-group-shop');\n\n if (groupShop == null) {\n // Adição normal de produto - Compre Junto é controlado em outro componente\n const form = currentProduct;\n const parent = form.closest('[data-product-box]');\n\n const respValidated = Store.validateFormProduct(form);\n const boxResponse = parent.querySelector('.msg-response');\n\n if (respValidated.validated) {\n Store.addItem(form, parent);\n } else {\n //console.info('não foi');\n Store.setRespValidateProduct(respValidated, form, boxResponse);\n }\n }\n });\n },\n\n // Lida com popup de compra rápida, retirar ou comentar caso não for utilizado\n popupPurchase: {\n popupEl: document.querySelector('[data-popup-purchase]'),\n currentOpenProduct: false,\n\n open: function (productBox) {\n // Salva o produto atual para referência futura\n ProductPurchase.popupPurchase.currentOpenProduct = productBox;\n\n // Clona elementos do produto e referencia o form de compra dele\n const clonedImages = productBox.querySelector('.images').cloneNode(true);\n const clonedName = productBox.querySelector('.name').cloneNode(true);\n const clonedPrice = productBox.querySelector('.price').cloneNode();\n const purchaseForm = productBox.querySelector('[data-product-purchase]');\n\n // Joga os elementos do produto dentro do popup\n const contentBox = this.popupEl.querySelector('.product');\n const leftBox = document.createElement('div');\n const rightBox = document.createElement('div');\n let priceWrapper = document.createElement('div');\n priceWrapper.classList.add('price-wrapper');\n priceWrapper.appendChild(clonedPrice);\n\n leftBox.appendChild(clonedImages);\n leftBox.appendChild(priceWrapper);\n rightBox.appendChild(clonedName);\n rightBox.appendChild(purchaseForm);\n\n contentBox.appendChild(leftBox);\n contentBox.appendChild(rightBox);\n\n // Atualiza o componente de preço dentro do popup e exibe\n clonedPrice.setAttribute('data-was-processed', false);\n window.Vnda.Component.Price.update();\n\n this.popupEl.classList.add('-active');\n },\n\n close: function () {\n // CHAMAR UMA ÚNICA VEZ\n // Instancia funcionamento ao clicar no botão de fechar o popup\n const popup = this.popupEl;\n const closeButtons = popup.querySelectorAll('[data-close-popup-purchase]');\n\n closeButtons.forEach((button) => {\n if (button.getAttribute('data-processed') == 'false') {\n button.addEventListener('click', () => {\n popup.classList.remove('-active');\n\n setTimeout(() => {\n // Retorna o formulário para o produto correspondente\n const purchaseForm = popup.querySelector('[data-product-purchase]');\n ProductPurchase.popupPurchase.currentOpenProduct.appendChild(purchaseForm);\n ProductPurchase.popupPurchase.currentOpenProduct = false;\n\n // Limpa os dados do produto do popup\n const popupProductEl = popup.querySelector('.product');\n while (popupProductEl.firstChild) {\n popupProductEl.removeChild(popupProductEl.firstChild);\n }\n }, 300);\n });\n button.setAttribute('data-processed', true);\n }\n });\n },\n },\n\n init: function (update) {\n const triggerUpdate = update || false;\n if (triggerUpdate) {\n this.products = document.querySelectorAll('[data-product-purchase]');\n this.productVariants = productVariants;\n }\n\n const { products, checkCombinations, checkSelection, markFirstVariant, submitForm, setQuantitySelector } = this;\n\n // Instancia funcionamento de fechar o popup de compra rápida, retirar ou comentar caso não for utilizado\n ProductPurchase.popupPurchase.close();\n\n if (products.length > 0)\n products.forEach((product) => {\n if (product.getAttribute('data-processed') == 'false') {\n const attrOptions = product.querySelectorAll('[data-attribute-value]');\n const attrInputs = product.querySelectorAll('input');\n\n // Remarca demais atributos ao clicar em uma opção\n attrOptions.forEach((attr) => {\n attr.addEventListener('click', () => {\n checkCombinations(product, attr);\n });\n });\n\n // Verifica variante para combinação de atributos selecionados\n attrInputs.forEach((input) => {\n input.addEventListener('change', () => {\n checkSelection(product);\n });\n });\n\n setQuantitySelector(product);\n markFirstVariant(product);\n submitForm(product);\n product.setAttribute('data-processed', true);\n\n // Abre o popup de compra rápida, retirar ou comentar caso não for utilizado\n const openPopupPurchaseButton = product.parentElement.querySelector('[data-open-popup-purchase]');\n if (openPopupPurchaseButton != null) {\n openPopupPurchaseButton.addEventListener('click', () => {\n ProductPurchase.popupPurchase.open(product.parentElement);\n });\n }\n }\n });\n },\n};\n\nexport default ProductPurchase;\n","import ProductPurchase from '../components/productPurchase';\n\nconst InfinityScroll = {\n params: window._pagination,\n priceProds: {\n selector: '[data-update-price]',\n attr: 'update-price',\n },\n productsWrapper: document.querySelectorAll('.section-list-products')[0],\n productWrapper: document.querySelectorAll('.list-products')[0],\n button: document.querySelector('[data-load-more]'),\n stopLoading: function () {\n const button = this.button;\n\n if (button != null) button.parentElement.removeChild(button);\n },\n setCurrentPage: function (_number) {\n const totalPages = this.params.totalPages;\n\n if (_number <= totalPages) {\n this.params.currentPage = _number;\n\n if (this.params.currentPage >= totalPages) this.stopLoading();\n\n if (_number < totalPages)\n return (this.params.nextUrl = this.params.pages[_number].url);\n }\n },\n\n setScript: function (script) {\n const newScript = document.createElement('script');\n newScript.innerText = script.innerText;\n return document.body.appendChild(newScript);\n },\n\n loadProducts: async function () {\n const nextUrl = this.params.nextUrl;\n const response = await fetch(nextUrl);\n const data = await response.text();\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(data, 'text/html');\n const script = doc.querySelector('[data-product-variants]');\n\n // Busca por scripts para compra rápida\n const scripts = doc.querySelectorAll('[data-variants-script]');\n if (scripts.length > 0)\n scripts.forEach((script) => {\n InfinityScroll.setScript(script);\n });\n\n return doc.querySelectorAll('.product-block');\n },\n updatePrice: function () {\n window.Vnda.Component.Price.update();\n },\n getNextPage: async function () {\n const currentPage = this.params.currentPage;\n const wrapper = this.productsWrapper;\n const productWrapper = this.productWrapper;\n\n if (!wrapper.classList.contains('-searching')) {\n this.productsWrapper.classList.add('-searching');\n this.button.classList.add('-searching');\n\n const newProducts = await this.loadProducts();\n\n newProducts.forEach((product) => {\n productWrapper.appendChild(product);\n });\n\n this.setCurrentPage(currentPage + 1);\n\n ProductPurchase.init(true);\n lazyLoadInstance.update();\n this.updatePrice();\n\n wrapper.classList.remove('-searching');\n this.button.classList.remove('-searching');\n }\n },\n\n init: function () {\n const button = this.button;\n\n if (typeof this.params != undefined) {\n if (button != null) {\n button.addEventListener(\n 'click',\n () => {\n this.getNextPage();\n },\n { passive: true }\n );\n }\n }\n },\n};\n\nexport default InfinityScroll;\n","import InfinityScroll from '../components/infinityScroll';\nimport { updatePriceBlock } from '../components/utilities.js';\n\nlet isMobile = false;\n\nif (window.screen.width >= 1023) {\n isMobile = false;\n} else {\n isMobile = true;\n}\n\nconst Tag = {\n spotGrid: function () {\n if (isMobile == false) {\n const setGridAttributesNode = () => {\n let filterGridNode = `