Skip to content

Commit

Permalink
added three-in-one modal
Browse files Browse the repository at this point in the history
  • Loading branch information
mirafedas committed Jan 28, 2025
1 parent 0a9e222 commit b4bf8e9
Show file tree
Hide file tree
Showing 26 changed files with 647 additions and 322 deletions.
18 changes: 18 additions & 0 deletions libs/blocks/merch/merch.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ a[is='checkout-link'].con-button > span {
content: "\00a0";
}

.three-in-one {
display: flex;
height: 100%;
}

.three-in-one .loading iframe {
visibility: hidden;
}

.three-in-one sp-theme {
width: max-content;
height: max-content;
left: 50%;
position: relative;
top: 50%;
transform: translate(-50%,-50%);
}

@media (max-width: 1199px) {
#checkout-link-modal {
height: 100vh;
Expand Down
21 changes: 18 additions & 3 deletions libs/blocks/merch/merch.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ const GeoMap = {
th_th: 'TH_th',
};

export const MODAL_TYPE_3_IN_1 = {
TWP: 'twp',
D2P: 'd2p',
CRM: 'crm',
};

export function getMiloLocaleSettings(locale) {
const localePrefix = locale?.prefix || 'US_en';
const geo = localePrefix.replace('/', '') ?? '';
Expand Down Expand Up @@ -478,7 +484,7 @@ async function openExternalModal(url, getModal, extraOptions) {

const isInternalModal = (url) => /\/fragments\//.test(url);

export async function openModal(e, url, offerType, hash, extraOptions) {
export async function openModal(e, url, offerType, hash, extraOptions, el) {
e.preventDefault();
e.stopImmediatePropagation();
const { getModal } = await import('../modal/modal.js');
Expand All @@ -496,7 +502,13 @@ export async function openModal(e, url, offerType, hash, extraOptions) {
const fragmentPath = url.split(/(hlx|aem).(page|live)/).pop();
modal = await openFragmentModal(fragmentPath, getModal);
} else {
modal = await openExternalModal(url, getModal, extraOptions);
const isThreeInOneModal = [MODAL_TYPE_3_IN_1.CRM, MODAL_TYPE_3_IN_1.D2P, MODAL_TYPE_3_IN_1.TWP].includes(el?.getAttribute('data-modal-type')) && el?.href;
if (isThreeInOneModal) {
const { default: openThreeInOneModal } = await import('./threeInOne.js');
modal = await openThreeInOneModal(el);

Check warning on line 508 in libs/blocks/merch/merch.js

View check run for this annotation

Codecov / codecov/patch

libs/blocks/merch/merch.js#L507-L508

Added lines #L507 - L508 were not covered by tests
} else {
modal = await openExternalModal(url, getModal, extraOptions, el);
}
}
if (modal) {
modal.classList.add(offerTypeClass);
Expand Down Expand Up @@ -539,7 +551,10 @@ export async function getModalAction(offers, options, el) {
if (!url) return undefined;
url = isInternalModal(url) || isProdModal(url)
? localizeLink(checkoutLinkConfig[columnName]) : checkoutLinkConfig[columnName];
return { url, handler: (e) => openModal(e, url, offerType, hash, options.extraOptions) };
return {
url,
handler: (e) => openModal(e, url, offerType, hash, options.extraOptions, el),
};
}

export async function getCheckoutAction(offers, options, imsSignedInPromise, el) {
Expand Down
98 changes: 98 additions & 0 deletions libs/blocks/merch/threeInOne.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { createTag, getConfig } from '../../utils/utils.js';

const MSG_SUBTYPE = {
AppLoaded: 'AppLoaded',
EXTERNAL: 'EXTERNAL',
SWITCH: 'SWITCH',
RETURN_BACK: 'RETURN_BACK',
OrderComplete: 'OrderComplete',
Error: 'Error',
Close: 'Close',
};

export const LANA_OPTIONS = {
clientId: 'merch-at-scale',
sampleRate: 10,
tags: 'three-in-one',
};

const handle3in1IFrameEvents = ({ data: msgData }) => {
let parsedMsg = null;
try {
parsedMsg = JSON.parse(msgData);
} catch (error) {
return;
}
const { app, subType, data } = parsedMsg || {};
if (app !== 'ucv3') return;
window.lana?.log(`3-in-1 modal: ${subType}`, LANA_OPTIONS);
switch (subType) {
case MSG_SUBTYPE.AppLoaded:
document.querySelector('.three-in-one iframe')?.classList?.remove('loading');
document.querySelector('.three-in-one sp-theme')?.remove();
break;
case MSG_SUBTYPE.EXTERNAL:
if (!data?.externalUrl || !data.target) return;
window.open(data.externalUrl, data.target);

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.
break;
case MSG_SUBTYPE.SWITCH:
if (!data?.externalUrl || !data.target) return;
window.open(data.externalUrl, data.target);

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.
break;
case MSG_SUBTYPE.RETURN_BACK:
if (!data?.externalUrl || !data.target) return;
window.open(data.externalUrl, data.target);

Check warning

Code scanning / CodeQL

Client-side URL redirect Medium

Untrusted URL redirection depends on a
user-provided value
.
break;
case MSG_SUBTYPE.OrderComplete:
break;
case MSG_SUBTYPE.Error:
break;
case MSG_SUBTYPE.Close:
document.querySelector('.dialog-modal.three-in-one')?.dispatchEvent(new Event('closeModal'));
break;
default:
break;
}
};

async function createContent(iframeUrl) {
const { base } = getConfig();
await Promise.all([
import(`${base}/features/spectrum-web-components/dist/theme.js`),
import(`${base}/features/spectrum-web-components/dist/progress-circle.js`),
]);
const content = createTag('div', { class: 'milo-iframe' });
const iframe = createTag('iframe', {
src: iframeUrl,
title: 'Three-in-one modal',
frameborder: '0',
marginwidth: '0',
marginheight: '0',
allowfullscreen: 'true',
loading: 'lazy',
class: 'loading',
});
const pCircle = createTag('sp-progress-circle', { label: 'progress circle', indeterminate: true, size: 'l' });
const theme = createTag('sp-theme', { theme: 'spectrum', color: 'light', scale: 'medium', dir: 'ltr' });
theme.append(pCircle);
content.append(theme);
content.append(iframe);
return content;
}

export default async function openThreeInOneModal(el) {
const iframeUrl = el?.href;
const modalType = el?.getAttribute('data-modal-type');
if (!modalType || !iframeUrl) return undefined;

window.addEventListener('message', handle3in1IFrameEvents);

const { getModal } = await import('../modal/modal.js');
const content = await createContent(iframeUrl);
return getModal(null, {
id: 'three-in-one',
content,
closeEvent: 'closeModal',
class: 'three-in-one',
});
}
30 changes: 30 additions & 0 deletions libs/blocks/modal/modal.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@
z-index: 102;
}

.dialog-modal.three-in-one {
height: 100%;
width: 100%;
max-height: 100%;
max-width: 100%;
overflow: hidden;
}

.three-in-one .dialog-close {
display: none;
}

.three-in-one .milo-iframe {
overflow: hidden;
height: 100%;
width: 100%;
box-sizing: border-box;
}

.three-in-one iframe {
width: 100%;
}

#locale-modal-v2 .dialog-close,
#locale-modal-v2 .georouting-wrapper {
display: block;
Expand Down Expand Up @@ -359,6 +382,13 @@
width: 80%;
}

.dialog-modal.three-in-one {
height: 820px;
width: 80%;
max-width: 1100px;
overflow: hidden;
}

.dialog-modal.tall-video,
.dialog-modal.tall-video .milo-video {
--modal-width-var: 35vw;
Expand Down
4 changes: 2 additions & 2 deletions libs/deps/mas/commerce.js

Large diffs are not rendered by default.

110 changes: 55 additions & 55 deletions libs/deps/mas/mas.js

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions libs/deps/mas/merch-card-collection.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var N=Object.defineProperty;var y=(s,e,t)=>e in s?N(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var E=(s,e,t)=>y(s,typeof e!="symbol"?e+"":e,t);import{html as c,LitElement as O}from"../lit-all.min.js";var f=class{constructor(e,t){this.key=Symbol("match-media-key"),this.matches=!1,this.host=e,this.host.addController(this),this.media=window.matchMedia(t),this.matches=this.media.matches,this.onChange=this.onChange.bind(this),e.addController(this)}hostConnected(){var e;(e=this.media)==null||e.addEventListener("change",this.onChange)}hostDisconnected(){var e;(e=this.media)==null||e.removeEventListener("change",this.onChange)}onChange(e){this.matches!==e.matches&&(this.matches=e.matches,this.host.requestUpdate(this.key,!this.matches))}};var T="hashchange";function L(s=window.location.hash){let e=[],t=s.replace(/^#/,"").split("&");for(let r of t){let[n,i=""]=r.split("=");n&&e.push([n,decodeURIComponent(i.replace(/\+/g," "))])}return Object.fromEntries(e)}function d(s){let e=new URLSearchParams(window.location.hash.slice(1));Object.entries(s).forEach(([n,i])=>{i?e.set(n,i):e.delete(n)}),e.sort();let t=e.toString();if(t===window.location.hash)return;let r=window.scrollY||document.documentElement.scrollTop;window.location.hash=t,window.scrollTo(0,r)}function x(s){let e=()=>{if(window.location.hash&&!window.location.hash.includes("="))return;let t=L(window.location.hash);s(t)};return e(),window.addEventListener(T,e),()=>{window.removeEventListener(T,e)}}var S="merch-card-collection:sort",g="merch-card-collection:showmore";var A="(max-width: 1199px)",R="(min-width: 768px)",C="(min-width: 1200px)";import{css as M,unsafeCSS as w}from"../lit-all.min.js";var b=M`
var M=Object.defineProperty;var b=(s,e,t)=>e in s?M(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var E=(s,e,t)=>(b(s,typeof e!="symbol"?e+"":e,t),t);import{html as c,LitElement as L}from"../lit-all.min.js";var T=class{constructor(e,t){this.key=Symbol("match-media-key"),this.matches=!1,this.host=e,this.host.addController(this),this.media=window.matchMedia(t),this.matches=this.media.matches,this.onChange=this.onChange.bind(this),e.addController(this)}hostConnected(){var e;(e=this.media)==null||e.addEventListener("change",this.onChange)}hostDisconnected(){var e;(e=this.media)==null||e.removeEventListener("change",this.onChange)}onChange(e){this.matches!==e.matches&&(this.matches=e.matches,this.host.requestUpdate(this.key,!this.matches))}};var f="hashchange";function O(s=window.location.hash){let e=[],t=s.replace(/^#/,"").split("&");for(let r of t){let[n,i=""]=r.split("=");n&&e.push([n,decodeURIComponent(i.replace(/\+/g," "))])}return Object.fromEntries(e)}function d(s){let e=new URLSearchParams(window.location.hash.slice(1));Object.entries(s).forEach(([n,i])=>{i?e.set(n,i):e.delete(n)}),e.sort();let t=e.toString();if(t===window.location.hash)return;let r=window.scrollY||document.documentElement.scrollTop;window.location.hash=t,window.scrollTo(0,r)}function x(s){let e=()=>{if(window.location.hash&&!window.location.hash.includes("="))return;let t=O(window.location.hash);s(t)};return e(),window.addEventListener(f,e),()=>{window.removeEventListener(f,e)}}var A="merch-card-collection:sort",C="merch-card-collection:showmore";var R="(max-width: 1199px)",g="(min-width: 768px)",S="(min-width: 1200px)";import{css as y,unsafeCSS as N}from"../lit-all.min.js";var w=y`
#header,
#resultText,
#footer {
Expand Down Expand Up @@ -65,7 +65,7 @@ var N=Object.defineProperty;var y=(s,e,t)=>e in s?N(s,e,{enumerable:!0,configura
}
/* tablets */
@media screen and ${w(R)} {
@media screen and ${N(g)} {
#header {
grid-template-columns: 1fr fit-content(100%) fit-content(100%);
}
Expand All @@ -84,7 +84,7 @@ var N=Object.defineProperty;var y=(s,e,t)=>e in s?N(s,e,{enumerable:!0,configura
}
/* Laptop */
@media screen and ${w(C)} {
@media screen and ${N(S)} {
#resultText {
grid-column: span 2;
order: -3;
Expand All @@ -96,9 +96,9 @@ var N=Object.defineProperty;var y=(s,e,t)=>e in s?N(s,e,{enumerable:!0,configura
justify-content: end;
}
}
`;var u=(s,e)=>s.querySelector(`[slot="${e}"]`)?.textContent?.trim();var D="merch-card-collection",a={alphabetical:"alphabetical",authored:"authored"},v={filters:["noResultText","resultText","resultsText"],mobile:["noSearchResultsMobileText","searchResultMobileText","searchResultsMobileText"],desktop:["noSearchResultsText","searchResultText","searchResultsText"]},P=(s,e={})=>{s.querySelectorAll("span[data-placeholder]").forEach(t=>{let{placeholder:r}=t.dataset;t.innerText=e[r]??""})},B=(s,{filter:e})=>s.filter(t=>t.filters.hasOwnProperty(e)),H=(s,{types:e})=>e?(e=e.split(","),s.filter(t=>e.some(r=>t.types.includes(r)))):s,V=s=>s.sort((e,t)=>(e.title??"").localeCompare(t.title??"","en",{sensitivity:"base"})),I=(s,{filter:e})=>s.sort((t,r)=>r.filters[e]?.order==null||isNaN(r.filters[e]?.order)?-1:t.filters[e]?.order==null||isNaN(t.filters[e]?.order)?1:t.filters[e].order-r.filters[e].order),k=(s,{search:e})=>e?.length?(e=e.toLowerCase(),s.filter(t=>(t.title??"").toLowerCase().includes(e))):s,h=class extends O{constructor(){super();E(this,"mobileAndTablet",new f(this,A));this.filter="all",this.hasMore=!1,this.resultCount=void 0,this.displayResult=!1}render(){return c`${this.header}
`;var m=(s,e)=>s.querySelector(`[slot="${e}"]`)?.textContent?.trim();var D="merch-card-collection",a={alphabetical:"alphabetical",authored:"authored"},v={filters:["noResultText","resultText","resultsText"],mobile:["noSearchResultsMobileText","searchResultMobileText","searchResultsMobileText"],desktop:["noSearchResultsText","searchResultText","searchResultsText"]},P=(s,e={})=>{s.querySelectorAll("span[data-placeholder]").forEach(t=>{let{placeholder:r}=t.dataset;t.innerText=e[r]??""})},I=(s,{filter:e})=>s.filter(t=>t.filters.hasOwnProperty(e)),H=(s,{types:e})=>e?(e=e.split(","),s.filter(t=>e.some(r=>t.types.includes(r)))):s,B=s=>s.sort((e,t)=>(e.title??"").localeCompare(t.title??"","en",{sensitivity:"base"})),V=(s,{filter:e})=>s.sort((t,r)=>r.filters[e]?.order==null||isNaN(r.filters[e]?.order)?-1:t.filters[e]?.order==null||isNaN(t.filters[e]?.order)?1:t.filters[e].order-r.filters[e].order),k=(s,{search:e})=>e?.length?(e=e.toLowerCase(),s.filter(t=>(t.title??"").toLowerCase().includes(e))):s,h=class extends L{constructor(){super();E(this,"mobileAndTablet",new T(this,R));this.filter="all",this.hasMore=!1,this.resultCount=void 0,this.displayResult=!1}render(){return c`${this.header}
<slot></slot>
${this.footer}`}updated(t){if(!this.querySelector("merch-card"))return;let r=window.scrollY||document.documentElement.scrollTop,n=[...this.children].filter(o=>o.tagName==="MERCH-CARD");if(n.length===0)return;t.has("singleApp")&&this.singleApp&&n.forEach(o=>{o.updateFilters(o.name===this.singleApp)});let i=this.sort===a.alphabetical?V:I,l=[B,H,k,i].reduce((o,p)=>p(o,this),n).map((o,p)=>[o,p]);if(this.resultCount=l.length,this.page&&this.limit){let o=this.page*this.limit;this.hasMore=l.length>o,l=l.filter(([,p])=>p<o)}let m=new Map(l.reverse());for(let o of m.keys())this.prepend(o);n.forEach(o=>{m.has(o)?(o.size=o.filters[this.filter]?.size,o.style.removeProperty("display"),o.requestUpdate()):(o.style.display="none",o.size=void 0)}),window.scrollTo(0,r),this.updateComplete.then(()=>{let o=this.shadowRoot.getElementById("resultText")?.firstElementChild?.assignedElements?.()?.[0];o&&P(o,{resultCount:this.resultCount,searchTerm:this.search,filter:this.sidenav?.filters.selectedText})})}connectedCallback(){super.connectedCallback(),this.filtered?(this.filter=this.filtered,this.page=1):this.startDeeplink(),this.sidenav=document.querySelector("merch-sidenav")}disconnectedCallback(){super.disconnectedCallback(),this.stopDeeplink?.()}get header(){if(!this.filtered)return c`<div id="header">
${this.footer}`}updated(t){if(!this.querySelector("merch-card"))return;let r=window.scrollY||document.documentElement.scrollTop,n=[...this.children].filter(o=>o.tagName==="MERCH-CARD");if(n.length===0)return;t.has("singleApp")&&this.singleApp&&n.forEach(o=>{o.updateFilters(o.name===this.singleApp)});let i=this.sort===a.alphabetical?B:V,l=[I,H,k,i].reduce((o,p)=>p(o,this),n).map((o,p)=>[o,p]);if(this.resultCount=l.length,this.page&&this.limit){let o=this.page*this.limit;this.hasMore=l.length>o,l=l.filter(([,p])=>p<o)}let u=new Map(l.reverse());for(let o of u.keys())this.prepend(o);n.forEach(o=>{u.has(o)?(o.size=o.filters[this.filter]?.size,o.style.removeProperty("display"),o.requestUpdate()):(o.style.display="none",o.size=void 0)}),window.scrollTo(0,r),this.updateComplete.then(()=>{let o=this.shadowRoot.getElementById("resultText")?.firstElementChild?.assignedElements?.()?.[0];o&&P(o,{resultCount:this.resultCount,searchTerm:this.search,filter:this.sidenav?.filters.selectedText})})}connectedCallback(){super.connectedCallback(),this.filtered?(this.filter=this.filtered,this.page=1):this.startDeeplink(),this.sidenav=document.querySelector("merch-sidenav")}disconnectedCallback(){super.disconnectedCallback(),this.stopDeeplink?.()}get header(){if(!this.filtered)return c`<div id="header">
<sp-theme color="light" scale="medium">
${this.searchBar} ${this.filtersButton} ${this.sortButton}
</sp-theme>
Expand All @@ -122,13 +122,13 @@ var N=Object.defineProperty;var y=(s,e,t)=>e in s?N(s,e,{enumerable:!0,configura
treatment="outline"
@click="${this.openFilters}"
><slot name="filtersText"></slot
></sp-action-button>`:""}get searchBar(){let t=u(this,"searchText");return this.mobileAndTablet.matches?c`<merch-search deeplink="search">
></sp-action-button>`:""}get searchBar(){let t=m(this,"searchText");return this.mobileAndTablet.matches?c`<merch-search deeplink="search">
<sp-search
id="searchBar"
@submit="${this.searchSubmit}"
placeholder="${t}"
></sp-search>
</merch-search>`:""}get sortButton(){let t=u(this,"sortText"),r=u(this,"popularityText"),n=u(this,"alphabeticallyText");if(!(t&&r&&n))return;let i=this.sort===a.alphabetical;return c`
</merch-search>`:""}get sortButton(){let t=m(this,"sortText"),r=m(this,"popularityText"),n=m(this,"alphabeticallyText");if(!(t&&r&&n))return;let i=this.sort===a.alphabetical;return c`
<sp-action-menu
id="sortButton"
size="m"
Expand All @@ -147,4 +147,4 @@ var N=Object.defineProperty;var y=(s,e,t)=>e in s?N(s,e,{enumerable:!0,configura
>${n}</sp-menu-item
>
</sp-action-menu>
`}sortChanged(t){t.target.value===a.authored?d({sort:void 0}):d({sort:t.target.value}),this.dispatchEvent(new CustomEvent(S,{bubbles:!0,composed:!0,detail:{value:t.target.value}}))}async showMore(){this.dispatchEvent(new CustomEvent(g,{bubbles:!0,composed:!0}));let t=this.page+1;d({page:t}),this.page=t,await this.updateComplete}startDeeplink(){this.stopDeeplink=x(({category:t,filter:r,types:n,sort:i,search:_,single_app:l,page:m})=>{r=r||t,!this.filtered&&r&&r!==this.filter&&setTimeout(()=>{d({page:void 0}),this.page=1},1),this.filtered||(this.filter=r??this.filter),this.types=n??"",this.search=_??"",this.singleApp=l,this.sort=i,this.page=Number(m)||1})}openFilters(t){this.sidenav?.showModal(t)}};E(h,"properties",{filter:{type:String,attribute:"filter",reflect:!0},filtered:{type:String,attribute:"filtered"},search:{type:String,attribute:"search",reflect:!0},sort:{type:String,attribute:"sort",default:a.authored,reflect:!0},types:{type:String,attribute:"types",reflect:!0},limit:{type:Number,attribute:"limit"},page:{type:Number,attribute:"page",reflect:!0},singleApp:{type:String,attribute:"single-app",reflect:!0},hasMore:{type:Boolean},displayResult:{type:Boolean,attribute:"display-result"},resultCount:{type:Number},sidenav:{type:Object}}),E(h,"styles",[b]);h.SortOrder=a;customElements.define(D,h);export{h as MerchCardCollection,P as updateLiterals};
`}sortChanged(t){t.target.value===a.authored?d({sort:void 0}):d({sort:t.target.value}),this.dispatchEvent(new CustomEvent(A,{bubbles:!0,composed:!0,detail:{value:t.target.value}}))}async showMore(){this.dispatchEvent(new CustomEvent(C,{bubbles:!0,composed:!0}));let t=this.page+1;d({page:t}),this.page=t,await this.updateComplete}startDeeplink(){this.stopDeeplink=x(({category:t,filter:r,types:n,sort:i,search:_,single_app:l,page:u})=>{r=r||t,!this.filtered&&r&&r!==this.filter&&setTimeout(()=>{d({page:void 0}),this.page=1},1),this.filtered||(this.filter=r??this.filter),this.types=n??"",this.search=_??"",this.singleApp=l,this.sort=i,this.page=Number(u)||1})}openFilters(t){this.sidenav?.showModal(t)}};E(h,"properties",{filter:{type:String,attribute:"filter",reflect:!0},filtered:{type:String,attribute:"filtered"},search:{type:String,attribute:"search",reflect:!0},sort:{type:String,attribute:"sort",default:a.authored,reflect:!0},types:{type:String,attribute:"types",reflect:!0},limit:{type:Number,attribute:"limit"},page:{type:Number,attribute:"page",reflect:!0},singleApp:{type:String,attribute:"single-app",reflect:!0},hasMore:{type:Boolean},displayResult:{type:Boolean,attribute:"display-result"},resultCount:{type:Number},sidenav:{type:Object}}),E(h,"styles",[w]);h.SortOrder=a;customElements.define(D,h);export{h as MerchCardCollection,P as updateLiterals};
Loading

0 comments on commit b4bf8e9

Please sign in to comment.