/////////////////////////////////////////////// // GraphQL // ogolne const priceQuery = `price { rebateCodeActive price { gross { value formatted } } omnibusPrice { gross { value formatted } } omnibusPriceDetails { unit { gross { value formatted } } youSavePercent omnibusPriceIsHigherThanSellingPrice newPriceEffectiveUntil { formatted } } max { gross { value formatted } } unit { gross { value formatted } } unitConvertedPrice { gross { value formatted } } youSavePercent beforeRebate { gross { value formatted } } beforeRebateDetails { youSavePercent unit { gross { value formatted } } } advancePrice { gross { value formatted } } suggested { gross { value formatted } } rebateNumber { number gross { value formatted } } }`; const productQuery = `id type name zones icon iconSecond iconSmall iconSmallSecond link zones producer{ name } category{ name } sizes{ id amount name ${priceQuery} } group{ id name link versions{ id name icon iconSecond iconSmall iconSmallSecond } } awardedParameters { name id description values { name id } } enclosuresImages { position url } points unit{ id, name, singular, plural, fraction, sellBy, precision, unitConvertedFormat } ${priceQuery}`; // 1. products const IDM_PRODUCTS_GQL = (args) => JSON.stringify({ query: `{ products(${args}){ took products{ ${productQuery} } } }` }); // 2. hotspots const IDM_HOTSPOTS_GQL = (args) => JSON.stringify({ query: `{ hotspots(${args}){ took products{ ${productQuery} } } }` }); // 3. single product const IDM_PRODUCT_GQL = (args) => JSON.stringify({ query: `{ product(${args}){ product{ ${productQuery} } } }` }); // ADD TO BASKET const IDM_HOTSPOT_ADD_TO_BASKET = (t, e, a) => JSON.stringify({ query: `mutation {\n addProductsToBasket(ProductInput: {id: ${t}, size: "${e}", quantity: ${a}}) {\n status\n results {\n status\n error {\n code\n message\n }\n productCode\n productId\n sizeId\n quantity\n quantityAvailable\n }\n clientDetailsInBasket {\n id\n login\n firstname\n lastname\n participationPartnerProgram\n usesVat\n email\n isWholesaler\n isWholesalerOrder\n clientIdUpc\n }\n }\n }` }); /////////////////////////////////////////////////////////// // TEXT const idmHotspotTextObject = { ["Kod rabatowy"]: "Kod rabatowy", ["Okazja"]: "Okazja", ["Promocja"]: "Promocja", ["Bestseller"]: "Bestseller", ["Nowość"]: "Nowość", ["Ilość"]: "Ilość", ["Zwiększ ilość"]: "Zwiększ ilość", ["Zmniejsz ilość"]: "Zmniejsz ilość", ["Najniższa cena produktu w okresie 30 dni przed wprowadzeniem obniżki"]: "Najniższa cena produktu w okresie 30 dni przed wprowadzeniem obniżki", ["Cena regularna"]: "Cena regularna", ["Cena bez kodu"]: "Cena bez kodu", ["Cena nadchodząca od"]: "Cena nadchodząca od", ["Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę"]: "Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę", ["Nie znaleziono produktów"]: "Nie znaleziono produktów", ["Błąd przy pobieraniu danych"]: "Błąd przy pobieraniu danych", ["Kliknij, by przejść do formularza kontaktu"]: "Kliknij, by przejść do formularza kontaktu", ["Cena na telefon"]: "Cena na telefon", ["Dodany"]: "Dodany", ["Wystąpił błąd"]: "Wystąpił błąd", ["Do koszyka"]: "Do koszyka", ["Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]: "Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:", ["Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]: "Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:", ["Wystąpił błąd z inicjalizacją. Proszę odśwież stronę"]: "Wystąpił błąd z inicjalizacją. Proszę odśwież stronę", ["Nie znaleziono kontenera"]: "Nie znaleziono kontenera", ["Nie znaleziono metody graphql"]: "Nie znaleziono metody graphql", } //////////////////////////////////////////////////////////////////////////\\\\\\\\\\\\ // IDOSELL omnibus details // omnibusDetailsTxt - nadpisać na własny obiekt app_shop.fn.idmGetOmnibusDetails = (options) => { const { productData, sizeId, priceType = app_shop.vars.priceType, } = options || {}; if (!productData) return false; const sizeData = productData.sizes.find((size) => size.id === sizeId) || productData; if (!sizeData?.price) return false; const classes = { add: [], remove: ['--omnibus', '--omnibus-short', '--omnibus-code', '--omnibus-code-short', '--omnibus-new-price', '--omnibus-higher'], }; const activeLabel = {}; const omnibusPrice = sizeData.price?.omnibusPriceDetails?.unit?.[priceType]?.formatted || sizeData.price.omnibusPrice[priceType]?.formatted; if (!omnibusPrice) { return { classes, }; } // Omnibus classes.add.push('--omnibus'); classes.remove = classes.remove.filter((item) => item !== '--omnibus'); const sellBy = productData?.unit?.sellBy; const unitMaxPrice = sizeData?.price?.unit?.[priceType]?.formatted && sizeData.price.max?.[priceType]?.value ? format_price(parseFloat(sizeData.price.max?.[priceType]?.value) * parseFloat(sellBy), { mask: app_shop.vars.currency_format, currency: app_shop.vars?.currency?.symbol, currency_space: app_shop.vars.currency_space, currency_before_price: app_shop.vars.currency_before_value, }) : false; const maxPrice = unitMaxPrice || sizeData.price.max?.[priceType]?.formatted; // Skrócona wersja omnibusa if (!maxPrice || maxPrice === omnibusPrice) { classes.add.push('--omnibus-short'); classes.remove = classes.remove.filter((item) => item !== '--omnibus-short'); } // Aktywny kod rabatowy if (app_shop.vars.omnibus?.rebateCodeActivate && sizeData.price?.rebateCodeActive) { classes.add.push('--omnibus-code'); activeLabel.rebateCodeActive = `${idmHotspotTextObject["Kod rabatowy"]}`; classes.remove = classes.remove.filter((item) => item !== '--omnibus-code'); } // Skrócona wersja omnibusa, gdy aktywny kod rabatowy const beforeRebatePrice = sizeData.price.beforeRebateDetails?.unit?.[priceType]?.formatted || sizeData.price.beforeRebate[priceType]?.formatted; if (app_shop.vars.omnibus?.rebateCodeActivate && beforeRebatePrice === omnibusPrice && sizeData.price?.rebateCodeActive) { classes.add.push('--omnibus-code-short'); classes.remove = classes.remove.filter((item) => item !== '--omnibus-code-short'); } // Nadchodząca cena const newDate = sizeData.price.omnibusPriceDetails?.newPriceEffectiveUntil?.formatted; if (newDate && maxPrice) { classes.add.push('--omnibus-new-price'); classes.remove = classes.remove.filter((item) => item !== '--omnibus-new-price'); } // Cena omnibusa wyższa niż cena sprzedaży const higher = sizeData.price.omnibusPriceDetails?.omnibusPriceIsHigherThanSellingPrice; if (higher) { classes.add.push('--omnibus-higher'); classes.remove = classes.remove.filter((item) => item !== '--omnibus-higher'); } // label okazja if ((!higher || newDate) && !activeLabel?.rebateCodeActive) { activeLabel.bargain = `${idmHotspotTextObject["Okazja"]}`; } // label promocja if (Object.keys(activeLabel)?.length === 0) { activeLabel.bargain = `${idmHotspotTextObject["Promocja"]}`; } // labele zones if(productData.zones.find(zone => zone ==="bestseller")) activeLabel.bestseller = `${idmHotspotTextObject["Bestseller"]}`; if(productData.zones.find(zone => zone ==="news")) activeLabel.news = `${idmHotspotTextObject["Nowość"]}`; let omnibusPercentSign = ''; if (higher) { omnibusPercentSign = '-'; } else if (sizeData.price.omnibusPriceDetails?.youSavePercent !== 0) { omnibusPercentSign = '+'; } const omnibusPercent = `${omnibusPercentSign}${sizeData.price.omnibusPriceDetails?.youSavePercent}%`; const omnibus = { price: omnibusPrice, visible: true, percent: omnibusPercent, html: `${idmHotspotTextObject['Najniższa cena produktu w okresie 30 dni przed wprowadzeniem obniżki']}: ${omnibusPrice}${omnibusPercent}`, }; const max = (maxPrice) ? { max: { price: maxPrice, visible: true, percent: `-${sizeData.price.youSavePercent}%`, html: `${idmHotspotTextObject['Cena regularna']}: ${maxPrice}-${sizeData.price.youSavePercent}%`, }, } : {}; const beforeRebate = (beforeRebatePrice) ? { beforeRebate: { price: beforeRebatePrice, visible: !!classes.add.includes('--omnibus-code'), percent: `-${sizeData.price.beforeRebateDetails?.youSavePercent}%`, html: `${idmHotspotTextObject['Cena bez kodu']}: ${beforeRebatePrice} -${sizeData.price.beforeRebateDetails?.youSavePercent}%`, }, } : {}; const newPriceEffectiveUntil = (newDate) ? { newPriceEffectiveUntil: { date: newDate, price: maxPrice, visible: !!classes.add.includes('--omnibus-new-price'), html: `${idmHotspotTextObject['Cena nadchodząca od']} ${newDate}: ${maxPrice}`, }, } : {}; return { classes, omnibus, ...max, ...beforeRebate, ...newPriceEffectiveUntil, activeLabel, }; }; ////////////////////////////////////////////////////////////////////////// // EVENTY // dodawanie do koszyka async function idmHandleAddToBasket(e){ const formEl = e.target.closest("form.add_to_basket"); if(!formEl) return; try{ // pobieranie danych i elementów formEl.classList.add("--loading") const buttonEl = formEl.querySelector(".add_to_basket__button"); e.preventDefault(); const id = formEl.querySelector("input[name='product']")?.value; const size = formEl.querySelector("input[type='hidden'][name='size']")?.value; const number = formEl.querySelector("input[name='number']")?.value; // dodanie do koszyka const res = await fetch(`/graphql/v1/`, { method: "POST", headers: { "Content-Type": "application/json", }, body: IDM_HOTSPOT_ADD_TO_BASKET(id, size, number) }); const data = await res.json(); // Błąd if(data?.data?.addProductsToBasket?.status !== "success") throw new Error(data); else{ // Obsługiwanie sukcesu app_shop.graphql.trackingEvents(res); buttonEl.classList.add("--success"); // Dodawanie do koszyka na stronie basketedit.php będzie wymagał innego indywidualnego kodu!!!!! buttonEl.innerHTML = `${buttonEl.dataset.success}`; setTimeout(()=>{ buttonEl.innerHTML = `${buttonEl.dataset.text}`; app_shop.fn?.menu_basket_cache?.(); buttonEl.classList.remove("--success"); }, 3000); } }catch(err){ console.error(err); Alertek.Error(idmHotspotTextObject["Coś poszło nie tak podczas dodawania do koszyka. Spróbuj ponownie lub odśwież stronę"]); buttonEl.innerHTML = `${buttonEl.dataset.error}`; buttonEl.classList.add("--error") setTimeout(()=>{ buttonEl.classList.remove("--error") buttonEl.innerHTML = `${buttonEl.dataset.text}`; }, 3000); }finally{ formEl.classList.remove("--loading") } } ///qty const idmRangeMaxAlert = (max)=> Alertek.Error(`${idmHotspotTextObject["Maksymalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]} ${max}`) const idmRangeMinAlert = (min)=> Alertek.Error(`${idmHotspotTextObject["Minimalna liczba sztuk tego towaru które możesz dodać do koszyka to:"]} ${min}`) function idmQuantityButtonClick(e){ if(e.target.classList.contains("idm-products-banner__qty-input")) return e.target.select(); const wrapper = e.target.closest(".idm-products-banner__qty"); const input = wrapper.querySelector(".idm-products-banner__qty-input"); const step = parseFloat(wrapper.dataset.sellBy || "1"); const precision = parseInt(wrapper.dataset.precision || "0"); const max = parseFloat(wrapper.dataset.max || "999999"); let current = parseFloat(input.value) || 0; if (e.target.classList.contains("idm-products-banner__qty-increase")) { current += step; if (current > max){ current = max; idmRangeMaxAlert(max) } } else if (e.target.classList.contains("idm-products-banner__qty-decrease")) { current -= step; if (current < step){ current = step; idmRangeMinAlert(step) } } input.value = current.toFixed(precision); } function idmQuantityInputChange(e){ if(e.target.value > +e.target.max){ idmRangeMaxAlert(e.target.max) e.target.value = +e.target.max } if(e.target.value < +e.target.min){ idmRangeMinAlert(e.target.min) e.target.value = +e.target.min; } } ////////////////////////////////////////////// // DANE // dwie funkcje zamiast jednej async function idmGetHotspotData(query, graphFn){ try{ const res = await fetch(`/graphql/v1/`, { method: "POST", headers: { "Content-Type": "application/json", }, body: graphFn ? graphFn(query) : IDM_PRODUCTS_GQL(query) }); const data = await res.json(); const products = data[graphFn === IDM_HOTSPOTS_GQL ? "hotspots" : "data"]?.products?.products; if(!products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]); console.log(data); return products; }catch(err){ console.error(idmHotspotTextObject["Błąd przy pobieraniu danych"], err); return null; } } function idmGetQueryData({ productsID, productsMenu, hotspotsType }){ let graphFn, query; if(productsID){ graphFn = IDM_PRODUCTS_GQL; query = `searchInput: {productsId: [${productsID}]}`; }else if(productsMenu){ graphFn = IDM_PRODUCTS_GQL; query = `searchInput: {navigation: ${productsMenu}}`; }else if(hotspotsType){ graphFn = IDM_HOTSPOTS_GQL; query = `searchInput: {hotspot: ${hotspotsType}, limit: 16}`; } return {graphFn, query} } ////////////////////////////////////////////// // LAZY LOADING function idmObserveOnce(element, callback, options = { root: null, rootMargin: "0px", threshold: 0.1 }) { if (!element) return; const observer = new IntersectionObserver((entries, obs) => { entries.forEach(entry => { if (entry.isIntersecting) { callback(entry); // run your callback obs.disconnect(); // stop observing after first trigger } }); }, options); observer.observe(element); } ////////////////////////////////////////////////////////////////////////// // Markup // Funkcja przygotująca markup dla wszystkich produktów function idmPrepareProductsMarkup(products, addToBasket){ let markup = ""; products.forEach((prod)=>{ markup += idmPrepareSingleProductMarkup(prod, addToBasket); }) return markup; } // funkcja przygotowująca markup dla wybranego produktu function idmPrepareSingleProductMarkup(prod, addToBasket){ const prodExchangedData = app_shop.fn?.idmGetOmnibusDetails({productData: prod}); // pobranie labelek let labelHTMLMarkup = ""; if(typeof prodExchangedData.activeLabel === "object") Object.entries(prodExchangedData.activeLabel).forEach(([key,value])=>{ labelHTMLMarkup += value; }) // markup pojedynczego produktu let singleMarkup = ""; singleMarkup += `
${idmPrepareHotspotImgMarkup(prod)} ${labelHTMLMarkup}
${prod.name}
${idmPrepareHotspotPriceMarkup(prod, prodExchangedData)}
${idmPrepareHotspotAddToBasketMarkup(prod, addToBasket)}
`; return singleMarkup; } // markup zdjęcia function idmPrepareHotspotImgMarkup(prod){ let markup = ""; if(prod.iconSmallSecond !== undefined && prod.iconSecond !== undefined) markup +=` ${prod.name} `; else if(prod?.iconSmall !== undefined) markup += ` ${prod.name} `; else markup += `${prod.name}` return markup; } // markup cen function idmPrepareHotspotPriceMarkup(prod, prodExchangedData){ const price = prod.price.price[idmPriceType]; const unit = prod.unit; const pointsPrice = prod?.points; const convertedPrice = prod.price?.unitConvertedPrice?.[idmPriceType]?.formatted; return ` ${price.formatted} / ${unit?.sellBy} ${unit?.sellBy > 1 ? unit?.plural : unit?.singular} ${convertedPrice ? `${convertedPrice}` : ""} ${pointsPrice ? `${pointsPrice} pkt.` : ""} ${price.value === 0 ? `${idmHotspotTextObject["Cena na telefon"]}` : ""} ${prodExchangedData?.beforeRebate?.visible ? `${prodExchangedData?.beforeRebate?.html}` : ""} ${prodExchangedData?.newPriceEffectiveUntil?.visible ? `${prodExchangedData?.newPriceEffectiveUntil?.html}` : ""} ${prodExchangedData?.omnibus?.visible ? `${prodExchangedData?.omnibus?.html}` : ""} ${prodExchangedData?.max?.visible ? `${prodExchangedData?.max?.html}` : ""} `; } // markup dodawania do koszyka function idmPrepareHotspotAddToBasketMarkup(prod, addToBasket){ let markup = ""; if(!addToBasket && typeof addToBasket !== "undefined" || (typeof addToBasket === "undefined" && typeof idmGeneralHotspotObjData === "object" && !idmGeneralHotspotObjData?.options?.addToBasket) || !addToBasket && typeof idmGeneralHotspotObjData === "undefined") return markup; // link do produktu jak nie jest to zwykły produkt if(prod.type !== "product") markup = `Zobacz produkt`; else if(addToBasket === "range" || typeof addToBasket === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.addToBasket === "range") // +- markup = `
`; else // Zwykłe dodanie do koszyka markup = `
`; return markup; } //////////////////////////////////////////////////// // INIT // brutto/netto const idmPriceType = app_shop?.vars?.priceType || "gross"; // Zmienna trzymająca dane o ustawieniach customowych ramek rekomendacji na całym sklepie /** * Obiekt konfiguracyjny ogólnych ustawień hotspotów rekomendacji. * * @typedef {object} idmGeneralHotspotObjData * @property {object} options - Główne ustawienia hotspotów * @property {boolean} options.lazy - Czy wczytywać zawartość w trybie lazy (required). * @property {boolean|string} options.addToBasket - Zachowanie przy dodawaniu do koszyka: * - true = przycisk dodaj do koszyka * - false = brak przycisku * - "range" = dodaj z wyborem zakresu (required). * @property {boolean|object} options.swiper - Ustawienia slidera: * - true/false = włącz/wyłącz * - object = konfiguracja instancji Swiper (required jeśli obiekt). */ const idmGeneralHotspotObjData = { options: { lazy: true, addToBasket: true, // true, false, "range" swiper: { // true, false, obiekt z opcjami swipera loop: false, autoHeight: false, spaceBetween: 16, slidesPerView: 1.4, centeredSlides: true, centeredSlidesBounds: true, breakpoints: { 550: { slidesPerView: 3, centeredSlides: true, centeredSlidesBounds: true, }, 979: { slidesPerView: 4, centeredSlides: false, }, } } } } // Funkcja inicjalizująca wybranego hotspota(addtobasket range - swiper) async function idmHotspotInit(id, options={}){ try{ const hotspotEl = document.getElementById(id); if(!hotspotEl) throw new Error("Nie znaleziono elementu"); // add to basket + - if(options?.addToBasket === "range" || typeof options?.addToBasket === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.addToBasket === "range"){ // obsługa i sprawdzanie clicków // hotspotEl.addEventListener("click", e=>{ // const wrapper = e.target.closest(".idm-products-banner__qty"); // if (!wrapper) return; // if(e.target.classList.contains("idm-products-banner__qty-input")) return e.target.select(); // const input = wrapper.querySelector(".idm-products-banner__qty-input"); // const step = parseFloat(wrapper.dataset.sellBy || "1"); // const precision = parseInt(wrapper.dataset.precision || "0"); // const max = parseFloat(wrapper.dataset.max || "999999"); // let current = parseFloat(input.value) || 0; // if (e.target.classList.contains("idm-products-banner__qty-increase")) { // current += step; // if (current > max){ // current = max; // rangeMaxAlert(max) // } // } else if (e.target.classList.contains("idm-products-banner__qty-decrease")) { // current -= step; // if (current < step){ // current = step; // rangeMinAlert(step) // } // } // input.value = current.toFixed(precision); // }); // sprawdzanie na input // hotspotEl.querySelectorAll(".idm-products-banner__qty-input").forEach(inp=>{ // inp.addEventListener("input", e=>{ // if(e.target.value > +e.target.max){ // rangeMaxAlert(e.target.max) // e.target.value = +e.target.max // } // if(e.target.value < +e.target.min){ // rangeMinAlert(e.target.min) // e.target.value = +e.target.min; // } // }); // }) } // swiper || slick if(options?.swiper || typeof options?.swiper === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.swiper){ // Opcje swipera let swiperOptions = typeof options.swiper === "object" ? options.swiper : ""; if(typeof options.swiper === "object") swiperOptions = options.swiper; else if(typeof idmGeneralHotspotObjData === "object" && typeof idmGeneralHotspotObjData?.options?.swiper === "object"){ swiperOptions = idmGeneralHotspotObjData?.options?.swiper; swiperOptions.navigation = { nextEl: `#${id} .idm-button-next`, prevEl: `#${id} .idm-button-prev`, } }else{ swiperOptions = { loop: false, autoHeight: false, spaceBetween: 16, slidesPerView: 1.4, centeredSlides: true, centeredSlidesBounds: true, breakpoints: { 550: { slidesPerView: 3, centeredSlides: true, centeredSlidesBounds: true, }, 979: { slidesPerView: 4, centeredSlides: false, }, }, navigation: { nextEl: `#${id} .idm-button-next`, prevEl: `#${id} .idm-button-prev`, }, } } // Wywołanie swipera const selectedSwiper = new HotspotSlider({ selector: `#${id} .swiper`, hotspotName: `${id}`, options: swiperOptions, }); await selectedSwiper.init(); } }catch(err){ console.error(idmHotspotTextObject["Wystąpił błąd z inicjalizacją. Proszę odśwież stronę"], err); } } console.log("init") //////////////////////////////////////////////////// // Funkcja init ELEMENT HTML async function idmInsertHotspotElement(selectedContainerEl){ selectedContainerEl.classList.add("--init"); const {graphFn, query} = idmGetQueryData({ productsID: selectedContainerEl?.dataset?.productsId, productsMenu: selectedContainerEl?.dataset?.productsMenu, hotspotsType: selectedContainerEl.dataset.hotspotsType }); if(!graphFn || !query){ console.log(idmHotspotTextObject["Nie znaleziono metody graphql"], selectedContainerEl) return selectedContainerEl.remove(); } // Funkcja od uzupełniania danych const idmFill = async ()=>{ try{ // pobranie danych o produktach const products = await idmGetHotspotData(query, graphFn); if(!products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]); // wstawienie produktów zależnie czy w section jest .hotspot czy nie const hotspotInsideEl = selectedContainerEl.querySelector(".hotspot"); if(hotspotInsideEl) hotspotInsideEl.innerHTML += `
${idmPrepareProductsMarkup(products, true)}
`; else selectedContainerEl.innerHTML = `
${idmPrepareProductsMarkup(products, true)}
`; selectedContainerEl.classList.remove("idm-loading") // init swipera idmHotspotInit(selectedContainerEl.id) }catch(err){ console.error(idmHotspotTextObject["Wystąpił błąd"], err); selectedContainerEl.remove(); } } if(selectedContainerEl.dataset?.lazy || !selectedContainerEl.dataset?.lazy && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.lazy) idmObserveOnce(selectedContainerEl, idmFill); else idmFill(); } // Zebranie wszystkich ramek HTML i wstawienie ich. async function idmInsertAllHTMLHotspots(){ try{ const reqArr = [] document.querySelectorAll(".idm__hotspot:not(.--init):not(.--lazy-hotspot)").forEach(hotspot=>{ reqArr.push(idmInsertHotspotElement(hotspot)); }); await Promise.all(reqArr); }catch(err){ console.error(err) } } idmInsertAllHTMLHotspots(); ///////////////////////////////////////////////////////////////////// // wdrożenie dla elementu HTML /** * Struktura sekcji hotspotu w HTML. * * @typedef {HTMLElement} HotspotSection * @property {string} id - Identyfikator elementu (np. "idmBlogHotspot1"). * @property {string} class - Klasy CSS używane do stylowania. * * @attribute {string} data-products-id - Lista ID produktów (rozdzielona przecinkami). * @attribute {number} data-products-menu - Identyfikator menu produktów. * @attribute {string} data-hotspots-type - Typ hotspotu (np. "promotion"). * @attribute {boolean} data-lazy - Czy sekcja ma być ładowana w trybie lazy. * * @example

aaa

*/ //////////////////////////////////////////////////// // Funkcja init OBIEKT JS async function idmInsertHotspotObject(idmHotspotObj){ // Wstaw kontener const selectedEl = document.querySelector(idmHotspotObj?.placement.selector); if(!selectedEl) throw new Error(idmHotspotTextObject["Nie znaleziono kontenera"]); selectedEl.insertAdjacentHTML(idmHotspotObj.placement.insert || "afterend", `
${idmHotspotObj?.title ? `

${idmHotspotObj.title}

` : ""}
`); // Utworzenie markupa HTML const selectedContainerEl = document.getElementById(idmHotspotObj.id); if(!selectedContainerEl) throw new Error(idmHotspotTextObject["Nie znaleziono kontenera"]); const idmFill = async ()=>{ try{ let {graphFn, query} = idmGetQueryData({ productsID: idmHotspotObj?.source?.productsId, productsMenu: idmHotspotObj?.source?.productsMenu, hotspotsType: idmHotspotObj.source.hotspotsType }); if(idmHotspotObj?.query?.graphFn && idmHotspotObj?.query?.string){ graphFn = idmHotspotObj.query.graphFn; query = idmHotspotObj.query.string; } // pobranie danych o produktach const products = await idmGetHotspotData(query, graphFn); if(!products) throw new Error(idmHotspotTextObject["Nie znaleziono produktów"]); // Wstawienie markupa na strone const hotspotMarkup = `${idmPrepareProductsMarkup(products, idmHotspotObj?.options?.addToBasket)}`; selectedContainerEl.querySelector(".products.hotspot__products")?.insertAdjacentHTML("beforeend", hotspotMarkup); selectedContainerEl.classList.remove("idm-loading"); // init swiper + add to basket idmHotspotInit(idmHotspotObj.id, idmHotspotObj?.options) }catch(err){ console.error(idmHotspotTextObject["Wystąpił błąd"], err); selectedContainerEl.remove(); } } if(idmHotspotObj?.options?.lazy || typeof idmHotspotObj?.options?.lazy === "undefined" && typeof idmGeneralHotspotObjData === "object" && idmGeneralHotspotObjData?.options?.lazy) idmObserveOnce(selectedContainerEl, idmFill); else idmFill(); } // obiekt js z przykładowymi danymi /** * Tablica konfiguracji hotspotów rekomendacji. * * @typedef {object} Hotspot * @property {string} id - Identyfikator ramki (required). * @property {string} title - Tytuł ramki. * @property {string} classes - Dodatkowe klasy CSS. * @property {object} placement - Określa, gdzie wstawić ramkę (required). * @property {string} placement.selector - Selektor miejsca osadzenia. * @property {string} placement.insert - Pozycja wstawienia względem selektora (np. "afterbegin", "beforeend"). * @property {object} source - Dane źródłowe dla hotspotu (required). * @property {string} [source.hotspotType] - Typ hotspotu (np. "promotion"). * @property {number[]} [source.productsId] - Tablica ID produktów. * @property {number} [source.productsMenu] - Identyfikator menu produktów. * @property {object} query - Dane zapytania, nadpisują source (DEV). * @property {string} query.string - Zapytanie w formacie GraphQL. * @property {Function} query.graphFn - Funkcja do pobierania danych. * @property {object} options - Ustawienia dla hotspotu (required). * @property {boolean} options.lazy - Czy wczytywać w trybie lazy. * @property {boolean|string} options.addToBasket - Obsługa koszyka: * - true = włącz * - false = wyłącz * - "range" = dodaj z zakresem * @property {boolean|object} options.swiper - Slider: * - true = aktywny * - false = nieaktywny * - object = konfiguracja Swiper * * @type {Hotspot[]} */ // const idmHotspotArr = [ // { // id: "idmMainHotspot1",//!id ramki // title: "Nowoczesna ramka rekomendacji",// // classes: "abcdefg", // placement: { // selector: "#content", // insert: "afterbegin" // }, // source: { // hotspotType: "protomtion", // productsId: [11,12], // productsMenu: 122, // }, // query: { // string: `searchInput: {productsId : [589, 180, 181590,160740, 155978, 153632, 123350, 82542, 37321, 17040, 25065, 25114, 85452]}`, // graphFn: IDM_PRODUCTS_GQL // }, // // addToBasket: true, // options: { // lazy: false, // addToBasket: "range", // swiper: true, // // swiper: albo true false - albo obiekt z opcjami swipera // } // }, // { // id: "idmMainHotspot2", // title: "Super ramka rekomendacji", // placement: { // selector: "#content", // insert: "beforeend" // }, // source: { // productsMenu: 488, // }, // query: { // string: `searchInput: {hotspot: promotion,limit: 16}`, // graphFn: IDM_HOTSPOTS_GQL // }, // // addToBasket: true, // options: { // lazy: true, // addToBasket: "range", // swiper: true, // // swiper: albo true false - albo obiekt z opcjami swipera // } // } // ]; // Wrzucenie na strone wszystkich ramek z obiektu js async function idmInsertAllObjectHotspots(hotspotArr){ try{ const reqArr = [] hotspotArr.forEach(hotspotObj=>{ reqArr.push(idmInsertHotspotObject(hotspotObj)); }); await Promise.all(reqArr); }catch(err){ console.error(err) } } // idmInsertAllObjectHotspots(idmHotspotArr); // style na razie tak doawane document.querySelector("body").insertAdjacentHTML("beforeend", ``);