From 130ceed233e2bfa5ff31dca2099802c96fab15fb Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Fri, 5 Jan 2024 15:15:38 +0530 Subject: [PATCH 01/12] Initial commits for child products --- blocks/product-children/product-children.js | 199 ++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 blocks/product-children/product-children.js diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js new file mode 100644 index 000000000..33923355f --- /dev/null +++ b/blocks/product-children/product-children.js @@ -0,0 +1,199 @@ +/* eslint-disable import/no-unresolved */ +import { getMetadata, loadScript } from '../../scripts/lib-franklin.js'; +import { getCookie, isOTEnabled } from '../../scripts/scripts.js'; + +const childProducts = ` + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + +
+
+
+
+
+`; + +export default async function decorate(block) { + const sku = getMetadata('sku') + const host = (window.location.host === 'lifesciences.danaher.com') ? window.location.host : 'stage.lifesciences.danaher.com'; + + block.classList.add('pt-10'); + block.innerHTML = childProducts; + await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); + await customElements.whenDefined('atomic-search-interface'); + loadScript('/blocks/category-family/image-component.js'); + + const productSearchInterface = document.querySelector('atomic-search-interface.product-search'); + + await productSearchInterface.initialize({ + accessToken: window.DanaherConfig.familyProductKey, + organizationId: window.DanaherConfig.searchOrg, + organizationEndpoints: await productSearchInterface + .getOrganizationEndpoints(window.DanaherConfig.searchOrg), + }); + + const isInternal = typeof getCookie('exclude-from-analytics') !== 'undefined'; + const { engine } = productSearchInterface; + const { + loadContextActions, + loadPaginationActions, + loadTabSetActions, + } = await import('https://static.cloud.coveo.com/headless/v2/headless.esm.js'); + + engine.dispatch(loadContextActions(engine).setContext({ + familyid: sku, + host, + internal: isInternal, + })); + + engine.dispatch(loadTabSetActions(engine).updateActiveTab('Family')); + + engine.dispatch(loadPaginationActions(engine).registerNumberOfResults(48)); + + if (!isOTEnabled()) { + productSearchInterface.analytics = false; + } + productSearchInterface.executeFirstSearch(); +} From f61c6583d3396464c282daf730332a034a892613 Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Fri, 5 Jan 2024 22:57:51 +0530 Subject: [PATCH 02/12] updated products --- blocks/product-children/product-children.js | 362 +++++++++++++------- 1 file changed, 247 insertions(+), 115 deletions(-) diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index 33923355f..ad5ca3d05 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -5,21 +5,10 @@ import { getCookie, isOTEnabled } from '../../scripts/scripts.js'; const childProducts = ` - + fields-to-include='["brand","images","sku","title","description","richdescription","opco","contenttype","documenttype","pagetype","shortspecifications", "specificationsjson", "specifications", "bundlepreviewjson"]'> @@ -30,9 +19,9 @@ const childProducts = ` - + -
+
@@ -40,48 +29,139 @@ const childProducts = ` @@ -158,42 +287,45 @@ const childProducts = ` export default async function decorate(block) { const sku = getMetadata('sku') const host = (window.location.host === 'lifesciences.danaher.com') ? window.location.host : 'stage.lifesciences.danaher.com'; + let response; + if (localStorage.getItem('product-details')) response = JSON.parse(localStorage.getItem('product-details')); + if (response[0]?.raw?.objecttype === 'Family' && response[0]?.raw?.numproducts > 0) { + block.classList.add('pt-10'); + block.innerHTML = childProducts; + await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); + await customElements.whenDefined('atomic-search-interface'); + loadScript('/blocks/category-family/image-component.js'); - block.classList.add('pt-10'); - block.innerHTML = childProducts; - await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); - await customElements.whenDefined('atomic-search-interface'); - loadScript('/blocks/category-family/image-component.js'); - - const productSearchInterface = document.querySelector('atomic-search-interface.product-search'); + const productSearchInterface = document.querySelector('atomic-search-interface.product-search'); - await productSearchInterface.initialize({ - accessToken: window.DanaherConfig.familyProductKey, - organizationId: window.DanaherConfig.searchOrg, - organizationEndpoints: await productSearchInterface - .getOrganizationEndpoints(window.DanaherConfig.searchOrg), - }); + await productSearchInterface.initialize({ + accessToken: window.DanaherConfig.familyProductKey, + organizationId: window.DanaherConfig.searchOrg, + organizationEndpoints: await productSearchInterface + .getOrganizationEndpoints(window.DanaherConfig.searchOrg), + }); - const isInternal = typeof getCookie('exclude-from-analytics') !== 'undefined'; - const { engine } = productSearchInterface; - const { - loadContextActions, - loadPaginationActions, - loadTabSetActions, - } = await import('https://static.cloud.coveo.com/headless/v2/headless.esm.js'); + const isInternal = typeof getCookie('exclude-from-analytics') !== 'undefined'; + const { engine } = productSearchInterface; + const { + loadContextActions, + loadPaginationActions, + loadTabSetActions, + } = await import('https://static.cloud.coveo.com/headless/v2/headless.esm.js'); - engine.dispatch(loadContextActions(engine).setContext({ - familyid: sku, - host, - internal: isInternal, - })); + engine.dispatch(loadContextActions(engine).setContext({ + familyid: sku, + host, + internal: isInternal, + })); - engine.dispatch(loadTabSetActions(engine).updateActiveTab('Family')); + engine.dispatch(loadTabSetActions(engine).updateActiveTab('Family')); - engine.dispatch(loadPaginationActions(engine).registerNumberOfResults(48)); + engine.dispatch(loadPaginationActions(engine).registerNumberOfResults(48)); - if (!isOTEnabled()) { - productSearchInterface.analytics = false; + if (!isOTEnabled()) { + productSearchInterface.analytics = false; + } + productSearchInterface.executeFirstSearch(); } - productSearchInterface.executeFirstSearch(); } From 8494608f0bd34a277fb705a12f110a7052d09b1a Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Mon, 8 Jan 2024 16:48:01 -0500 Subject: [PATCH 03/12] Product tile custom element in atomic result template --- blocks/product-children/product-children.js | 251 +----------------- blocks/product-children/product-tile.js | 269 ++++++++++++++++++++ styles/coveo-custom/product-tile.css | 1 + templates/productDetail/productDetail.js | 3 +- 4 files changed, 285 insertions(+), 239 deletions(-) create mode 100644 blocks/product-children/product-tile.js create mode 100644 styles/coveo-custom/product-tile.css diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index ad5ca3d05..129db22c6 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -1,7 +1,9 @@ /* eslint-disable import/no-unresolved */ +import ProductTile from './product-tile.js'; import { getMetadata, loadScript } from '../../scripts/lib-franklin.js'; import { getCookie, isOTEnabled } from '../../scripts/scripts.js'; +customElements.define('product-tile', ProductTile); const childProducts = ` @@ -285,7 +62,7 @@ const childProducts = ` `; export default async function decorate(block) { - const sku = getMetadata('sku') + const sku = getMetadata('sku'); const host = (window.location.host === 'lifesciences.danaher.com') ? window.location.host : 'stage.lifesciences.danaher.com'; let response; if (localStorage.getItem('product-details')) response = JSON.parse(localStorage.getItem('product-details')); @@ -299,24 +76,24 @@ export default async function decorate(block) { const productSearchInterface = document.querySelector('atomic-search-interface.product-search'); await productSearchInterface.initialize({ - accessToken: window.DanaherConfig.familyProductKey, - organizationId: window.DanaherConfig.searchOrg, - organizationEndpoints: await productSearchInterface + accessToken: window.DanaherConfig.familyProductKey, + organizationId: window.DanaherConfig.searchOrg, + organizationEndpoints: await productSearchInterface .getOrganizationEndpoints(window.DanaherConfig.searchOrg), }); const isInternal = typeof getCookie('exclude-from-analytics') !== 'undefined'; const { engine } = productSearchInterface; const { - loadContextActions, - loadPaginationActions, - loadTabSetActions, + loadContextActions, + loadPaginationActions, + loadTabSetActions, } = await import('https://static.cloud.coveo.com/headless/v2/headless.esm.js'); engine.dispatch(loadContextActions(engine).setContext({ - familyid: sku, - host, - internal: isInternal, + familyid: sku, + host, + internal: isInternal, })); engine.dispatch(loadTabSetActions(engine).updateActiveTab('Family')); @@ -324,7 +101,7 @@ export default async function decorate(block) { engine.dispatch(loadPaginationActions(engine).registerNumberOfResults(48)); if (!isOTEnabled()) { - productSearchInterface.analytics = false; + productSearchInterface.analytics = false; } productSearchInterface.executeFirstSearch(); } diff --git a/blocks/product-children/product-tile.js b/blocks/product-children/product-tile.js new file mode 100644 index 000000000..5165d1637 --- /dev/null +++ b/blocks/product-children/product-tile.js @@ -0,0 +1,269 @@ +import { getAuthorization, getCommerceBase } from '../../scripts/commerce.js'; + +const baseURL = getCommerceBase(); +/* eslint-disable no-console */ +export default class ProductTile extends HTMLElement { + sku; + + result; + + product; + + showPartList = false; + + specifications = {}; + + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + hasPrice() { + return this.product?.salePrice && this.product?.salePrice?.value > 0; + } + + bundlepreviewJson() { + return this.result?.raw?.bundlepreviewjson + ? JSON.parse(this.result?.raw?.bundlepreviewjson) : []; + } + + getSpecifications() { + if (this.result?.raw?.specificationsjson) { + const specifications = JSON.parse(this.result?.raw?.specificationsjson); + const trimmedSpecifications = {}; + let keys = Object.keys(specifications); + const filteredSpecification = keys.filter((key) => specifications[key]?.at(0)?.length > 0) + .reduce((obj, key) => { + obj[key] = specifications[key]; + return obj; + }, {}); + keys = Object.keys(filteredSpecification); + if (keys.length > 3) { + this.specifications = keys.slice(0, 3).forEach((key) => { + trimmedSpecifications[key] = specifications[key]; + }); + this.specifications = trimmedSpecifications; + } else { + this.specifications = filteredSpecification; + } + } + return this.specifications; + } + + // eslint-disable-next-line class-methods-use-this + formatCurrency(value, currencyCode) { + if (value) { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: currencyCode?.toUpperCase() || 'USD', + }).format(value); + } + return ''; + } + + async connectedCallback() { + const { resultContext } = await import( + // eslint-disable-next-line import/no-unresolved + 'https://static.cloud.coveo.com/atomic/v2/index.esm.js' + ); + this.result = await resultContext(this); + this.sku = this.result.raw.sku; + await this.getProduct(); + this.getSpecifications(); + this.render(); + this.attachEventListeners(); + } + + attachEventListeners() { + // Attach a click event listener to the button + const button = this.shadowRoot.querySelector('.add-to-quote'); + button?.addEventListener('click', this.onButtonClick.bind(this)); + const bundleDetails = this.shadowRoot.querySelector('.bundle-details'); + bundleDetails?.addEventListener('click', () => { + this.showPartList = !this.showPartList; + }); + } + + // eslint-disable-next-line class-methods-use-this + onButtonClick() { + this.addToQuote(); + } + + async getProduct() { + try { + if (this.sku) { + const product = await fetch(`${baseURL}/products/${this.sku}`); + this.product = product; + } + } catch (error) { + console.error(error); + } + } + + async addToQuote() { + try { + const authHeader = getAuthorization(); + if (authHeader && (authHeader.has('authentication-token') || authHeader.has('Authorization'))) { + const quote = await fetch(`${baseURL}/rfqcart/-`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', ...Object.fromEntries(authHeader) }, + body: JSON.stringify({ + quantity: { + type: 'Quantity', + value: 1, + unit: 'N/A', + }, + productSKU: this.sku, + image: this.image, + brand: this.opco, + productDescription: this.description, + referrer: window.location.href, + referrerTitle: document.title.replace('| Danaher Lifesciences', '').replace('| Danaher Life Sciences', '').trim(), + country: this.country, + }), + }); + this.quote = quote; + } + } catch (error) { + console.error(error); + } + } + + render() { + this.shadowRoot.innerHTML = ` + +
+
+
+ +
+
+ ${this.result?.raw?.objecttype === 'Product' || this.result?.raw?.objecttype === 'Bundle' ? ` + + + + ` : ''} + + + +
+ ${this.result?.raw?.objecttype === 'Product' || this.result?.raw?.objecttype === 'Bundle' ? ` + +

+
+ ` : ''} +
+ ${this.result?.raw?.objecttype === 'Family' || this.result?.raw?.objecttype === 'Bundle' ? ` +
+ ${this.result?.raw?.richdescription} +
+ ${this.result?.raw?.objecttype === 'Bundle' ? ` +
+ + See Full Specifications + + +
+ ` : ''} + ` : ''} + ${this.result?.raw?.objecttype === 'Product' ? ` +
+ ${Object.entries(this.specifications).map(([index, content]) => ` +
+
+
+ ${index}: +
+
+
+
+ ${typeof content !== 'object' ? content : content.toString().replaceAll(',', ', ')} +
+
+
+ `).join('')} +
+
+ + See Full Specifications + + +
+ ` : ''} +
+
+ +
+ + + +
+
+ ${this.result?.raw?.objecttype === 'Product' || this.result?.raw?.objecttype === 'Bundle' ? ` +
+
+
+
+

+ ${this.hasPrice() ? `${this.formatCurrency(this.product.salePrice?.value, this.product.salePrice?.currencyMnemonic)}` : 'Request for Price'} + ${this.hasPrice() ? '
(USD)
' : ''} +

+
+
+

Unit of Measure:

+

+ ${this.product?.minOrderQuantity ? `${this.product.minOrderQuantity}` : '1'}/${this.product?.packingUnit ? `${this.product.packingUnit}` : 'EA'} +

+
+
+

Min. Order Qty:

+

${this.product?.minOrderQuantity ? `${this.product?.minOrderQuantity}` : '1'}

+
+
+ ${this.hasPrice() ? ` + + + ` : ''} + +
+ ${this.bundlepreviewJson()?.length > 0 ? ` + + ${this.showPartList ? 'Hide' : 'Show'} Product Details + + + ` : ''} +
+
+
+ ` : ''} +
+ ${this.showPartList ? ` +
+
+ Products + QTY +
+
+ ${Object.entries(this.bundlepreviewJson()).map(([bundle]) => ` +
+
+
+ +
+
+ ${bundle?.title} +
+

${bundle?.sku}

+
+
+
+
+ ${bundle?.quantity} +
+
+ `).join('')}` : ''}`; + } +} diff --git a/styles/coveo-custom/product-tile.css b/styles/coveo-custom/product-tile.css new file mode 100644 index 000000000..9a8447541 --- /dev/null +++ b/styles/coveo-custom/product-tile.css @@ -0,0 +1 @@ +.flex-justify-between{display:flex;width:100%;align-items:center;justify-content:space-between}.border-bottom{border-left-width:0px;border-right-width:0px;border-bottom-width:1px;border-top-width:0px;border-style:solid;--tw-border-opacity:1;border-bottom-color:rgb(229 231 235 / var(--tw-border-opacity))}.padding-x-3{padding-left:0.75rem;padding-right:0.75rem}.product-description{position:relative;margin-top:0.5rem;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden}.product-description::after{content:"";position:absolute;bottom:0px;right:0px;height:3rem;width:100%;background-image:linear-gradient(to bottom, var(--tw-gradient-stops));--tw-gradient-from:transparent var(--tw-gradient-from-position);--tw-gradient-to:rgb(0 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from), var(--tw-gradient-to);--tw-gradient-to:#fff var(--tw-gradient-to-position)}.product-description.family::after{height:4rem}.product-description h1,.product-description h2,.product-description h3,.product-description h4,.product-description h5,.product-description h6,.product-description p{margin:0px}.no-border{border-style:none}.bundle-image{height:100%;width:100%;-o-object-fit:contain;object-fit:contain}.description{display:flex;flex:1 1 0%;flex-direction:column;padding-top:0.5rem;padding-bottom:0.5rem;padding-right:0.5rem}.sku-text{margin-bottom:0.25rem;display:flex}.sku-text > :not([hidden]) ~ :not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.sku-text{font-size:0.75rem;line-height:1rem;--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.sku-text p{margin:0px}.bundle-heading{padding-top:1rem;padding-bottom:1rem;font-size:1rem;line-height:1.5rem;font-weight:700}.danaherpurple{--tw-text-opacity:1;color:rgb(117 35 255 / var(--tw-text-opacity))}.bundle-icon,.icon{height:1.25rem;width:1.25rem;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.flex-end{margin-top:1.25rem;display:flex;justify-content:flex-end}.flex-end a{text-decoration-line:none}.flex-end a:hover{text-decoration-line:none}.gray-background{--tw-bg-opacity:1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.rotate{--tw-rotate:180deg;transform:translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.bundle-details{display:flex;align-items:center;font-size:1rem;line-height:1.5rem;font-weight:700}.b{display:grid;height:auto;min-width:100%;grid-template-columns:repeat(1, minmax(0, 1fr));-moz-column-gap:0.5rem;column-gap:0.5rem;vertical-align:middle}@media (min-width: 768px){.b{grid-template-columns:repeat(2, minmax(0, 1fr))}}.c{display:flex;width:100%;font-size:0.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}.d{margin-top:auto;margin-bottom:auto;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.e{display:flex;width:100%;overflow-wrap:break-word;padding-top:0.25rem;padding-bottom:0.25rem;font-size:0.875rem;line-height:1.25rem;font-weight:600;--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}.flex-wrapper{display:flex}.flex-wrapper.family-width{width:85%}.flex-wrapper.product-width{width:100%}@media (min-width: 768px){.flex-wrapper.product-width{width:66.666667%}}.image-container{height:6rem;width:6rem;flex-shrink:0;padding-top:0.5rem;padding-bottom:0.5rem;padding-right:1rem}.image-container img{border-radius:0.375rem;--tw-shadow:0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.bundle-image-container{height:5rem;width:5rem;flex-shrink:0;padding-top:0.5rem;padding-bottom:0.5rem;padding-right:1rem}.bundle-image-container img{border-radius:0.375rem;--tw-shadow:0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)}.att-label{font-weight:700}.sku-text{margin-bottom:0.25rem;display:flex}.sku-text > :not([hidden]) ~ :not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.sku-text{font-size:0.75rem;line-height:1rem;--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.sku-text p{margin:0px}.middle-align{margin-top:auto;margin-bottom:auto;width:100%;padding:0.25rem}.tile-wrapper{display:flex;width:100%;flex-direction:column}@media (min-width: 768px){.tile-wrapper{flex-direction:row}}atomic-result-title{font-size:1.125rem;line-height:1.75rem;font-weight:700;--tw-text-opacity:1;color:rgb(55 65 81 / var(--tw-text-opacity))}atomic-result-title:hover{--tw-text-opacity:1;color:rgb(31 41 55 / var(--tw-text-opacity))}atomic-result-title a{text-decoration-line:none;text-decoration-thickness:0px}atomic-field-condition{max-width:none}.full-specification{margin-top:0.5rem;line-height:1.5rem;--tw-text-opacity:1;color:rgb(117 35 255 / var(--tw-text-opacity))}.full-specification a{display:flex;align-items:center;font-weight:700;--tw-text-opacity:1;color:rgb(117 35 255 / var(--tw-text-opacity));text-decoration-line:none}.full-specification a:hover{text-decoration-line:none}.full-specification a:hover,.full-specification a:visited,.full-specification a:active,.full-specification a:focus{--tw-text-opacity:1;color:rgb(117 35 255 / var(--tw-text-opacity))}.bundle-p-title{font-weight:500;--tw-text-opacity:1;color:rgb(107 114 128 / var(--tw-text-opacity))}.action-wrapper{display:flex;width:100%;border-top-width:0px;border-bottom-width:0px;border-left-width:1px;border-right-width:0px;border-style:solid;--tw-border-opacity:1;border-left-color:rgb(229 231 235 / var(--tw-border-opacity));border-right-color:rgb(229 231 235 / var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(249 250 251 / var(--tw-bg-opacity));padding-top:0.5rem;padding-bottom:0.5rem}@media (min-width: 768px){.action-wrapper{width:50%}}.family-wrapper{display:flex;padding-top:1rem;padding-bottom:1rem}.description{display:flex;flex:1 1 0%;flex-direction:column;padding-top:0.5rem;padding-bottom:0.5rem;padding-right:0.5rem}.family-description{display:flex;width:75%;flex:1 1 0%;flex-direction:column;padding-top:0.5rem;padding-bottom:0.5rem;padding-right:0.5rem}.add-to-cart-wrapper{display:flex;flex-direction:column;gap:0.5rem;padding-left:0.5rem;padding-right:0.5rem;--tw-text-opacity:1;color:rgb(17 24 39 / var(--tw-text-opacity))}.price-block{display:flex;justify-content:flex-end}.price-text{margin:0px;font-size:2.25rem;font-weight:800;line-height:2.25rem}.price-text.no-price{font-size:1.5rem;line-height:2rem}.price-attribute{display:flex;justify-content:space-between;font-size:0.875rem;line-height:1.25rem;font-weight:600}.price-attribute-text{margin-top:0px;margin-bottom:0px;font-size:0.875rem;font-weight:400;line-height:1.25rem}.price-attribute-value{margin-top:0px;margin-bottom:0px;margin-left:auto}.add-to-cart-cta{display:flex}.add-to-cart-cta > :not([hidden]) ~ :not([hidden]){--tw-space-x-reverse:0;margin-right:calc(0.5rem * var(--tw-space-x-reverse));margin-left:calc(0.5rem * calc(1 - var(--tw-space-x-reverse)))}.add-to-cart-cta.flex-end{justify-content:flex-end}.add-to-cart-cta.flex-between{justify-content:space-between}.quantity-input{width:2rem;border-radius:0.375rem;border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(209 213 219 / var(--tw-border-opacity));padding:0.5rem}.price-currency{margin:0px;display:inline-block;vertical-align:bottom;font-size:0.75rem;line-height:1rem;font-weight:600}.rfq-button{margin-bottom:1rem;display:block;padding-left:2rem;padding-right:2rem}@media (min-width: 640px){.rfq-button{margin-bottom:0px;display:flex}}.btn{display:inline-flex;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;place-items:center;justify-content:center}.btn > :not([hidden]) ~ :not([hidden]){--tw-space-x-reverse:0;margin-right:calc(0.25rem * var(--tw-space-x-reverse));margin-left:calc(0.25rem * calc(1 - var(--tw-space-x-reverse)))}.btn{white-space:nowrap;border-radius:9999px;--tw-bg-opacity:1;background-color:rgb(117 35 255 / var(--tw-bg-opacity));padding-top:0.5rem;padding-bottom:0.5rem;padding-left:1rem;padding-right:1rem;text-align:center;vertical-align:middle;font-size:1rem;line-height:1.5rem;font-weight:400;letter-spacing:0.025em;--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity));text-decoration-line:none;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;transition-property:color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms}.btn:hover{--tw-bg-opacity:1;background-color:rgb(64 0 165 / var(--tw-bg-opacity))}.btn:focus{outline:2px solid transparent;outline-offset:2px}.btn.btn-outline-brand{border-width:1px;border-style:solid;--tw-border-opacity:1;border-color:rgb(117 35 255 / var(--tw-border-opacity));--tw-bg-opacity:1;background-color:rgb(255 255 255 / var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(117 35 255 / var(--tw-text-opacity))}.btn.btn-outline-brand:hover{--tw-bg-opacity:1;background-color:rgb(117 35 255 / var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}.btn.orange{border-style:none}.brand-info{font-size:0.875rem;font-weight:400;line-height:1.25rem;--tw-text-opacity:1;color:rgb(59 199 229 / var(--tw-text-opacity))} \ No newline at end of file diff --git a/templates/productDetail/productDetail.js b/templates/productDetail/productDetail.js index 640bb56b1..228e0d6c4 100644 --- a/templates/productDetail/productDetail.js +++ b/templates/productDetail/productDetail.js @@ -2,8 +2,7 @@ import { getMetadata } from '../../scripts/lib-franklin.js'; import { makeCoveoApiRequest } from '../../scripts/scripts.js'; function getCoveoApiPayload(qParam) { - let sku = getMetadata('sku'); - sku = sku.at(0).split('.').at(0); + const sku = getMetadata('sku'); const payload = { context: { host: 'stage.lifesciences.danaher.com', From 82296481c942f9b537403ed1157dfca077cdc791 Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Tue, 9 Jan 2024 15:16:59 +0530 Subject: [PATCH 04/12] updated for pagination --- blocks/product-children/product-children.js | 8 ++++++++ blocks/product-resources/product-resources.js | 18 +++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index 129db22c6..454d3ba82 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -11,6 +11,14 @@ const childProducts = ` pipeline="Danaher Family Product Listing" language-assets-path="${window.location.origin}/localization" fields-to-include='["brand","images","sku","title","description","richdescription","opco","contenttype","documenttype","pagetype","shortspecifications", "specificationsjson", "specifications", "bundlepreviewjson"]'> + diff --git a/blocks/product-resources/product-resources.js b/blocks/product-resources/product-resources.js index 187b0ebe3..fc8dbdc25 100644 --- a/blocks/product-resources/product-resources.js +++ b/blocks/product-resources/product-resources.js @@ -10,15 +10,15 @@ const productResources = ` language-assets-path="${window.location.origin}/localization" fields-to-include='["ec_images","ec_brand","images","sku","description","opco","contenttype","documenttype","workflow","chromatographycolumninternaldiametermetricmm","chromatographycolumnlengthmetricmm","chromatographycolumnparticlesizemetricmicrometer","chromatographycolumnporesizemetricangstrom","chromatographytype","discontinued"]'> From 23333e5c0d8b47851914e7c93ab3b02dd05230c4 Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Tue, 9 Jan 2024 16:06:31 +0530 Subject: [PATCH 05/12] updated response from scripts --- blocks/product-children/product-children.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index 454d3ba82..9561c58a9 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -1,7 +1,7 @@ /* eslint-disable import/no-unresolved */ import ProductTile from './product-tile.js'; import { getMetadata, loadScript } from '../../scripts/lib-franklin.js'; -import { getCookie, isOTEnabled } from '../../scripts/scripts.js'; +import { getCookie, isOTEnabled, getProductResponse } from '../../scripts/scripts.js'; customElements.define('product-tile', ProductTile); const childProducts = ` @@ -72,9 +72,8 @@ const childProducts = ` export default async function decorate(block) { const sku = getMetadata('sku'); const host = (window.location.host === 'lifesciences.danaher.com') ? window.location.host : 'stage.lifesciences.danaher.com'; - let response; - if (localStorage.getItem('product-details')) response = JSON.parse(localStorage.getItem('product-details')); - if (response[0]?.raw?.objecttype === 'Family' && response[0]?.raw?.numproducts > 0) { + const response = getProductResponse(); + if (response?.length > 0 && response[0]?.raw?.objecttype === 'Family' && response[0]?.raw?.numproducts > 0) { block.classList.add('pt-10'); block.innerHTML = childProducts; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); From 015327c09e9513fd04bc2afd6e830f2b1c5d3b0d Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 10 Jan 2024 18:55:07 +0530 Subject: [PATCH 06/12] added toast notofication --- blocks/product-children/product-children.js | 8 +++++--- blocks/product-children/product-tile.js | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index 9561c58a9..c4929d2ae 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -1,7 +1,9 @@ /* eslint-disable import/no-unresolved */ import ProductTile from './product-tile.js'; -import { getMetadata, loadScript } from '../../scripts/lib-franklin.js'; -import { getCookie, isOTEnabled, getProductResponse } from '../../scripts/scripts.js'; +import { loadScript } from '../../scripts/lib-franklin.js'; +import { + getCookie, isOTEnabled, getProductResponse, getSKU, +} from '../../scripts/scripts.js'; customElements.define('product-tile', ProductTile); const childProducts = ` @@ -70,7 +72,7 @@ const childProducts = ` `; export default async function decorate(block) { - const sku = getMetadata('sku'); + const sku = getSKU(); const host = (window.location.host === 'lifesciences.danaher.com') ? window.location.host : 'stage.lifesciences.danaher.com'; const response = getProductResponse(); if (response?.length > 0 && response[0]?.raw?.objecttype === 'Family' && response[0]?.raw?.numproducts > 0) { diff --git a/blocks/product-children/product-tile.js b/blocks/product-children/product-tile.js index 5165d1637..1bea7c4bb 100644 --- a/blocks/product-children/product-tile.js +++ b/blocks/product-children/product-tile.js @@ -123,6 +123,12 @@ export default class ProductTile extends HTMLElement { }), }); this.quote = quote; + if (this.quote.status === 200) { + const responseJson = await this.quote.json(); + const addedProduct = responseJson?.items?.slice(-1)?.at(0); + const { default: getToast } = await import('../../scripts/toast.js'); + await getToast('quote-toast', addedProduct); + } } } catch (error) { console.error(error); @@ -240,6 +246,7 @@ export default class ProductTile extends HTMLElement {
` : ''} + ${this.showPartList ? 'show' : 'hide'} ${this.showPartList ? `
From 254fbf2b2114d76decff458f50da02f6e330aeeb Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 10 Jan 2024 21:27:21 +0530 Subject: [PATCH 07/12] updated for show/hide products --- blocks/product-children/product-tile.js | 102 +++++++++++++++++------- scripts/toast.js | 2 +- styles/styles.css | 5 -- 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/blocks/product-children/product-tile.js b/blocks/product-children/product-tile.js index 1bea7c4bb..013521404 100644 --- a/blocks/product-children/product-tile.js +++ b/blocks/product-children/product-tile.js @@ -1,4 +1,7 @@ import { getAuthorization, getCommerceBase } from '../../scripts/commerce.js'; +import { + div, img, p, span, +} from '../../scripts/dom-builder.js'; const baseURL = getCommerceBase(); /* eslint-disable no-console */ @@ -79,11 +82,17 @@ export default class ProductTile extends HTMLElement { const button = this.shadowRoot.querySelector('.add-to-quote'); button?.addEventListener('click', this.onButtonClick.bind(this)); const bundleDetails = this.shadowRoot.querySelector('.bundle-details'); - bundleDetails?.addEventListener('click', () => { + bundleDetails?.addEventListener('click', (e) => { + e.preventDefault(); this.showPartList = !this.showPartList; + this.appendProductDetails(); }); } + getShowPartList() { + return this.showPartList; + } + // eslint-disable-next-line class-methods-use-this onButtonClick() { this.addToQuote(); @@ -135,12 +144,68 @@ export default class ProductTile extends HTMLElement { } } + appendProductDetails() { + const list = this.shadowRoot.querySelector('.product-details-list'); + const tileWrapper = this.shadowRoot.querySelector('.tile-wrapper'); + const link = this.shadowRoot.querySelector('.product-detail-link'); + if (this.showPartList) { + link.innerHTML = `Hide Produt Details + + `; + tileWrapper.classList.add('no-border'); + tileWrapper.classList.remove('border-bottom'); + const detailsHeading = div( + { class: 'details-heading gray-background padding-x-3' }, + div( + { class: 'flex-justify-between bundle-heading' }, + span({ class: 'bundle-title' }, 'Products'), + span({ class: 'bundle-qty' }, 'QTY'), + ), + ); + list.append(detailsHeading); + /* eslint-disable-next-line */ + Object.entries(this.bundlepreviewJson()).map(([i, bundle]) => { + const detailItem = div( + { class: 'details-table flex-justify-between border-bottom' }, + div( + { class: 'flex-wrapper' }, + div( + { class: 'bundle-image-container' }, + img({ src: bundle?.image, title: bundle?.title, class: 'bundle-image' }, bundle?.title), + ), + div( + { class: 'description' }, + span({ class: 'bundle-p-title' }, bundle?.title), + div( + { class: 'sku-text' }, + p(bundle?.sku), + ), + ), + ), + div({ class: 'bundle-qty' }, bundle?.quantity), + ); + list.append(detailItem); + }); + } else { + tileWrapper.classList.add('border-bottom'); + tileWrapper.classList.remove('no-border'); + link.innerHTML = `Show Produt Details + + `; + list.innerHTML = ''; + } + } + render() { this.shadowRoot.innerHTML = ` -
+
@@ -236,9 +301,9 @@ export default class ProductTile extends HTMLElement {
${this.bundlepreviewJson()?.length > 0 ? ` - - ${this.showPartList ? 'Hide' : 'Show'} Product Details - + + Show Product Details + ` : ''}
@@ -246,31 +311,6 @@ export default class ProductTile extends HTMLElement {
` : ''}
- ${this.showPartList ? 'show' : 'hide'} - ${this.showPartList ? ` -
-
- Products - QTY -
-
- ${Object.entries(this.bundlepreviewJson()).map(([bundle]) => ` -
-
-
- -
-
- ${bundle?.title} -
-

${bundle?.sku}

-
-
-
-
- ${bundle?.quantity} -
-
- `).join('')}` : ''}`; +
`; } } diff --git a/scripts/toast.js b/scripts/toast.js index 45cbc6d89..c892bd99e 100644 --- a/scripts/toast.js +++ b/scripts/toast.js @@ -28,7 +28,7 @@ export default async function getToast(toastId, addedProduct, addEventListeners) ), ), div( - { class: 'flex text-white rounded-r bg-danaherorange-600 goto-quotecart' }, + { class: 'flex text-white rounded-r bg-danaherpurple-500 goto-quotecart' }, div( { class: 'p-4 my-auto' }, button({ class: 'text-sm font-medium', name: 'close', type: 'button' }, 'View'), diff --git a/styles/styles.css b/styles/styles.css index 2f49b428f..e7bd9ca52 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -3941,11 +3941,6 @@ main .default-content-wrapper ul { background-color: rgb(220 96 22 / var(--tw-bg-opacity)); } -.bg-danaherorange-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 96 22 / var(--tw-bg-opacity)); -} - .bg-danaherpurple-25 { --tw-bg-opacity: 1; background-color: rgb(245 239 255 / var(--tw-bg-opacity)); From ba8618b4f3abf3730b47908730487b8199d890a3 Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 10 Jan 2024 21:41:43 +0530 Subject: [PATCH 08/12] updated quote --- blocks/product-children/product-tile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blocks/product-children/product-tile.js b/blocks/product-children/product-tile.js index 013521404..a9a317c64 100644 --- a/blocks/product-children/product-tile.js +++ b/blocks/product-children/product-tile.js @@ -132,8 +132,8 @@ export default class ProductTile extends HTMLElement { }), }); this.quote = quote; - if (this.quote.status === 200) { - const responseJson = await this.quote.json(); + if (quote.status === 200) { + const responseJson = await quote.json(); const addedProduct = responseJson?.items?.slice(-1)?.at(0); const { default: getToast } = await import('../../scripts/toast.js'); await getToast('quote-toast', addedProduct); From 42ce301e309d387c9372943cc461d4851dd4e3ed Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 17 Jan 2024 19:59:24 +0530 Subject: [PATCH 09/12] updated for review comments --- blocks/category-family/category-family.js | 3 +- blocks/product-resources/product-resources.js | 2 - scripts/scripts.js | 89 +++++++++++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/blocks/category-family/category-family.js b/blocks/category-family/category-family.js index 7fc6023d2..66b281518 100644 --- a/blocks/category-family/category-family.js +++ b/blocks/category-family/category-family.js @@ -1,5 +1,5 @@ /* eslint-disable import/no-unresolved */ -import { getMetadata, loadScript } from '../../scripts/lib-franklin.js'; +import { getMetadata } from '../../scripts/lib-franklin.js'; import { getCookie, isOTEnabled } from '../../scripts/scripts.js'; const categoryFamily = ` @@ -159,7 +159,6 @@ export default async function decorate(block) { block.innerHTML = categoryFamily; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); - loadScript('/blocks/category-family/image-component.js'); const categorySearchInterface = document.querySelector('atomic-search-interface.category-search'); diff --git a/blocks/product-resources/product-resources.js b/blocks/product-resources/product-resources.js index ad4bd4a97..89b194207 100644 --- a/blocks/product-resources/product-resources.js +++ b/blocks/product-resources/product-resources.js @@ -1,5 +1,4 @@ /* eslint-disable import/no-unresolved */ -import { loadScript } from '../../scripts/lib-franklin.js'; import { getCookie, isOTEnabled, getProductResponse, getSKU, } from '../../scripts/scripts.js'; @@ -166,7 +165,6 @@ export default async function decorate(block) { block.innerHTML = productResources; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); - loadScript('/blocks/category-family/image-component.js'); const resourceSearchInterface = document.querySelector('atomic-search-interface.resource-search'); diff --git a/scripts/scripts.js b/scripts/scripts.js index b52303323..e4bfa4faf 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -580,3 +580,92 @@ window.dataLayer.push({ // Datalayer Init - End loadPage(); + +class CustomImage extends HTMLElement { + shadow; + + result; + + initialized = false; + + get field() { + return this.getAttribute('field'); + } + + // eslint-disable-next-line class-methods-use-this + createOptimizedPicture( + src, + alt = '', + eager = false, + breakpoints = [{ media: '(min-width: 600px)', width: '300' }, { width: '300' }], + ) { + const url = new URL(src); + + const picture = document.createElement('picture'); + // webp + breakpoints.forEach((br) => { + const source = document.createElement('source'); + if (br.media) source.setAttribute('media', br.media); + source.setAttribute('type', 'image/webp'); + source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&fmt=webp&wid=${br.width}`); + picture.appendChild(source); + }); + + // fallback + breakpoints.forEach((br, i) => { + if (i < breakpoints.length - 1) { + const source = document.createElement('source'); + if (br.media) source.setAttribute('media', br.media); + source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); + picture.appendChild(source); + } else { + const productImage = document.createElement('img'); + productImage.setAttribute('loading', eager ? 'eager' : 'lazy'); + productImage.setAttribute('alt', alt); + picture.appendChild(productImage); + productImage.setAttribute('src', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); + } + }); + + return picture; + } + + async connectedCallback() { + if (this.initialized) { + return; + } + + this.initialized = true; + this.shadow = this.attachShadow({ mode: 'closed' }); + + try { + const { resultContext } = await import( + // eslint-disable-next-line import/no-unresolved + 'https://static.cloud.coveo.com/atomic/v2/index.esm.js' + ); + this.result = await resultContext(this); + this.render(); + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + } + } + + render() { + const value = this.result.raw[this.field]; + const image = Array.isArray(value) ? value[0] : value; + + this.shadow.innerHTML = ` + `; + + this.shadow.append(this.createOptimizedPicture(image, this.result.title)); + } +} + +customElements.define('custom-image', CustomImage); From 61ff3c9e92e9dbaf7ab1fc26d994846792855b59 Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 17 Jan 2024 20:05:58 +0530 Subject: [PATCH 10/12] removed image component --- blocks/category-family/image-component.js | 88 ----------------------- styles/styles.css | 19 ----- 2 files changed, 107 deletions(-) delete mode 100644 blocks/category-family/image-component.js diff --git a/blocks/category-family/image-component.js b/blocks/category-family/image-component.js deleted file mode 100644 index 459e466a6..000000000 --- a/blocks/category-family/image-component.js +++ /dev/null @@ -1,88 +0,0 @@ -class CustomImage extends HTMLElement { - shadow; - - result; - - initialized = false; - - get field() { - return this.getAttribute('field'); - } - - // eslint-disable-next-line class-methods-use-this - createOptimizedPicture( - src, - alt = '', - eager = false, - breakpoints = [{ media: '(min-width: 600px)', width: '300' }, { width: '300' }], - ) { - const url = new URL(src); - - const picture = document.createElement('picture'); - // webp - breakpoints.forEach((br) => { - const source = document.createElement('source'); - if (br.media) source.setAttribute('media', br.media); - source.setAttribute('type', 'image/webp'); - source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&fmt=webp&wid=${br.width}`); - picture.appendChild(source); - }); - - // fallback - breakpoints.forEach((br, i) => { - if (i < breakpoints.length - 1) { - const source = document.createElement('source'); - if (br.media) source.setAttribute('media', br.media); - source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); - picture.appendChild(source); - } else { - const img = document.createElement('img'); - img.setAttribute('loading', eager ? 'eager' : 'lazy'); - img.setAttribute('alt', alt); - picture.appendChild(img); - img.setAttribute('src', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); - } - }); - - return picture; - } - - async connectedCallback() { - if (this.initialized) { - return; - } - - this.initialized = true; - this.shadow = this.attachShadow({ mode: 'closed' }); - - try { - const { resultContext } = await import( - // eslint-disable-next-line import/no-unresolved - 'https://static.cloud.coveo.com/atomic/v2/index.esm.js' - ); - this.result = await resultContext(this); - this.render(); - } catch (error) { - // eslint-disable-next-line no-console - console.error(error); - } - } - - render() { - const value = this.result.raw[this.field]; - const image = Array.isArray(value) ? value[0] : value; - - this.shadow.innerHTML = ` - `; - - this.shadow.append(this.createOptimizedPicture(image, this.result.title)); - } -} - -customElements.define('custom-image', CustomImage); diff --git a/styles/styles.css b/styles/styles.css index 230eeee23..3fff05eb1 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -1483,25 +1483,6 @@ button.suggestion.selected { transition-duration: 700ms; } -.productdetail main .columns.columns-2-cols .product-hero .vertical-gallery-container > div div:nth-child(1) img { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - font-size: 1rem; - line-height: 1.5rem; - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.columns.features-card-left > div > div.product-hero .vertical-gallery-container > div div:nth-child(1) img > .card { - display: flex; - flex-direction: row; - padding-bottom: 1.5rem; -} - -.columns.features-card-left > div > div.product-hero .vertical-gallery-container > div div:nth-child(1) img > div.card > .left-content { - padding-right: 0.75rem; -} - .product-hero .vertical-gallery-container > div > div:not(:nth-child(1)) { grid-column: span 1 / span 1; display: flex; From 8215d365ebf56f35bfc7018ff655fdb0b5bcaccb Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 17 Jan 2024 20:31:09 +0530 Subject: [PATCH 11/12] moved image component to script folder --- blocks/category-family/category-family.js | 3 +- blocks/product-children/product-children.js | 2 +- blocks/product-resources/product-resources.js | 2 + scripts/image-component.js | 88 ++++++++++++++++++ scripts/scripts.js | 89 ------------------- 5 files changed, 93 insertions(+), 91 deletions(-) create mode 100644 scripts/image-component.js diff --git a/blocks/category-family/category-family.js b/blocks/category-family/category-family.js index 66b281518..20bb383e3 100644 --- a/blocks/category-family/category-family.js +++ b/blocks/category-family/category-family.js @@ -1,5 +1,5 @@ /* eslint-disable import/no-unresolved */ -import { getMetadata } from '../../scripts/lib-franklin.js'; +import { getMetadata, loadScript } from '../../scripts/lib-franklin.js'; import { getCookie, isOTEnabled } from '../../scripts/scripts.js'; const categoryFamily = ` @@ -159,6 +159,7 @@ export default async function decorate(block) { block.innerHTML = categoryFamily; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); + loadScript('../../scripts/image-component.js'); const categorySearchInterface = document.querySelector('atomic-search-interface.category-search'); diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index c4929d2ae..2a2a2d419 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -80,7 +80,7 @@ export default async function decorate(block) { block.innerHTML = childProducts; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); - loadScript('/blocks/category-family/image-component.js'); + loadScript('../../scripts/image-component.js'); const productSearchInterface = document.querySelector('atomic-search-interface.product-search'); diff --git a/blocks/product-resources/product-resources.js b/blocks/product-resources/product-resources.js index 89b194207..b1d51034d 100644 --- a/blocks/product-resources/product-resources.js +++ b/blocks/product-resources/product-resources.js @@ -1,4 +1,5 @@ /* eslint-disable import/no-unresolved */ +import { loadScript } from '../../scripts/lib-franklin.js'; import { getCookie, isOTEnabled, getProductResponse, getSKU, } from '../../scripts/scripts.js'; @@ -165,6 +166,7 @@ export default async function decorate(block) { block.innerHTML = productResources; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); + loadScript('../../scripts/image-component.js'); const resourceSearchInterface = document.querySelector('atomic-search-interface.resource-search'); diff --git a/scripts/image-component.js b/scripts/image-component.js new file mode 100644 index 000000000..6d6ef559c --- /dev/null +++ b/scripts/image-component.js @@ -0,0 +1,88 @@ +class CustomImage extends HTMLElement { + shadow; + + result; + + initialized = false; + + get field() { + return this.getAttribute('field'); + } + + // eslint-disable-next-line class-methods-use-this + createOptimizedPicture( + src, + alt = '', + eager = false, + breakpoints = [{ media: '(min-width: 600px)', width: '300' }, { width: '300' }], + ) { + const url = new URL(src); + + const picture = document.createElement('picture'); + // webp + breakpoints.forEach((br) => { + const source = document.createElement('source'); + if (br.media) source.setAttribute('media', br.media); + source.setAttribute('type', 'image/webp'); + source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&fmt=webp&wid=${br.width}`); + picture.appendChild(source); + }); + + // fallback + breakpoints.forEach((br, i) => { + if (i < breakpoints.length - 1) { + const source = document.createElement('source'); + if (br.media) source.setAttribute('media', br.media); + source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); + picture.appendChild(source); + } else { + const productImage = document.createElement('img'); + productImage.setAttribute('loading', eager ? 'eager' : 'lazy'); + productImage.setAttribute('alt', alt); + picture.appendChild(productImage); + productImage.setAttribute('src', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); + } + }); + + return picture; + } + + async connectedCallback() { + if (this.initialized) { + return; + } + + this.initialized = true; + this.shadow = this.attachShadow({ mode: 'closed' }); + + try { + const { resultContext } = await import( + // eslint-disable-next-line import/no-unresolved + 'https://static.cloud.coveo.com/atomic/v2/index.esm.js' + ); + this.result = await resultContext(this); + this.render(); + } catch (error) { + // eslint-disable-next-line no-console + console.error(error); + } + } + + render() { + const value = this.result.raw[this.field]; + const image = Array.isArray(value) ? value[0] : value; + + this.shadow.innerHTML = ` + `; + + this.shadow.append(this.createOptimizedPicture(image, this.result.title)); + } +} + +customElements.define('custom-image', CustomImage); diff --git a/scripts/scripts.js b/scripts/scripts.js index 5e6788050..865f37b76 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -675,92 +675,3 @@ window.dataLayer.push({ // Datalayer Init - End loadPage(); - -class CustomImage extends HTMLElement { - shadow; - - result; - - initialized = false; - - get field() { - return this.getAttribute('field'); - } - - // eslint-disable-next-line class-methods-use-this - createOptimizedPicture( - src, - alt = '', - eager = false, - breakpoints = [{ media: '(min-width: 600px)', width: '300' }, { width: '300' }], - ) { - const url = new URL(src); - - const picture = document.createElement('picture'); - // webp - breakpoints.forEach((br) => { - const source = document.createElement('source'); - if (br.media) source.setAttribute('media', br.media); - source.setAttribute('type', 'image/webp'); - source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&fmt=webp&wid=${br.width}`); - picture.appendChild(source); - }); - - // fallback - breakpoints.forEach((br, i) => { - if (i < breakpoints.length - 1) { - const source = document.createElement('source'); - if (br.media) source.setAttribute('media', br.media); - source.setAttribute('srcset', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); - picture.appendChild(source); - } else { - const productImage = document.createElement('img'); - productImage.setAttribute('loading', eager ? 'eager' : 'lazy'); - productImage.setAttribute('alt', alt); - picture.appendChild(productImage); - productImage.setAttribute('src', `${url.toString()}?$danaher-mobile$&wid=${br.width}`); - } - }); - - return picture; - } - - async connectedCallback() { - if (this.initialized) { - return; - } - - this.initialized = true; - this.shadow = this.attachShadow({ mode: 'closed' }); - - try { - const { resultContext } = await import( - // eslint-disable-next-line import/no-unresolved - 'https://static.cloud.coveo.com/atomic/v2/index.esm.js' - ); - this.result = await resultContext(this); - this.render(); - } catch (error) { - // eslint-disable-next-line no-console - console.error(error); - } - } - - render() { - const value = this.result.raw[this.field]; - const image = Array.isArray(value) ? value[0] : value; - - this.shadow.innerHTML = ` - `; - - this.shadow.append(this.createOptimizedPicture(image, this.result.title)); - } -} - -customElements.define('custom-image', CustomImage); From 015d163e8178cda696b873b223486c71ff391733 Mon Sep 17 00:00:00 2001 From: rgravitvl Date: Wed, 17 Jan 2024 20:36:07 +0530 Subject: [PATCH 12/12] updated image component reference --- blocks/category-family/category-family.js | 2 +- blocks/product-children/product-children.js | 2 +- blocks/product-resources/product-resources.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/blocks/category-family/category-family.js b/blocks/category-family/category-family.js index 20bb383e3..e1843970d 100644 --- a/blocks/category-family/category-family.js +++ b/blocks/category-family/category-family.js @@ -159,7 +159,7 @@ export default async function decorate(block) { block.innerHTML = categoryFamily; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); - loadScript('../../scripts/image-component.js'); + loadScript('/../../scripts/image-component.js'); const categorySearchInterface = document.querySelector('atomic-search-interface.category-search'); diff --git a/blocks/product-children/product-children.js b/blocks/product-children/product-children.js index 2a2a2d419..aaa32c041 100644 --- a/blocks/product-children/product-children.js +++ b/blocks/product-children/product-children.js @@ -80,7 +80,7 @@ export default async function decorate(block) { block.innerHTML = childProducts; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); - loadScript('../../scripts/image-component.js'); + loadScript('/../../scripts/image-component.js'); const productSearchInterface = document.querySelector('atomic-search-interface.product-search'); diff --git a/blocks/product-resources/product-resources.js b/blocks/product-resources/product-resources.js index b1d51034d..fd9b04268 100644 --- a/blocks/product-resources/product-resources.js +++ b/blocks/product-resources/product-resources.js @@ -166,7 +166,7 @@ export default async function decorate(block) { block.innerHTML = productResources; await import('https://static.cloud.coveo.com/atomic/v2/atomic.esm.js'); await customElements.whenDefined('atomic-search-interface'); - loadScript('../../scripts/image-component.js'); + loadScript('/../../scripts/image-component.js'); const resourceSearchInterface = document.querySelector('atomic-search-interface.resource-search');