{"version":3,"file":"index.es.min.js","sources":["../../../packages/helpers/src/props.helpers.js","../../../packages/helpers/src/viewport.helpers.ts","../../../packages/helpers/src/utils.ts","../../../packages/page-builder-sections/src/pdp-detailed-description/subcomponents/list/list.js","../../../packages/page-builder-sections/src/pdp-detailed-description/subcomponents/detailed-description/detailed-description.js","../../../packages/helpers/src/dataLayer.js","../../../services/pdp-data/src/prod/index.js","../../../packages/helpers/src/cremaDataHelper.js","../../../packages/helpers/src/PDPservices.js","../../../packages/helpers/src/notesIcons.js","../../../packages/helpers/src/cupSizeIcons.js","../../../packages/page-builder-sections/src/pdp-detailed-description/pdp-detailed-description.js","../../../packages/helpers/src/catalog.js","../../../packages/helpers/src/render.js"],"sourcesContent":["const getData = attributes => attributes.find(attribute => attribute.nodeName === 'data')\n\nconst createProps = attributes => {\n const data = getData([...attributes])\n const props = [...attributes]\n .filter(attribute => attribute.nodeName !== 'data')\n .reduce((all, attr) => {\n return { ...all, [attr.nodeName]: attr.nodeValue }\n }, {})\n\n if (isNil(data)) {\n return props\n }\n\n try {\n return { ...props, ...JSON.parse(data.nodeValue) }\n } catch (error) {\n console.log('ERROR: No data', error, data?.nodeValue)\n }\n}\n\nconst isNil = obj => obj === undefined || obj === null\n\nexport const parseBool = value => (!value || value === 'false' ? false : true)\n\nexport default createProps\n","import { BREAKPOINT_M, BREAKPOINT_TABLET } from '@kissui/components'\n\nconst viewport = () => {\n const lt = (ref: number) => {\n return window.innerWidth < ref\n }\n\n return {\n get is() {\n const { innerWidth: vw, devicePixelRatio } = window\n return {\n mobile: vw < BREAKPOINT_M,\n mobile_tablet: vw < BREAKPOINT_TABLET,\n tablet: vw >= BREAKPOINT_M && vw < BREAKPOINT_TABLET,\n desktop: vw >= BREAKPOINT_TABLET && devicePixelRatio <= 1,\n retina: vw >= BREAKPOINT_TABLET && devicePixelRatio > 1\n }\n },\n lt\n }\n}\n\nconst helper = viewport()\n\nexport default helper\n","export { waitForSelector } from './waitForSelector'\n\nexport const constants = {\n LEFT: 37,\n UP: 38,\n RIGHT: 39,\n DOWN: 40,\n ESC: 27,\n SPACE: 32,\n ENTER: 13,\n TAB: 9\n}\n\nexport function capitalize(s = '') {\n return s[0].toUpperCase() + s.slice(1)\n}\n\nexport const convertToCamelCase = (str: string): string => {\n const arr = str.match(/[a-z]+|\\d+/gi)\n if (!arr) { return str }\n return arr.map((m, i) => {\n let low = m.toLowerCase()\n if (i !== 0) {\n low = low.split('').map((s, k) => (k === 0 ? s.toUpperCase() : s)).join(\"\")\n }\n return low\n }).join(\"\")\n}\n\nexport function slug(s = '') {\n return s\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, '-') // Replace spaces with -\n .replace(/[^\\w-]+/g, '') // Remove all non-word chars\n .replace(/--+/g, '-') // Replace multiple - with single -\n}\n\nexport function pxToEm(target: number, stripedInnerFontSize = 1) {\n return target / 14 / stripedInnerFontSize + 'em'\n}\n\nexport function percent(target: number) {\n return target + '%'\n}\n\nexport function parseHTML(str: string) {\n const tmp = document.implementation.createHTMLDocument('')\n tmp.body.innerHTML = str\n return tmp.body.childNodes\n}\n\nexport function stripHTML(str: string) {\n const tmp = document.implementation.createHTMLDocument('')\n tmp.body.innerHTML = str\n return (tmp.body.textContent ?? \"\").replace(RegExp('[\\\\s|\\'|\"]', 'g'), '')\n}\n\nexport function makeId(length: number) {\n var result = ''\n var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n var charactersLength = characters.length\n for (var i = 0; i < length; i++) {\n result += characters.charAt(Math.floor(Math.random() * charactersLength))\n }\n return result\n}\n\nexport function removeEmptyValues(obj: { [key: string]: any }): { [key: string]: any } {\n const findText = [\n 'Default campaign ID (tracking missing in Page Builder export)',\n 'Default campaign name (tracking missing in Page Builder export)',\n 'promoname', \n 'promoid', \n 'promocreative', \n 'undefined'\n ];\n \n for (let key in obj) {\n const value = obj[key];\n \n if (value === null || value === undefined || value === '') {\n delete obj[key];\n continue;\n }\n \n if (typeof value === 'string') {\n for (const text of findText) {\n if (value.includes(text)) {\n delete obj[key];\n break;\n }\n }\n }\n }\n \n return obj;\n}\n\nexport function makeHash(str: string) {\n var hash = 0,\n i,\n chr\n if (!str) {\n return hash\n }\n for (i = 0; i < str.length; i++) {\n chr = str.charCodeAt(i)\n hash = (hash << 5) - hash + chr\n hash |= 0 // Convert to 32bit integer\n }\n return 'id-' + hash\n}\n\nexport function getHashLink(link: string) {\n let linkHash = link\n let linkNoHash = link\n if (link.indexOf('#') !== -1) {\n linkNoHash = link.replace('#', '')\n } else {\n linkHash = '#' + link\n }\n\n return { linkNoHash, linkHash }\n}\n\nexport function lazyLoad(node: Element, attribute: string, value: any, url: string) {\n const CLASSNAME_OUT_OF_SCREEN = 'lazy-load'\n const CLASSNAME_IN_SCREEN = 'lazy-loaded'\n const CLASSNAME_ON_ERROR = 'lazy-loaded-error'\n\n const isOldIOS = () => {\n var agent = window.navigator.userAgent,\n start = agent.indexOf('OS ')\n if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {\n return window.Number(agent.substr(start + 3, 3).replace('_', '.')) < 14\n }\n return false\n }\n\n const inViewPort = (attribute: string, value: any) => {\n node.setAttribute(attribute, value)\n\n const cb = () => node.classList.add(CLASSNAME_IN_SCREEN)\n\n if (url) {\n const img = new Image()\n img.src = url\n img.onload = cb\n img.onerror = () => {\n cb()\n node.classList.add(CLASSNAME_ON_ERROR)\n throw new Error(`Image ${url} cannot be loaded`)\n }\n\n return\n }\n\n cb()\n }\n\n if (/Trident\\/|MSIE/.test(window.navigator.userAgent) || isOldIOS()) {\n inViewPort(attribute, value)\n } else {\n if ('IntersectionObserver' in window) {\n node.classList.add(CLASSNAME_OUT_OF_SCREEN)\n let lazyBackgroundObserver = new IntersectionObserver(function (entries) {\n entries.forEach(function (entry) {\n if (entry.isIntersecting) {\n inViewPort(attribute, value)\n lazyBackgroundObserver.unobserve(entry.target)\n }\n })\n })\n lazyBackgroundObserver.observe(node)\n } else {\n inViewPort(attribute, value)\n }\n }\n}\n\nexport function lazyLoadCallback(node: Element, cb: () => void) {\n const isOldIOS = () => {\n var agent = window.navigator.userAgent,\n start = agent.indexOf('OS ')\n if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {\n return window.Number(agent.substr(start + 3, 3).replace('_', '.')) < 14\n }\n return false\n }\n\n if (/Trident\\/|MSIE/.test(window.navigator.userAgent) || isOldIOS()) {\n cb()\n } else {\n if ('IntersectionObserver' in window) {\n let lazyBackgroundObserver = new IntersectionObserver(\n function (entries) {\n entries.forEach(function (entry) {\n if (entry.isIntersecting) {\n cb()\n lazyBackgroundObserver.unobserve(entry.target)\n }\n })\n },\n { rootMargin: '150% 0px' }\n )\n lazyBackgroundObserver.observe(node)\n }\n }\n}\n\n// Debounce\nexport function debounce<T>(func: (v: T) => void, time = 100) {\n let timer: number\n return function (event: T) {\n if (timer) {\n window.clearTimeout(timer)\n }\n timer = window.setTimeout(func, time, event)\n }\n}\n\n// isIE - to check for internet explorer\nexport function isIE() {\n let ua = window.navigator.userAgent,\n isIE = /MSIE|Trident/.test(ua)\n\n return isIE\n}\n\n// Load external script\nexport const loadExternalScript = ({\n src,\n callback = null,\n async = false,\n defer = false,\n module = false,\n id = ''\n}: {\n src: string;\n callback: null | GlobalEventHandlers[\"onload\"]\n module: boolean,\n defer: boolean,\n async: boolean,\n id: string\n}) => {\n const script = document.createElement('script')\n script.type = module ? 'module' : 'text/javascript'\n script.src = src\n id ? (script.id = id) : false // add id attribute only if passed\n if (typeof callback === 'function') {\n script.onload = callback\n }\n script.async = async\n script.defer = defer\n document.body.appendChild(script)\n}\n\n// Load external css\nexport const loadExternalCss = ({ src }: { src: string }) => {\n const script = document.createElement('link')\n script.rel = 'stylesheet'\n script.href = src\n document.body.appendChild(script)\n}\n// Lazy load vendor script\nexport const lazyLoadVendorScript = (handler, el) => {\n const observer = new IntersectionObserver(handler)\n observer.observe(el)\n}\n\n/**\n * Replaces variable inside a given string\n * Each variable have to be enclosed between stChr and enChr\n * The values have to be contained in the vars object, they key must match\n * example :\n * txt : 'See {resultsLength} Results'\n * vars : {resultsLength:'30'}\n * stChr : '{'\n * enChr : '}'\n *\n * will return : 'See 30 Results'\n *\n * @param {string} txt\n * @param {object} vars\n * @param {string} stChr\n * @param {string} enChr\n */\nexport function interpolate(txt: string, vars: Record<string, null | undefined | string>, stChr: string, enChr: string) {\n let curIdx = 0\n\n while (txt) {\n const stIdx = txt.indexOf(stChr, curIdx)\n if (stIdx === -1) {\n break\n }\n const enIdx = txt.indexOf(enChr, stIdx + 1)\n if (enIdx === -1) {\n break\n }\n const hashId = txt.substring(stIdx + stChr.length, enIdx)\n if (vars[hashId] != null) {\n txt = txt.substr(0, stIdx) + vars[hashId] + txt.substr(enIdx + enChr.length)\n curIdx = stIdx\n } else {\n curIdx = enIdx\n }\n }\n return txt\n}\n\n/**\n * Find in container element, add height to equal size of element\n * @param container css path where my element is contain e.g. `.c-container`\n * @param el css path of elements to equalized\n */\nexport const equalHeight = (containerSelector: string, el: string, elementScope: HTMLElement) => {\n const container = elementScope.querySelector<HTMLElement>(containerSelector)\n if (!container) {\n return\n }\n\n const items = container.querySelectorAll<HTMLElement>(el)\n let max = -1\n\n for (let i = 0; i < [...items].length; i++) {\n const item = [...items][i]\n let h = item.offsetHeight\n max = h > max ? h : max\n }\n\n if (max <= 0) {\n return\n }\n\n for (let i = 0; i < [...items].length; i++) {\n const item = [...items][i]\n item.style.height = `${max}px`\n }\n}\n\nexport const stringifyCurlyQuote = (data: {}) => JSON.stringify(data).replace(\"'\", '’')\n\nexport const stringifyForAttribute = (data = {}) => {\n return escapeHtml(JSON.stringify(data))\n}\n\n/**\n * This function is included instead of sanitizeString because for\n * inserting HTML into innerHTML we need to make sure all HTML\n * entities are escaped.\n */\nexport const escapeHtml = (text: string) => {\n const map = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n } as { [s: string]: string }\n\n return text.replace(/[&<>\"']/g, (m) => map[m])\n}\n\n/**\n * Because setting attributes escapes more than the characters above and then preact also\n * escapes text we need a more complete way of unescaping all html entities (not just the ones\n * above)\n */\nconst domParser = new DOMParser()\nexport const unescapeHtml = (text: string) => {\n return domParser.parseFromString(text, \"text/html\").body.textContent\n}\n\nexport const sanitizeString = (data: {}) => {\n if (!data) {\n return ''\n }\n\n return data.toString().replace(/\"/g, '"').replace(/'/g, ''')\n}\n\nexport const stripTags = (s: string) => {\n return (s || '').replace(/(<([^>]+)>)/gi, '')\n}\n\nexport const setAttributes = (element: Element, attrs: Record<string, any>) => {\n for (let key in attrs) {\n element.setAttribute(key, attrs[key])\n }\n return element\n}\n\nexport const getMetaContent = (metaName: string) => {\n const metaTag = document.querySelector(`meta[name=${metaName}]`)\n if (!metaTag) {\n return ''\n }\n return metaTag.getAttribute('content')\n}\n\nexport const isObjectEmpty = (obj: {}) => {\n return Object.keys(obj).length === 0\n}\n","import createProps from '@kissui/helpers/src/props.helpers'\n\nclass List extends HTMLElement {\n constructor() {\n super()\n }\n\n connectedCallback() {\n this.props = createProps(this.attributes)\n\n this.classes = this.createClasses()\n this.render()\n }\n\n createClasses() {\n const baseClass = 'nb-list'\n return {\n base: baseClass,\n heading: `${baseClass}__heading t-sm-700-sl`,\n items: `${baseClass}__items`,\n item: {\n base: `${baseClass}__item`,\n single: `${baseClass}__item--single`,\n icon: `${baseClass}__item-icon`,\n label: `${baseClass}__item-label t-2xs-500-sl`\n }\n }\n }\n\n render() {\n const { heading = '' } = this.props\n\n this.innerHTML = `\n <div class=\"${this.classes.base}\">\n <div class=\"${this.classes.heading}\">${heading}</div>\n ${this.renderItems()}\n </div>\n `\n }\n\n renderItems() {\n const { items = [] } = this.props\n const isSingle = items.length === 1\n\n if (isSingle) {\n const first = items.find(Boolean)\n return this.renderItem(first, isSingle)\n }\n\n const renderedItems = items.reduce(\n (output, item) => `${output}${this.renderItem(item)}`,\n ''\n )\n\n return `<div class=\"${this.classes.items}\">${renderedItems}</div>`\n }\n\n renderItem({ icon, label, size }, single = false) {\n const modifier = single ? this.classes.item.single : ''\n\n return `\n <div class=\"${this.classes.item.base} ${modifier}\">\n <div class=\"${this.classes.item.icon}\">\n <nb-icon icon=\"${icon}\"></nb-icon>\n </div>\n <div class=\"${this.classes.item.label}\">\n ${label}\n ${size ? `<br>${size}` : ''}\n </div>\n </div>\n `\n }\n}\n\ncustomElements.get('nb-list') || customElements.define('nb-list', List)\n\nexport default List\n","import createProps from '@kissui/helpers/src/props.helpers.js'\nimport viewportHelper from '@kissui/helpers/src/viewport.helpers'\nimport { stringifyForAttribute } from '@kissui/helpers/src/utils'\nimport '../list'\nclass DetailedDescription extends HTMLElement {\n connectedCallback() {\n this.props = createProps(this.attributes)\n this.render()\n }\n\n render() {\n const { campaign, layout, copywriting } = this.props\n const { levels = [] } = copywriting\n\n const { padding_top, padding_bottom, background_color = 'white_1000' } = layout\n\n const levelsAvailable = levels.length && levels.every(({ value }) => value !== 0)\n\n this.innerHTML = `\n <nb-container\n background_color=\"${background_color}\"\n campaign_id=\"${campaign.id}\"\n campaign_name=\"${campaign.name}\"\n campaign_creative=\"${campaign.creative}\"\n campaign_position=\"${campaign.position}\"\n classname=\"${padding_top} ${padding_bottom}\"\n contrast=\"light\">\n\n <div class=\"cb-header\">\n ${this.renderHeader()}\n ${levelsAvailable ? this.renderDescription() : ''}\n </div>\n ${\n levelsAvailable\n ? this.setPropertiesList()\n : `<div class=\"cb-desc cb-no-capsule-prop\">\n ${this.renderDescription()}\n ${this.setPropertiesList()}\n </div>`\n }\n </nb-container>\n `\n }\n\n setPropertiesList() {\n const { sizes, notes } = this.props.copywriting\n\n return `<div class=\"cb-cols\">\n <div class=\"cb-col caption\">\n ${this.renderRoastText()}\n ${this.renderList(sizes)}\n ${this.renderList(notes)}\n </div>\n <div class=\"cb-col\">\n ${this.renderLevels()}\n ${this.renderDetails()}\n </div>\n </div>`\n }\n\n transformRoastLevelToString() {\n const { roast, levels_roast } = this.props.copywriting\n\n if (roast.description < levels_roast.label_light_property) {\n return levels_roast.label_light\n } else if (roast.description < levels_roast.label_medium_property) {\n return levels_roast.label_medium\n } else if (roast.description < levels_roast.label_dark_property) {\n return levels_roast.label_dark\n } else {\n return levels_roast.label_light\n }\n }\n\n renderHeader() {\n const { header_title } = this.props.copywriting\n if (!header_title) {\n return ''\n }\n\n return `<h2 class=\"h-2xl-700\">${header_title}</h2>`\n }\n\n renderDescription() {\n const { description } = this.props.copywriting\n if (!description) {\n return ''\n }\n\n return `<div class=\"description wysiwyg ${\n viewportHelper.is.mobile ? 't-sm-400' : 't-md-400'\n }\">${description}</div>`\n }\n\n renderRoastText() {\n const { roast = {} } = this.props.copywriting\n const { heading, description } = roast\n if (!heading || !description) {\n return ''\n }\n\n return `\n <div class=\"cb-table\">\n <div class=\"cb-row\">\n <p class=\"t-xs-700-sl\">${heading}</p>\n <div class=\"cb-cell is-text\">\n <nb-icon icon=\"24/coffeenote/roasted\"></nb-icon> ${this.transformRoastLevelToString(\n description\n )}\n </div>\n </div>\n </div>\n `\n }\n\n renderList(list) {\n if (!list) {\n return ''\n }\n\n return `<div class=\"cb-cell\">\n <nb-list data='${stringifyForAttribute(list)}'></nb-list>\n </div>`\n }\n\n renderLevels() {\n const { levels } = this.props.copywriting\n\n if (!levels?.length) {\n return ''\n }\n const renderedLevels = levels.reduce(\n (output, level) => `${output}${this.renderLevel(level)}`,\n ''\n )\n if (!renderedLevels) {\n return ''\n }\n return `<div class=\"cb-table\">${renderedLevels}</div>`\n }\n\n renderLevel({ label, value, information }) {\n const { a11y_level_of } = this.props.copywriting\n if (!value) {\n return ''\n }\n return `\n <div class=\"cb-row\">\n <p class=\"t-xs-700-sl\">${label}</p>\n <div class=\"cb-cell\">\n <nb-level value=\"${value}\" a11y_of=\"${a11y_level_of}\"></nb-level>\n </div>\n <nb-tooltip\n content=\"${information}\"\n position=\"top\"\n alignment=\"${viewportHelper.is.mobile ? 'right' : 'center'}\">\n </nb-tooltip>\n </div>\n `\n }\n\n renderDetails() {\n const { details = {} } = this.props.copywriting\n if (!details.heading || !details.text) {\n return ''\n }\n const data = stringifyForAttribute({\n ...details,\n classes: { title: 't-sm-700-sl' }\n })\n return `<nb-collapse data='${data}'></nb-collapse>`\n }\n}\n\ncustomElements.get('nb-detailed-description') ||\n customElements.define('nb-detailed-description', DetailedDescription)\n\nexport default DetailedDescription\n","export const getDataLayer = () => {\n return window[window?.padlNamespace]?.dataLayer\n}\n\nexport const getMarketCode = () => {\n const dataLayer = getDataLayer()\n if (!dataLayer) {\n return 'ch'\n }\n\n return dataLayer.app.app.market.toLocaleLowerCase()\n}\n\nexport const getLangCode = () => {\n const dataLayer = getDataLayer()\n if (!dataLayer) {\n return 'en'\n }\n\n return getDataLayer().page.page.pageInfo.language.toLocaleLowerCase()\n}\n\nexport const getSegmentCode = () => {\n const dataLayer = getDataLayer()\n if (!dataLayer) {\n return 'B2C'\n }\n\n return getDataLayer().page.page.pageInfo.segmentBusiness\n}\n\nexport const isLoggedIn = () => {\n const dataLayer = getDataLayer()\n if (!dataLayer || !dataLayer.user) {\n return false\n }\n\n return dataLayer.user.isLoggedIn\n}\n\nexport const interpolateMarketLang = (string, market, lang) => {\n return string.replace('{market}', market).replace('{lang}', lang)\n}\n","import { getDataLayer } from '@kissui/helpers/src/dataLayer'\n\nexport async function setPDPDataProvider() {\n window.getPDPData = window.getPDPData || getPDPData\n}\n\nexport async function getPDPData() {\n return await window.pdpData\n}\n\nexport async function market() {\n return napi.market().read() // eslint-disable-line\n}\n\nexport function getCurrency() {\n return getDataLayer().currency\n}\n\nexport async function getPriceFormatter() {\n return napi.priceFormat() // eslint-disable-line\n}\n","import { getMarketCode } from './dataLayer'\n\nconst LABEL_CATEGORY_NAME = 'cat/capsule-range-label'\nconst LABEL_CATEGORY_NAME_MACHINE = 'cat/machine-range-label'\nexport const RANGE_CATEGORY_NAME = 'cat/capsule-range'\nconst FAIR_TRADE_CATEGORY_NAME = 'cat/capsule-range-fair-trade'\nconst VERTUO_NEXT_CATEGORY_NAME = 'cat/capsule-attribute-only-vertuo-next'\nconst ORGANIC_EU_CATEGORY_NAME = 'capsule-attribute-organic-eu'\nconst RAINFOREST_CATEGORY_NAME = 'capsule-attribute-rainforest'\nconst SUSTAINABILITY_CATEGORY_NAME = 'capsule-attribute-sustainability'\nconst ARABICA_CATEGORY_NAME = 'capsule-attribute-arabica'\nconst PRODUCT_HIGHLIGHT_CATEGORY_NAME = 'cat/capsule-attribute-highlight'\nconst TECHNOLOGY_CATEGORY_IDENTIFIER = '/machineTechno/'\n\nconst COMMON_URL = 'https://www.nespresso.com/shared_res/agility/commons/img/icons/'\n\nexport const FAIR_TRADE_IMG = COMMON_URL + 'fairTrade.svg'\nexport const ORGANIC_LOGO_IMG_EU = COMMON_URL + 'logo-organic-eu.svg'\nexport const ORGANIC_LOGO_IMG_US = COMMON_URL + 'logo-organic-us.svg'\nexport const ORGANIC_LOGO_IMG_CA = COMMON_URL + 'logo-organic-ca.svg'\nexport const ORGANIC_LOGO_IMG_BR = COMMON_URL + 'logo-organic-br.svg'\nexport const ORGANIC_LOGO_IMG_JP = COMMON_URL + 'logo-organic-jp.svg'\nexport const ORGANIC_LOGO_IMG_BE = COMMON_URL + 'logo-organic-be.png'\n\nexport const VERTUONEXT_LOGO_IMG = COMMON_URL + 'logo-only-vertuo-next.svg'\nexport const RAINFOREST_LOGO_IMG = COMMON_URL + 'logo-rainforest.svg'\nexport const SUSTAINABILITY_LOGO_IMG = COMMON_URL + 'logo-sustainability.svg'\nexport const Q_CERTIFICATION_ARABICA_LOGO_IMG = COMMON_URL + 'q_grade_certification_arabica.svg'\nexport const DESIGN_AWARD_2021_IMG = COMMON_URL + 'design_award_2021.svg'\n\nexport const LOGO_IMG_MAP = {\n fair_trade: FAIR_TRADE_IMG,\n is_organic: getOrganicLogo(),\n only_vertuo_next: VERTUONEXT_LOGO_IMG,\n is_q_certified_arabica: Q_CERTIFICATION_ARABICA_LOGO_IMG,\n is_rainforest: RAINFOREST_LOGO_IMG,\n is_sustainable: SUSTAINABILITY_LOGO_IMG,\n is_design_award_2021: DESIGN_AWARD_2021_IMG\n}\n\nexport function getOrganicLogo() {\n let organicLogoImg = ORGANIC_LOGO_IMG_EU\n\n switch (getMarketCode()) {\n case 'us':\n organicLogoImg = ORGANIC_LOGO_IMG_US\n break\n case 'ca':\n organicLogoImg = ORGANIC_LOGO_IMG_CA\n break\n case 'br':\n organicLogoImg = ORGANIC_LOGO_IMG_BR\n break\n case 'jp':\n organicLogoImg = ORGANIC_LOGO_IMG_JP\n break\n case 'be':\n organicLogoImg = ORGANIC_LOGO_IMG_BE\n break\n }\n\n return organicLogoImg\n}\n\n/**\n * retrieves the list of categories of type Vertuo Next\n * @param {category[]} categories\n */\nexport function getVertuoNext(categories) {\n return categories.find(category => isVertuoNext(category))\n}\n\n/**\n * returns true when the category is product vertuo next\n * @param {category} category\n */\nfunction isVertuoNext(category) {\n return getCategoryRegEx(VERTUO_NEXT_CATEGORY_NAME).test(category.id)\n}\n\n/**\n * retrieves the list of categories of type organic EU\n * @param {category[]} categories\n */\nexport function getOrganicEu(categories) {\n return categories.find(category => isOrganicEu(category))\n}\n\n/**\n * returns true when the category is product organic EU\n * @param {category} category\n */\nfunction isOrganicEu(category) {\n return getCategoryRegEx(ORGANIC_EU_CATEGORY_NAME).test(category.id)\n}\n\n/**\n * retrieves the list of categories of type rainforest\n * @param {category[]} categories\n */\nexport function getRainforest(categories) {\n return categories.find(category => isRainforest(category))\n}\n\n/**\n * returns true when the category is rainforest\n * @param {category} category\n */\nfunction isRainforest(category) {\n return getCategoryRegEx(RAINFOREST_CATEGORY_NAME).test(category.id)\n}\n\n/**\n * retrieves the list of categories of type sustainability\n * @param {category[]} categories\n */\nexport function getSustainability(categories) {\n return categories.find(category => isSustainability(category))\n}\n\n/**\n * retrieves the list of categories of type arabica\n * @param {category[]} categories\n */\nexport function getArabica(categories) {\n return categories.find(category => isArabica(category))\n}\n\n/**\n * returns true when the category is arabica\n * @param {category} category\n */\nfunction isArabica(category) {\n return getCategoryRegEx(ARABICA_CATEGORY_NAME).test(category.id)\n}\n\n/**\n * returns true when the category is sustainability\n * @param {category} category\n */\nfunction isSustainability(category) {\n return getCategoryRegEx(SUSTAINABILITY_CATEGORY_NAME).test(category.id)\n}\n\n/**\n * retrieves the list of categories of type label\n * @param {category[]} categories\n */\nexport function getLabels(categories) {\n return categories.filter(category => isLabel(category))\n}\n\n/**\n * retrieves the list of categories of type label\n * @param {category[]} categories\n */\nexport function getProductHighlight(categories) {\n return categories.find(category => isProductHighlight(category))\n}\n/**\n * retrieves the list of categories of type label\n * @param {category[]} categories\n */\nexport function getFairTrade(categories) {\n return categories.find(category => isFairTrade(category))\n}\n\n/**\n * returns a regex to match the tail (global) of a given local category ID\n * @param {string} categoryIdTail : should contain the end of the category ID\n */\nexport function getCategoryRegEx(categoryIdTail) {\n return new RegExp(categoryIdTail.replace(/\\//g, '\\\\/'))\n}\n\n/**\n * returns true when the category is child of the label category (is type label)\n * @param {category} category\n */\nfunction isLabel(category) {\n return (\n getCategoryRegEx(LABEL_CATEGORY_NAME).test(category.id) ||\n getCategoryRegEx(LABEL_CATEGORY_NAME_MACHINE).test(category.id)\n )\n}\n\n/**\n * returns true when the category is product highlight\n * @param {category} category\n */\nfunction isProductHighlight(category) {\n return getCategoryRegEx(PRODUCT_HIGHLIGHT_CATEGORY_NAME).test(category.id)\n}\n/**\n * returns true when the category is fair trade\n * @param {category} category\n */\nfunction isFairTrade(category) {\n return getCategoryRegEx(FAIR_TRADE_CATEGORY_NAME).test(category.id)\n}\n\n/**\n * returns true when the category is child of the range category (is type range)\n * @param {category} category\n */\nexport function isRange(category) {\n return category.superCategories.some(superCategory =>\n getCategoryRegEx(RANGE_CATEGORY_NAME).test(superCategory)\n )\n}\n\nexport function getTechnologyName(productData, categories) {\n if (!productData || !productData.technologies || !productData.technologies.length) {\n return null\n }\n\n const techno = productData.technologies[0]\n const categoryNameAsSubstring = techno.substring(\n techno.indexOf(TECHNOLOGY_CATEGORY_IDENTIFIER) + TECHNOLOGY_CATEGORY_IDENTIFIER.length\n )\n const category = categories?.find(cat => cat.id === techno)\n\n // Backward compatibility, return name as substring if the list of categories are not available\n return category?.name || categoryNameAsSubstring\n}\n\nexport function isCategoryHidden(categoryId) {\n let hideCategory = false\n // To enable AB testing: exclude categories which are to be hidden\n if (\n window.PLP_HIDE_CATEGORIES?.length &&\n window.PLP_HIDE_CATEGORIES.findIndex(c => categoryId.indexOf(c) >= 0) >= 0\n ) {\n hideCategory = true\n }\n\n // To enable AB testing: exclude categories except those which are to be shown\n if (window.PLP_ONLY_SHOW_CATEGORIES?.length) {\n // Default to hide\n hideCategory = true\n if (window.PLP_ONLY_SHOW_CATEGORIES.findIndex(c => categoryId.indexOf(c) >= 0) >= 0) {\n hideCategory = false\n }\n }\n return hideCategory\n}\n","import {\n getVertuoNext,\n getOrganicEu,\n getLabels,\n getProductHighlight,\n getFairTrade,\n getRainforest,\n getSustainability,\n getArabica\n} from '@kissui/helpers/src/cremaDataHelper'\n\n/**\n * Modifies the structure to make it easier to use in components\n * Applies all the data customization mixing Page builder with HMC data\n * @param {object} plpData : original PLP data\n */\nexport async function getMergedPDPData(pdpData) {\n if (!pdpData) {\n console.error('PDP data is not available')\n return\n }\n const { configuration: { eCommerceData: { categories, product } = {} } = {} } = pdpData\n\n if (product.ranges && product.ranges.length > 0) {\n const rangeId = product.ranges[0]\n const category = categories.find(category => category.id === rangeId)\n if (category != null) {\n product.rangeData = category\n }\n }\n\n addLabels(categories, product)\n addFairTrade(categories, product)\n addProductHighlight(categories, product)\n addVertuoNext(categories, product)\n addOrganicEu(categories, product)\n addRainforest(categories, product)\n addSustainability(categories, product)\n addArabica(categories, product)\n\n return pdpData\n}\n\n/**\n * adds labels property to products containing each label's category data (JSON parsed description property) assigned to it\n * labels are categories that have the label base category as parent\n * to apply a label on a given product, the label has to contain the product\n * this function has to clean the productGroups as well by removing the label ones\n * @param {category[]} categories\n * @param {product} product\n */\nfunction addLabels(categories, product) {\n const labels = getLabels(categories).map(label => label.description)\n product.labels = labels\n}\n\nfunction addVertuoNext(categories, product) {\n const onlyVertuoNext = getVertuoNext(categories)\n if (!onlyVertuoNext) {\n return\n }\n product.onlyVertuoNext = true\n}\n\nfunction addOrganicEu(categories, product) {\n if (getOrganicEu(categories)) {\n product.organicEu = true\n }\n}\n\nfunction addRainforest(categories, product) {\n if (getRainforest(categories)) {\n product.rainforest = true\n }\n}\n\nfunction addSustainability(categories, product) {\n if (getSustainability(categories)) {\n product.sustainability = true\n }\n}\nfunction addArabica(categories, product) {\n if (getArabica(categories)) {\n product.arabica = true\n }\n}\n\n/**\n * adds highlighted property to products containing the product highlight category assigned to it\n * product highlight is a category recognized by ID\n * to apply a the product highlight on a given product, the product highlight productGroup has to contain the product\n * this function has to clean the productGroups as well by removing the product highlight one\n * @param {category[]} categories\n * @param {product} product\n */\nfunction addProductHighlight(categories, product) {\n const productHighlight = getProductHighlight(categories)\n if (!productHighlight) {\n return\n }\n product.highlighted = true\n}\n/**\n * adds fairTrade property to products containing the faire trade category assigned to it\n * Fair trade is a category recognized by ID\n * to apply a the fair trade on a given product, the faire trade productGroup has to contain the product\n * this function has to clean the productGroups as well by removing the fair trade one\n * @param {category[]} categories\n * @param {productGroup[]} productGroups\n * @param {product[]} products\n */\nfunction addFairTrade(categories, product) {\n const fairTrade = getFairTrade(categories)\n if (!fairTrade) {\n return\n }\n product.fairTrade = fairTrade.name\n}\n","export const NOTES_ICON_DEFAULT = '24/coffee/coffee-aroma'\n\n/**\n * Normalize aromatic note\n * E.g. veryRoasted become roasted\n * For notes with hyphen, it's not necessary\n * E.g. nutty-and-balanced will be considered has nutty\n * @param {string} note\n * @returns {string}\n */\nconst harmonizeNoteName = _note => {\n const sanityNote = _note.split('/')\n let note = sanityNote.pop()\n note = note.replace('capsule-aromatic-', '').replace('recipe-', '')\n\n if (['peppery', 'spicy', 'peppery-note'].includes(note)) {\n return '24/coffeenote/spicy'\n } else if (['woody', 'wood', 'oak-wood', 'smoky-wood'].includes(note)) {\n return '24/coffeenote/oak-wood'\n } else if (\n [\n 'sugar',\n 'brown-sugar-and-roasted-notes',\n 'candy-sweet',\n 'delicate-toasted-biscuit-notes'\n ].includes(note)\n ) {\n return '24/coffeenote/sugar'\n } else if (['sweet'].includes(note)) {\n return '24/coffeenote/sweet'\n } else if (['berry'].includes(note)) {\n return '24/coffeenote/berry'\n } else if (['baked-apple', 'apple', 'baked-apple-flavors'].includes(note)) {\n return '24/coffeenote/baked-apple'\n } else if (['bergamot'].includes(note)) {\n return '24/coffeenote/bergamot'\n } else if (['bitterness', 'bitter'].includes(note)) {\n return '24/coffeenote/bitterness'\n } else if (['blueberry'].includes(note)) {\n return '24/coffeenote/blueberry'\n } else if (['bread-aroma', 'bread'].includes(note)) {\n return '24/coffeenote/bread-aroma'\n } else if (['candied-fruit'].includes(note)) {\n return '24/coffeenote/candied-fruit'\n } else if (['caramel'].includes(note)) {\n return '24/coffeenote/caramel'\n } else if (['cereal', 'cerealFruity', 'mild-cereal', 'sweetCereal'].includes(note)) {\n return '24/coffeenote/cereal'\n } else if (\n [\n 'maltedCereal',\n 'malted',\n 'toasted-cereal',\n 'malty-faintly-green-notes',\n 'maltyToasted'\n ].includes(note)\n ) {\n return '24/coffeenote/malted'\n } else if (\n ['roastedCereal', 'veryRoasted', 'roasted', 'longRoasted', 'roastedCocoa'].includes(note)\n ) {\n return '24/coffeenote/roasted'\n } else if (\n [\n 'hintOfFruity',\n 'fruityWiney',\n 'fruity',\n 'fruity-exotic',\n 'juicy-fruity',\n 'ripe-fruits'\n ].includes(note)\n ) {\n return '24/coffeenote/fruity'\n } else if (['citric', 'lemon', 'citrus'].includes(note)) {\n return '24/coffeenote/citrus'\n } else if (['cocoa', 'hintsOfBitterCocoaPowderAndCereals'].includes(note)) {\n return '24/coffeenote/cocoa'\n } else if (['chocolate', 'dark-chocolate', 'white-chocolate'].includes(note)) {\n return '24/coffeenote/chocolate'\n } else if (['cardamom'].includes(note)) {\n return '24/coffeenote/cardamom'\n } else if (['ginger', 'cocoaGinger'].includes(note)) {\n return '24/coffeenote/ginger'\n } else if (['ginseng'].includes(note)) {\n return '24/coffeenote/ginseng'\n } else if (['nutty', 'nut', 'hazelnut', 'hazelnut-aromas'].includes(note)) {\n return '24/coffeenote/hazelnut'\n } else if (['refreshing-mint', 'peppermint'].includes(note)) {\n return '24/coffeenote/peppermint'\n } else if (['almond', 'almonds'].includes(note)) {\n return '24/coffeenote/almonds'\n } else if (['balance', 'balanced', 'smooth'].includes(note)) {\n return '24/coffeenote/balance'\n } else if (['tropical', 'exotic'].includes(note)) {\n return '24/coffeenote/tropical'\n } else if (['coconut'].includes(note)) {\n return '24/coffeenote/coconut'\n } else if (['cocktail'].includes(note)) {\n return '24/coffeenote/cocktail'\n } else if (['biscuity', 'biscuit', 'reminiscent-shortbread-cookies'].includes(note)) {\n return '24/coffeenote/biscuit'\n } else if (\n ['whiskey', 'Whisky', 'whisky', 'alcohol', 'whiskey-flavor', 'whisky-flavour'].includes(\n note\n )\n ) {\n return '24/coffeenote/alcohol'\n } else if (['watermelon'].includes(note)) {\n return '24/coffeenote/watermelon'\n } else if (['RedFruit', 'redfruit', 'red-fruit', 'strawberry'].includes(note)) {\n return '24/coffeenote/red-fruit'\n } else if (\n [\n 'flowery',\n 'flower',\n 'Floral',\n 'floral',\n 'floralJasmine',\n 'floralandWild',\n 'orange-blossom'\n ].includes(note)\n ) {\n return '24/coffeenote/flowery'\n } else if (['herbal', 'dry-vegetal'].includes(note)) {\n return '24/coffeenote/herbal'\n } else if (['honey'].includes(note)) {\n return '24/coffeenote/honey'\n } else if (['smooth-b2b'].includes(note)) {\n return '24/coffeenote/roasted'\n } else if (\n ['sweetnotes-b2b', 'toffeenotes-b2b', 'caramellynotes-b2b', 'caramelized'].includes(note)\n ) {\n return '24/coffeenote/caramel'\n } else if (\n [\n 'rich-b2b',\n 'veryRoasted',\n 'intense',\n 'intense-selection',\n 'rich',\n 'intense-roasted',\n 'bold-roasted-notes'\n ].includes(note)\n ) {\n return '24/coffeenote/intense-roasted'\n } else if (['leather'].includes(note)) {\n return '24/coffeenote/leather'\n } else if (['powerful-intense', 'powerful'].includes(note)) {\n return '24/coffeenote/powerful-intense'\n } else if (['milky', 'milk', 'milk-selection'].includes(note)) {\n return '24/coffeenote/milky'\n } else if (['pumpkin', 'sweet-pumpkin'].includes(note)) {\n return '24/coffeenote/pumpkin'\n } else if (['vanilla', 'vanillaAlmonds', 'vanillaCardamom'].includes(note)) {\n return '24/coffeenote/vanilla'\n } else if (['chicory', 'vegetal'].includes(note)) {\n return '24/coffeenote/vegetal'\n } else if (['winey', 'wine'].includes(note)) {\n return '24/coffeenote/winey'\n } else if (['pecan-nut', 'pecan', 'praline-notes'].includes(note)) {\n return '24/coffeenote/nut'\n } else if (['maple-syrup', 'syrup'].includes(note)) {\n return '24/coffeenote/syrup'\n } else if (['amaretti'].includes(note)) {\n return '24/coffeenote/amaretti'\n } else if (['dry-fruits'].includes(note)) {\n return '24/coffeenote/dry-fruits'\n } else if (['peanut'].includes(note)) {\n return '24/coffeenote/peanut'\n } else if (['popcorn'].includes(note)) {\n return '24/coffeenote/popcorn'\n } else if (['sesame'].includes(note)) {\n return '24/coffeenote/toasted-sesame'\n }\n return NOTES_ICON_DEFAULT\n}\n\nexport const getNoteIcon = note => {\n return harmonizeNoteName(note)\n}\n","export const CUPSIZE_ICON_DEFAULT = '24/cupsize/cupsize-espresso-ol'\n\nconst cupSizeLookup = {\n ristretto: '24/cupsize/cupsize-ristretto-ol',\n espresso: '24/cupsize/cupsize-espresso-ol',\n lungo: '24/cupsize/cupsize-lungo-ol',\n 'lungo-plus': '24/cupsize/cupsize-lungo-plus-ol',\n 'ristretto-vertuo': '24/cupsize/cupsize-ristretto-vl',\n 'espresso-vertuo': '24/cupsize/cupsize-espresso-vl',\n 'double-espresso-vertuo': '24/cupsize/cupsize-lungo-vl',\n 'lungo-vertuo': '24/cupsize/cupsize-lungo-vl',\n 'gran-lungo': '24/cupsize/cupsize-gran-lungo-vl',\n coffee: '24/cupsize/cupsize-mug-small-vl',\n 'mug-medium': '24/cupsize/cupsize-mug-medium-vl',\n 'mug-large': '24/cupsize/cupsize-mug-large-vl',\n 'paper-cup-extra-small-alt': '24/cupsize/paper-cup-extra-small-alt',\n 'paper-cup-extra-small': '24/cupsize/paper-cup-extra-small',\n 'paper-cup-large-alt': '24/cupsize/paper-cup-large-alt',\n 'paper-cup-large': '24/cupsize/paper-cup-large',\n 'paper-cup-medium-alt': '24/cupsize/paper-cup-medium-alt',\n 'paper-cup-medium': '24/cupsize/paper-cup-medium',\n 'paper-cup-small-alt': '24/cupsize/paper-cup-small-alt',\n 'paper-cup-small': '24/cupsize/paper-cup-small',\n xl: '24/accessory/travel-mug-vl',\n 'cold-brew': '24/coffee/cold-brew',\n 'carafe-vertuo': '24/cupsize/cupsize-carafe-vl',\n alto: '24/cupsize/cupsize-alto-vl',\n americano: '24/cupsize/cupsize-americano-ol',\n icedrecipe: '24/recipe/iced-coffee',\n 'icedrecipe-vertuo': '24/recipe/iced-vl',\n milk: '24/coffeenote/milky',\n 'cappuccino-and-latte-macchiato': '24/recipe/cappuccino-ol',\n 'double-cappuccino': '24/recipe/double-cappuccino-vl',\n reverso: '24/recipe/reverso-vl',\n 'cortado-cappuccino': '24/recipe/cortado-ol',\n 'ristretto-b2b': '',\n 'espresso-b2b': '',\n 'lungo-b2b': '',\n 'icedRecipe-b2b': ''\n}\n\n/**\n * @function\n * @description Returns the icon for a given cup size, or a default icon.\n * @param {string} cupSize\n * @param {boolean} returnDefaultIcon If true, an icon will always be returned, else `''`\n * @returns {string}\n */\nexport const getCupSizeIcon = (cupSize, returnDefaultIcon = true) => {\n const cupSizeStr = cupSize ? cupSize.split('/')?.pop() : ''\n\n const cupSizeKey = cupSizeStr\n .toLowerCase()\n .replace('capsule-cupsize-', '')\n .replace('machine-cupsize.', '') // This seems incorrect, but is the information we currenrtly have about this cup size\n\n return cupSizeLookup[cupSizeKey] || (returnDefaultIcon ? CUPSIZE_ICON_DEFAULT : '')\n}\n\n/**\n * @function\n * @description Returns the type of icon for a given cupsize, so to distinguish between\n * coffees for recipes or normal coffees\n * @param {string} cupSize\n * @returns {'recipe' | 'coffee'}\n */\nexport const getCupType = cupSize => {\n const cupSizeIcon = getCupSizeIcon(cupSize)\n if (cupSizeIcon.includes('recipe')) return 'recipe'\n if (cupSizeIcon.includes('cupsize')) return 'coffee'\n}\n","import { setPDPDataProvider } from '@kissui/pdp-data'\n\nimport createProps from '@kissui/helpers/src/props.helpers'\nimport { renderComponent } from '@kissui/helpers/src/render'\nimport { interpolate } from '@kissui/helpers/src/utils'\n\nimport { getMergedPDPData } from '@kissui/helpers/src/PDPservices'\nimport { getNoteIcon } from '@kissui/helpers/src/notesIcons'\nimport { getCupSizeIcon } from '@kissui/helpers/src/cupSizeIcons'\nimport { getProduct } from '@kissui/helpers/src/catalog'\nimport './subcomponents/detailed-description'\n\nclass PdpDetailedDescription extends HTMLElement {\n constructor() {\n super()\n this.props = {}\n this.pdpData = {}\n this.product = null\n this.categories = null\n this.napiProduct = null\n }\n\n async mergePdpData() {\n this.pdpData = await getMergedPDPData(await window.getPDPData())\n this.product = this.pdpData.configuration.eCommerceData.product\n this.categories = this.pdpData.configuration.eCommerceData.categories\n }\n\n async connectedCallback() {\n this.props = createProps(this.attributes)\n\n setPDPDataProvider()\n\n await this.mergePdpData()\n this.render()\n\n try {\n this.napiProduct = await getProduct(this.product.id)\n } catch (e) {\n console.log('PDP, error fetching product data SKU:', this.product.id, e)\n }\n\n if (this.napiProduct.capsuleProperties) {\n // We have new data, re-render the component\n this.render()\n }\n }\n\n render() {\n const product = this.product\n\n const { campaign, copywriting, layout } = this.props\n const { levels } = copywriting\n\n const {\n levels_roast,\n levels_acidity_label,\n levels_bitterness_label,\n levels_roastiness_label,\n levels_body_label,\n levels_acidity_info,\n levels_bitterness_info,\n levels_roastiness_info,\n levels_body_info,\n level_list\n } = levels\n\n const detailedDescData = { levels: level_list }\n\n const notesItems = product?.flavors?.map(noteID => {\n const noteKey = noteID.split('/')?.pop()\n const { name = '' } = this.getCategory(noteID) || {}\n return { icon: getNoteIcon(noteKey), label: name }\n })\n if (notesItems && notesItems.length > 0) {\n detailedDescData.notes = { heading: copywriting.notes_title, items: notesItems }\n }\n\n const sizeItems = product?.cupSizes?.map(cupSizeID => {\n const { name = '', capacityLabel = '' } = this.getCategory(cupSizeID) || {}\n return { icon: getCupSizeIcon(cupSizeID), label: name, size: capacityLabel }\n })\n if (sizeItems && sizeItems.length > 0) {\n detailedDescData.sizes = { heading: copywriting.sizes_title, items: sizeItems }\n }\n\n detailedDescData.details = {\n heading: copywriting.details_heading,\n text: this.renderDetailedDescIngredient(product.ingredients)\n }\n\n if (copywriting.description !== '') {\n detailedDescData.description = interpolate(\n copywriting.description,\n {\n roasting: product.roastingDescription,\n origin: product.originDescription,\n aromatic: product.aromaticProfileDescription\n },\n '{',\n '}'\n )\n } else {\n detailedDescData.description = `<p>${product.originDescription}</p><p>${product.aromaticProfileDescription}</p>`\n }\n\n if (this.napiProduct?.capsuleProperties) {\n // If data is already available from napi then use it instead\n detailedDescData.levels = detailedDescData.levels || []\n\n if (this.napiProduct.capsuleProperties.roastLevel != null && levels_roastiness_label) {\n // we are Finding the index of the existing roastiness level item in the detailedDescData.levels array\n const roastinessItemIndex = detailedDescData.levels.findIndex(\n item => item.label === levels_roastiness_label\n )\n\n // Checking if roastiness is separated and the item exists in the array\n if (levels_roast && levels_roast.is_separated && roastinessItemIndex !== -1) {\n // If roastiness is separated and the item exists, update the roast data\n detailedDescData.roast = {\n heading: levels_roast.label,\n description: this.napiProduct.capsuleProperties.roastLevel\n }\n } else if (roastinessItemIndex !== -1) {\n // If the roastinessItem exists but roastiness is not separated we update the existing item's value and information\n detailedDescData.levels[roastinessItemIndex].value =\n this.napiProduct.capsuleProperties.roastLevel\n detailedDescData.levels[roastinessItemIndex].information =\n levels_roastiness_info\n } else {\n // If the item doesn't exist, add a new roastiness level object to the array\n detailedDescData.levels.unshift({\n label: levels_roastiness_label,\n value: this.napiProduct.capsuleProperties.roastLevel,\n information: levels_roastiness_info\n })\n }\n }\n\n if (this.napiProduct.capsuleProperties.acidity != null && levels_acidity_label) {\n const acidityItem = detailedDescData.levels.find(\n item => item.label === levels_acidity_label\n )\n if (acidityItem) {\n acidityItem.value = this.napiProduct.capsuleProperties.acidity\n acidityItem.information = levels_acidity_label\n } else {\n detailedDescData.levels.unshift({\n label: levels_acidity_label,\n value: this.napiProduct.capsuleProperties.acidity,\n information: levels_acidity_info\n })\n }\n }\n\n if (this.napiProduct.capsuleProperties.bitterness != null && levels_bitterness_label) {\n const bitternessItem = detailedDescData.levels.find(\n item => item.label === levels_bitterness_label\n )\n if (bitternessItem) {\n bitternessItem.value = this.napiProduct.capsuleProperties.bitterness\n bitternessItem.information = levels_bitterness_label\n } else {\n detailedDescData.levels.unshift({\n label: levels_bitterness_label,\n value: this.napiProduct.capsuleProperties.bitterness,\n information: levels_bitterness_info\n })\n }\n }\n\n if (this.napiProduct.capsuleProperties.body > 0 && levels_body_label) {\n // Body data was supplied by NAPI and needs to override Page Builder data\n // so check if it already exists and remove it\n const bodyItem = detailedDescData.levels.find(\n item => item.label === levels_body_label\n )\n if (bodyItem) {\n bodyItem.value = this.napiProduct.capsuleProperties.body\n bodyItem.information = levels_body_info\n } else {\n detailedDescData.levels.unshift({\n label: levels_body_label,\n value: this.napiProduct.capsuleProperties.body,\n information: levels_body_info\n })\n }\n }\n }\n\n const dataToRender = {\n campaign,\n layout,\n copywriting: {\n ...copywriting,\n ...detailedDescData,\n levels_roast\n }\n }\n renderComponent(this, dataToRender, 'nb-detailed-description', 0)\n }\n\n renderDetailedDescIngredient(ingredients) {\n if (!ingredients || !ingredients.length) {\n return ''\n }\n\n let hasParagraphOpened = false\n return (\n ingredients.reduce((acc, ingredient) => {\n if (ingredient.type.code === 'TITLE') {\n hasParagraphOpened = true\n return acc + `<p><strong>${ingredient.text}</strong>`\n } else if (ingredient.type.code === 'DESCRIPTION') {\n const content = `${!hasParagraphOpened ? '<p>' : '<br>'}${ingredient.text}</p>`\n hasParagraphOpened = false\n return acc + content\n }\n }, '') + (hasParagraphOpened ? '</p>' : '')\n )\n }\n\n getCategory(id) {\n return this.categories.find(cat => cat.id === id)\n }\n}\n\ncustomElements.get('nb-pdp-detailed-description') ||\n customElements.define('nb-pdp-detailed-description', PdpDetailedDescription)\n\nexport default PdpDetailedDescription\n","import { COFFEE_VERTUO } from '@kissui/components/src/constants.mjs'\nimport { getCurrency } from './getCurrency'\nexport { getCurrency } from './getCurrency'\n\nexport const ECAPI_TYPE_CAPSULE = 'capsule'\nexport const ECAPI_TYPE_MACHINE = 'machine'\nexport const ECAPI_TYPE_ACCESSORY = 'accessory'\nexport const ECAPI_TYPE_GIFT_CARD = 'giftcard'\n\nconst TECHNOLOGY_CATEGORY_IDENTIFIER = '/machineTechno/'\nconst SLEEVE_OF_10 = 10\nconst SLEEVE_OF_7 = 7\n\nconst trimSku = sku => sku.replace(/[^a-z0-9- +./]/gi, '')\n\nexport const getLegacySKU = productId => productId.split('prod/').pop()\n\nexport const getPriceFormatter = async () => await window.napi.priceFormat()\n\nexport const getProduct = sku => window.napi.catalog().getProduct(trimSku(sku))\n\nexport function getTechnologyName(productData) {\n const techno = productData.technologies[0]\n return techno.substring(\n techno.indexOf(TECHNOLOGY_CATEGORY_IDENTIFIER) + TECHNOLOGY_CATEGORY_IDENTIFIER.length\n )\n}\n\nfunction isMultipleOf(quantity, multiple) {\n return quantity % multiple === 0\n}\n\nexport function getSleeveNumber(product, getTechnologyNameFn = getTechnologyName) {\n if (product.sales_multiple !== 1 && isMultipleOf(product.sales_multiple, SLEEVE_OF_10)) {\n // Sleeve of original or vertuo\n return product.sales_multiple / SLEEVE_OF_10\n }\n\n if (\n product.sales_multiple !== 1 &&\n getTechnologyNameFn(product) === COFFEE_VERTUO &&\n isMultipleOf(product.sales_multiple, SLEEVE_OF_7)\n ) {\n // Sleeve of vertuo\n return product.sales_multiple / SLEEVE_OF_7\n }\n\n if (product.sales_multiple === 1 && isMultipleOf(product.unitQuantity, SLEEVE_OF_10)) {\n // Bundle of original or vertuo\n return product.unitQuantity / SLEEVE_OF_10\n }\n\n if (\n product.sales_multiple === 1 &&\n getTechnologyNameFn(product) === COFFEE_VERTUO &&\n isMultipleOf(product.unitQuantity, SLEEVE_OF_7)\n ) {\n // Bundle of vertuo\n return product.unitQuantity / SLEEVE_OF_7\n }\n\n return NaN\n}\n\n/**\n * Guess if the product is part of a bundle.\n * This is determined by checking the 'sales_multiple' and 'unitQuantity' properties.\n */\nexport function isBundled(productData) {\n // TODO: this function should not change the productData, but some components still need it\n productData.sales_multiple = productData.sales_multiple || productData.salesMultiple\n\n const isSalesMultipleGreaterThanOne = productData.sales_multiple > 1\n const isUnitQuantityEqualToOne = productData.unitQuantity === 1\n const isSalesMultipleEqualToOne = productData.sales_multiple === 1\n const isUnitQuantityGreaterThanOne = productData.unitQuantity > 1\n\n // The product is not bundled if sales_multiple > 1 and unitQuantity = 1\n if (isSalesMultipleGreaterThanOne && isUnitQuantityEqualToOne) {\n return false\n }\n\n // The product is bundled if sales_multiple = 1 and unitQuantity > 1\n return isSalesMultipleEqualToOne && isUnitQuantityGreaterThanOne\n}\n\n/**\n * Replace an array of SKU with product data\n * Remove the element inside the list if sku fail. It prevents to get an empty item.\n * @param {Array.<String>} skus\n * @param getProductFn\n * @returns {Promise<Awaited<unknown>[]>}\n */\nexport function getProductAndClean(skus, getProductFn = getProduct, napi = window.napi) {\n const promises = []\n\n if (!napi) {\n return Promise.reject()\n }\n\n if (!Array.isArray(skus)) {\n skus = [skus]\n }\n\n // Load manually the product to delete SKU fail\n for (const sku of skus) {\n promises.push(\n getProductFn(sku)\n .then(data => skus.splice(skus.indexOf(sku), 1, data))\n .catch(() => {\n skus.splice(skus.indexOf(sku), 1)\n console.error(`getProduct fail on sku ${sku}`)\n })\n )\n }\n\n return Promise.all(promises)\n}\n\nexport const getFormattedPrice = async price => {\n const priceFormatter = await getPriceFormatter()\n const currency = getCurrency()\n\n return priceFormatter.html\n ? priceFormatter.html(currency, price)\n : priceFormatter.short(currency, price) || ''\n}\n\nexport const getProductCategories = async sku => {\n const productDetails = await getProduct(sku)\n const productCategories = productDetails ? productDetails.supercategories : []\n const productCategoriesNew = await Promise.all(\n productCategories.map(async categoryEncoded => {\n const productCategoryData = await window.napi.catalog().getCategory(categoryEncoded)\n return productCategoryData\n })\n )\n return productCategoriesNew\n}\n","export function renderComponent(container, data, tagName, order) {\n const comp = document.createElement(tagName)\n comp.setAttribute('data', JSON.stringify(data))\n appendComponentInOrder(container, comp, tagName, order)\n}\n\nexport function appendComponentInOrder(\n container,\n component,\n tagName,\n order,\n removeExisting = true\n) {\n if (removeExisting) {\n const existing = container.getElementsByTagName(tagName)\n if (existing.length > 0 && existing[0].parentElement) {\n // IE doesn't support element.remove() I don't know if it's transpiled or polyfill\n existing[0].parentElement.removeChild(existing[0])\n }\n }\n if (container.children.length >= order + 1) {\n return container.insertBefore(component, container.children[order])\n } else {\n return container.appendChild(component)\n }\n}\n"],"names":["createProps","attributes","data","find","attribute","nodeName","getData","props","filter","reduce","all","attr","nodeValue","isNil","JSON","parse","error","console","log","obj","helper","is","innerWidth","vw","devicePixelRatio","window","mobile","BREAKPOINT_M","mobile_tablet","BREAKPOINT_TABLET","tablet","desktop","retina","lt","ref","stringifyForAttribute","escapeHtml","stringify","text","map","replace","m","DOMParser","List","HTMLElement","constructor","connectedCallback","this","classes","createClasses","render","baseClass","base","heading","items","item","single","icon","label","innerHTML","renderItems","isSingle","length","first","Boolean","renderItem","renderedItems","output","size","modifier","customElements","get","define","DetailedDescription","campaign","layout","copywriting","levels","padding_top","padding_bottom","background_color","levelsAvailable","every","value","id","name","creative","position","renderHeader","renderDescription","setPropertiesList","sizes","notes","renderRoastText","renderList","renderLevels","renderDetails","transformRoastLevelToString","roast","levels_roast","description","label_light_property","label_light","label_medium_property","label_medium","label_dark_property","label_dark","header_title","viewportHelper","list","renderedLevels","level","renderLevel","information","a11y_level_of","details","title","getMarketCode","dataLayer","padlNamespace","app","market","toLocaleLowerCase","async","getPDPData","pdpData","LABEL_CATEGORY_NAME","LABEL_CATEGORY_NAME_MACHINE","FAIR_TRADE_CATEGORY_NAME","VERTUO_NEXT_CATEGORY_NAME","ORGANIC_EU_CATEGORY_NAME","RAINFOREST_CATEGORY_NAME","SUSTAINABILITY_CATEGORY_NAME","ARABICA_CATEGORY_NAME","PRODUCT_HIGHLIGHT_CATEGORY_NAME","COMMON_URL","ORGANIC_LOGO_IMG_EU","ORGANIC_LOGO_IMG_US","ORGANIC_LOGO_IMG_CA","ORGANIC_LOGO_IMG_BR","ORGANIC_LOGO_IMG_JP","ORGANIC_LOGO_IMG_BE","getVertuoNext","categories","category","getCategoryRegEx","test","isVertuoNext","getOrganicEu","isOrganicEu","getRainforest","isRainforest","getSustainability","isSustainability","getArabica","isArabica","getLabels","isLabel","getProductHighlight","isProductHighlight","getFairTrade","isFairTrade","categoryIdTail","RegExp","getMergedPDPData","configuration","eCommerceData","product","ranges","rangeId","rangeData","addLabels","labels","fairTrade","addFairTrade","highlighted","addProductHighlight","onlyVertuoNext","addVertuoNext","organicEu","addOrganicEu","rainforest","addRainforest","sustainability","addSustainability","arabica","addArabica","organicLogoImg","getOrganicLogo","cupSizeLookup","ristretto","espresso","lungo","coffee","xl","alto","americano","icedrecipe","milk","reverso","getCupSizeIcon","cupSize","returnDefaultIcon","cupSizeKey","split","pop","toLowerCase","PdpDetailedDescription","super","napiProduct","mergePdpData","setPDPDataProvider","sku","napi","catalog","getProduct","trimSku","e","capsuleProperties","levels_acidity_label","levels_bitterness_label","levels_roastiness_label","levels_body_label","levels_acidity_info","levels_bitterness_info","levels_roastiness_info","levels_body_info","level_list","detailedDescData","notesItems","flavors","noteID","noteKey","getCategory","note","_note","includes","NOTES_ICON_DEFAULT","harmonizeNoteName","notes_title","sizeItems","cupSizes","cupSizeID","capacityLabel","sizes_title","details_heading","renderDetailedDescIngredient","ingredients","txt","vars","stChr","enChr","curIdx","stIdx","indexOf","enIdx","hashId","substring","substr","interpolate","roasting","roastingDescription","origin","originDescription","aromatic","aromaticProfileDescription","roastLevel","roastinessItemIndex","findIndex","is_separated","unshift","acidity","acidityItem","bitterness","bitternessItem","body","bodyItem","container","tagName","order","comp","document","createElement","setAttribute","component","removeExisting","existing","getElementsByTagName","parentElement","removeChild","children","insertBefore","appendChild","appendComponentInOrder","renderComponent","hasParagraphOpened","acc","ingredient","type","code","content","cat"],"mappings":"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"}