{"version":3,"file":"modal-upsell-section-xxxxxxxxxxxxxxxxxxxx.min.js","mappings":"yBAYA,MAAMA,oBAAoBC,YAIjBC,WAAAA,GACLC,QAAQ,KAHFC,mBAAqBC,KAAKC,cAAcC,KAAKF,MAInDA,KAAKG,aAAa,CAAEC,KAAM,OAAQC,gBAAgB,IAClDL,KAAKM,WAAWC,UAAY,UAAHC,OCnB7B,qsEDmBgD,YAAAA,OElBrC,64BFmBT,CAEOC,iBAAAA,GACLT,KAAKU,QACP,CAEOC,oBAAAA,GACLC,oBAAoB,eAAgBZ,KAAKD,oBAEzC,MAAMc,EAAeb,KAAKM,WAAWQ,iBAAiB,iBACtD,IAAK,MAAMC,KAAeF,EACxBE,EAAYH,oBAAoB,QAASI,EAE7C,CAEQN,MAAAA,GACNO,iBAAiB,eAAgBjB,KAAKD,oBAEtC,MAAMc,EAAeb,KAAKM,WAAWQ,iBAAiB,iBACtD,IAAK,MAAMC,KAAeF,EACxBE,EAAYE,iBAAiB,QAASD,EAE1C,CAEQf,aAAAA,CAAciB,GAAuC,IAAAC,EAC3D,MAAMC,EAAmB,OAAfD,EAAGD,EAAMG,aAAM,EAAZF,EAAcC,KAC3B,IAAKA,EAEH,YADAE,QAAQC,KAAK,oDAKf,MAAMC,EAAQxB,KAAKc,iBAA8B,uBACjD,IAAK,MAAMW,KAAQD,EAAO,CACxB,MAAME,EAAYC,SAASF,EAAKG,QAAQF,UAAW,IAC7CG,EAAWT,EAAKI,MAAMM,KAAKL,GAAQA,EAAKM,aAAeL,GACzDG,EACFJ,EAAKO,UAAUC,IAAI,UAEnBR,EAAKO,UAAUE,OAAO,SAE1B,CAOA,MAAMC,EAAQnC,KAAKoC,cAAc,kBAC3BC,EAAgBF,EAAMG,aAAe,GAC3CH,EAAMG,YACJD,EAAcE,QAAQ,oBAAqBnB,EAAKoB,YAAc,KAAKC,QAAQ,IAI7EzC,KAAK0C,SAAS,CAAEC,IAAK,EAAGC,SAAU,UACpC,EAGF,SAAS5B,EAAqB6B,GAC5B,MAAM3B,EAAQ,IAAI4B,MAAM,gCACxBC,cAAc7B,EAChB,CG/CA,SAAS8B,IACP,MAAMC,EAAQC,SAASd,cAA2B,iBAClD,IAAKa,EAEH,YADA3B,QAAQC,KAAK,mCAIf0B,EAAMjB,UAAUC,IAAI,UAGpB,MAAMkB,EAAkB,IAAIC,YAAoB,wBAAyB,CACvE/B,OAAQ,CAAEgC,QAASJ,KAErBF,cAAcI,GAGd,MAAMG,EAAqB,IAAIR,MAAM,6BACrCC,cAAcO,EAChB,CHqCKC,eAAeC,IAAI,iBACtBD,eAAeE,OAAO,eAAgB9D,aG7BxCsB,iBAAiB,8BApDjB,WACE,MAAMgC,EAAQC,SAASd,cAA2B,iBAClD,IAAKa,EAEH,YADA3B,QAAQC,KAAK,mCAOf,IADoB0B,EAAMb,cAAc,oCAGtC,YADAsB,SAASC,KAAO,GAAHnD,OAAMoD,QAAQC,OAAOC,KAAI,aAKxC,MAAMC,EAAiB,IAAIX,YAAoB,uBAAwB,CACrE/B,OAAQ,CAAEgC,QAASJ,KAErBF,cAAcgB,GAEdd,EAAMjB,UAAUE,OAAO,UACvBe,EAAMe,OACR,GA8BA/C,iBAAiB,+BAAgC+B,GACjD/B,iBAAiB,iBATjB,SAAyBC,GACTgC,SAASd,cAAc,mBACvBlB,EAAMG,OAAOgC,SACzBL,GAEJ,E","sources":["webpack://lange/./scripts/sections/modal-upsell/modal-upsell/index.ts","webpack://lange/./scripts/sections/modal-upsell/modal-upsell/index.scss","webpack://lange/./scripts/sections/modal-upsell/modal-upsell/index.html","webpack://lange/./scripts/sections/modal-upsell/index.ts"],"sourcesContent":["import { CustomElement } from '@integrabeauty/custom-elements';\nimport html from './index.html';\nimport styles from './index.scss';\n\n/**\n * Custom element that represents the upsell modal component.\n *\n * It appears when user click Checkout CTA in the cart modal if it wasn't already shown. Renders\n * list of products that the user can add to their cart before checking out. Products are filtered\n * based on the current cart contents, so that products that are already in the cart are not shown\n * in the modal. Relies on the modal-manager library.\n */\nclass ModalUpsell extends HTMLElement implements CustomElement {\n  public shadowRoot!: ShadowRoot;\n  private onCartUpdatedBound = this.onCartUpdated.bind(this);\n\n  public constructor() {\n    super();\n    this.attachShadow({ mode: 'open', delegatesFocus: true });\n    this.shadowRoot.innerHTML = `<style>${styles}</style>${html}`;\n  }\n\n  public connectedCallback() {\n    this.render();\n  }\n\n  public disconnectedCallback() {\n    removeEventListener('cart-updated', this.onCartUpdatedBound);\n\n    const closeButtons = this.shadowRoot.querySelectorAll('.close, .back');\n    for (const closeButton of closeButtons) {\n      closeButton.removeEventListener('click', onCloseButtonClicked);\n    }\n  }\n\n  private render() {\n    addEventListener('cart-updated', this.onCartUpdatedBound);\n\n    const closeButtons = this.shadowRoot.querySelectorAll('.close, .back');\n    for (const closeButton of closeButtons) {\n      closeButton.addEventListener('click', onCloseButtonClicked);\n    }\n  }\n\n  private onCartUpdated(event: WindowEventMap['cart-updated']) {\n    const cart = event.detail?.cart;\n    if (!cart) {\n      console.warn('Received cart-updated event without cart details');\n      return;\n    }\n\n    // filter out li elements with products that are already in the cart\n    const items = this.querySelectorAll<HTMLElement>('li[data-product-id]');\n    for (const item of items) {\n      const productId = parseInt(item.dataset.productId, 10);\n      const isInCart = cart.items.some(item => item.product_id === productId);\n      if (isInCart) {\n        item.classList.add('hidden');\n      } else {\n        item.classList.remove('hidden');\n      }\n    }\n\n    // TODO review if we need to handle different currencies. We don't support it here and in all\n    // other places, e.g. the price update on the PDP and product cards.\n\n    // update Estimated Total, replaceing a number in the text content with the new total price.\n    // Expected text content for this element is something like \"$123.45\" or \"$123\".\n    const total = this.querySelector('[slot=\"total\"]');\n    const previousValue = total.textContent || '';\n    total.textContent =\n      previousValue.replace(/\\d+(?:\\.\\d{2})?/g, (cart.total_price / 100).toFixed(2));\n\n    // scroll to top after a product is added to the cart, so that the user can see the free\n    // shipping message\n    this.scrollTo({ top: 0, behavior: 'smooth' });\n  }\n}\n\nfunction onCloseButtonClicked(_event: Event) {\n  const event = new Event('upsell-modal-close-requested');\n  dispatchEvent(event);\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'modal-upsell': ModalUpsell;\n  }\n}\n\nif (!customElements.get('modal-upsell')) {\n  customElements.define('modal-upsell', ModalUpsell);\n}\n","export default \":host{background-color:#fff;border-left:1px solid #dbdbdb;bottom:0;display:flex;flex-direction:column;height:100vh;justify-content:space-between;max-width:100%;overflow:auto;position:fixed;right:0;top:0;width:510px;z-index:510}header{background-color:#fff;padding:12px 56px 12px 16px;position:sticky;top:0;z-index:2}header:after{background-color:#e6e7e8;bottom:0;content:\\\"\\\";height:1px;left:16px;position:absolute;right:16px}h2{font-size:1.5rem;font-weight:600;letter-spacing:.07em;line-height:1.1;margin-bottom:10px;text-transform:uppercase}h2,p{margin-top:0}p{margin-bottom:0}slot[name=delivery-message],slot[name=products]{display:block;padding:16px}slot[name=products]{margin-bottom:auto}::slotted(ul){display:grid;gap:16px;grid-template-columns:1fr 1fr}footer{background-color:#fff;bottom:0;box-shadow:0 -3px 7px #0003;padding:14px 16px 16px;position:sticky;z-index:1}.total{display:flex;font-size:1.25rem;font-weight:600;justify-content:space-between;margin-bottom:10px}.actions{column-gap:12px;display:grid;grid-template-columns:1fr 1fr}.cta{align-items:center;background-color:#000;border:1px solid #000;border-radius:0;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-flex;font-size:1rem;font-weight:600;height:48px;justify-content:center;letter-spacing:.16em;line-height:1;padding:10px 16px;text-align:center;text-decoration:none;text-transform:uppercase;transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);white-space:nowrap;width:100%}.cta:active,.cta:hover{background-color:#333;border-color:#333}.cta:focus{outline:2px solid #000;outline-offset:1px}.cta:disabled,.cta[disabled]{background-color:#e6e7e8;border-color:#e6e7e8;color:#83888c;pointer-events:none}.back{background-color:#fff;border-color:#000;color:#000}.back:active,.back:hover{background-color:#f5f5f5;border-color:#1e1e1e}.policy{font-size:.75rem;margin-top:10px}button{appearance:none;background:none;border:none;color:inherit;cursor:pointer;font:inherit;margin:0;outline:none;padding:0}.close{position:absolute;right:16px;top:12px}.close:hover{opacity:.7}.close:focus{outline:2px solid #000;outline-offset:1px}.close svg{display:block}\";","// Module\nvar code = \"<header><h2><slot name=\\\"title\\\"></slot></h2><p><slot name=\\\"subtitle\\\"></slot></p><button class=\\\"close\\\" aria-label=\\\"Close upsell dialog window\\\"><svg role=\\\"presentation\\\" stroke=\\\"black\\\" fill=\\\"none\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 24 24\\\" width=\\\"24\\\" height=\\\"24\\\"><path d=\\\"M0.600006 23.4L23.4 0.6\\\" stroke-width=\\\"1.5\\\" stroke-miterlimit=\\\"10\\\"></path><path d=\\\"M23.4 23.4L0.600006 0.6\\\" stroke-width=\\\"1.5\\\" stroke-miterlimit=\\\"10\\\"></path></svg></button></header><slot name=\\\"delivery-message\\\"></slot><slot name=\\\"products\\\"></slot><footer><div class=\\\"total\\\"><span>Estimated Total</span><slot name=\\\"total\\\"></slot></div><div class=\\\"actions\\\"><button class=\\\"cta back\\\">Back to Bag</button><a href=\\\"/checkout\\\" class=\\\"cta\\\">Checkout</a></div><p class=\\\"policy\\\">By checking out, I agree to the Terms of Use and acknowledge that I have read the Privacy Policy. Shipping and promotions calculated in checkout.</p></footer>\";\n// Exports\nexport default code;","import './modal-upsell';\n\n/**\n * Handles the upsell modal window. The modal is opened when the user clicks on the checkout button\n * in the cart modal, but only if it wasn't displayed before. If the upsell modal was already\n * displayed, we want to proceed to checkout as normal. The modal can be closed by\n * clicking on the close button or the shroud. When the modal is closed, the cart modal is opened\n * again.\n */\n\nfunction show() {\n  const modal = document.querySelector<HTMLElement>('#modal-upsell');\n  if (!modal) {\n    console.warn('#modal-upsell element not found');\n    return;\n  }\n\n  // check if the there are any product cards to show, if not, don't show the modal and go to\n  // checkout instead\n  const productItem = modal.querySelector('li[data-product-id]:not(.hidden)');\n  if (!productItem) {\n    location.href = `${Shopify.routes.root}checkout`;\n    return;\n  }\n\n  type Detail = WindowEventMap['modal-show-requested']['detail'];\n  const modalShowEvent = new CustomEvent<Detail>('modal-show-requested', {\n    detail: { element: modal }\n  });\n  dispatchEvent(modalShowEvent);\n\n  modal.classList.remove('hidden');\n  modal.focus();\n}\n\nfunction hide() {\n  const modal = document.querySelector<HTMLElement>('#modal-upsell');\n  if (!modal) {\n    console.warn('#modal-upsell element not found');\n    return;\n  }\n\n  modal.classList.add('hidden');\n\n  type Detail = WindowEventMap['modal-close-requested']['detail'];\n  const modalCloseEvent = new CustomEvent<Detail>('modal-close-requested', {\n    detail: { element: modal }\n  });\n  dispatchEvent(modalCloseEvent);\n\n  // when the modal is closed, the cart modal is opened again\n  const cartModalShowEvent = new Event('cart-modal-show-requested');\n  dispatchEvent(cartModalShowEvent);\n}\n\nfunction onShroudClicked(event: WindowEventMap['shroud-clicked']) {\n  const modal = document.querySelector('#modal-upsell');\n  if (modal === event.detail.element) {\n    hide();\n  }\n}\n\naddEventListener('upsell-modal-show-requested', show);\naddEventListener('upsell-modal-close-requested', hide);\naddEventListener('shroud-clicked', onShroudClicked);\n\ndeclare global {\n  interface WindowEventMap {\n    'upsell-modal-close-requested': Event;\n    'upsell-modal-show-requested': Event;\n  }\n}\n"],"names":["ModalUpsell","HTMLElement","constructor","super","onCartUpdatedBound","this","onCartUpdated","bind","attachShadow","mode","delegatesFocus","shadowRoot","innerHTML","concat","connectedCallback","render","disconnectedCallback","removeEventListener","closeButtons","querySelectorAll","closeButton","onCloseButtonClicked","addEventListener","event","_event$detail","cart","detail","console","warn","items","item","productId","parseInt","dataset","isInCart","some","product_id","classList","add","remove","total","querySelector","previousValue","textContent","replace","total_price","toFixed","scrollTo","top","behavior","_event","Event","dispatchEvent","hide","modal","document","modalCloseEvent","CustomEvent","element","cartModalShowEvent","customElements","get","define","location","href","Shopify","routes","root","modalShowEvent","focus"],"sourceRoot":""}