diff --git a/.github/workflows/helpers.js b/.github/workflows/helpers.js index da3565c095..c086fe88d1 100644 --- a/.github/workflows/helpers.js +++ b/.github/workflows/helpers.js @@ -3,6 +3,60 @@ const owner = process.env.REPO_OWNER || ''; // example owner: adobecom const repo = process.env.REPO_NAME || ''; // example repo name: milo const auth = process.env.GH_TOKEN || ''; // https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens +const CURRENT_YEAR = 2024; +const RCPDates = [ + { + start: new Date('2024-05-26T00:00:00-07:00'), + end: new Date('2024-06-01T00:00:00-07:00'), + }, + { + start: new Date('2024-06-13T11:00:00-07:00'), + end: new Date('2024-06-13T14:00:00-07:00'), + }, + { + start: new Date('2024-06-30T00:00:00-07:00'), + end: new Date('2024-07-06T00:00:00-07:00'), + }, + { + start: new Date('2024-08-25T00:00:00-07:00'), + end: new Date('2024-08-31T00:00:00-07:00'), + }, + { + start: new Date('2024-09-12T11:00:00-07:00'), + end: new Date('2024-09-12T14:00:00-07:00'), + }, + { + start: new Date('2024-10-14T00:00:00-07:00'), + end: new Date('2024-11-18T17:00:00-08:00'), + }, + { + start: new Date('2024-11-17T00:00:00-08:00'), + end: new Date('2024-11-30T00:00:00-08:00'), + }, + { + start: new Date('2024-12-12T11:00:00-08:00'), + end: new Date('2024-12-12T14:00:00-08:00'), + }, + { + start: new Date('2024-12-15T00:00:00-08:00'), + end: new Date('2025-01-02T00:00:00-08:00'), + }, +]; + +const isWithinRCP = () => { + const now = new Date(); + if (now.getFullYear() !== CURRENT_YEAR) { + console.log(`ADD NEW RCPs for ${CURRENT_YEAR + 1}`); + return true; + } + + if (RCPDates.some(({ start, end }) => start <= now && now <= end)) { + console.log('Current date is within a RCP. Stopping execution.'); + return true; + } + + return false; +}; const getLocalConfigs = () => { if (!owner || !repo || !auth) { @@ -12,7 +66,12 @@ Then run: node --env-file=.env .github/workflows/update-ims.js`); const { Octokit } = require('@octokit/rest'); return { - github: { rest: new Octokit({ auth }) }, + github: { + rest: new Octokit({ auth }), + repos: { + createDispatchEvent: () => console.log('local mock createDispatch'), + }, + }, context: { repo: { owner, @@ -83,4 +142,5 @@ module.exports = { getLocalConfigs, slackNotification, pulls: { addLabels, addFiles, getChecks, getReviews }, + isWithinRCP, }; diff --git a/.github/workflows/high-impact-alert.js b/.github/workflows/high-impact-alert.js new file mode 100644 index 0000000000..9a5a5833fb --- /dev/null +++ b/.github/workflows/high-impact-alert.js @@ -0,0 +1,29 @@ +const { + slackNotification, + getLocalConfigs, +} = require('./helpers.js'); + +const main = async (params) => { + const { context } = params; + + try { + if (context.payload.label.name !== 'high-impact') { + console.log('No high impact label detected'); + return; + } + + const { html_url, number, title } = context.payload.pull_request; + console.log('High impact label detected, sending Slack notification'); + slackNotification(`:alert: High Impact PR has been opened: <${html_url}|#${number}: ${title}>.` + + ` Please prioritize testing the proposed changes.`, process.env.SLACK_HIGH_IMPACT_PR_WEBHOOK); + } catch (error) { + console.error(error); + } +}; + +if (process.env.LOCAL_RUN) { + const { context } = getLocalConfigs(); + main({ context }); +} + +module.exports = main; diff --git a/.github/workflows/high-impact-alert.yml b/.github/workflows/high-impact-alert.yml new file mode 100644 index 0000000000..bf198f5080 --- /dev/null +++ b/.github/workflows/high-impact-alert.yml @@ -0,0 +1,24 @@ +name: High Impact Alert + +on: + pull_request: + types: + - labeled + +env: + SLACK_HIGH_IMPACT_PR_WEBHOOK: ${{ secrets.SLACK_HIGH_IMPACT_PR_WEBHOOK }} + +jobs: + send_alert: + if: github.repository_owner == 'adobecom' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4.1.4 + + - name: Send Slack message for high impact PRs + uses: actions/github-script@v7.0.1 + with: + script: | + const main = require('./.github/workflows/high-impact-alert.js') + main({ github, context }) diff --git a/.github/workflows/mark-stale-prs.yaml b/.github/workflows/mark-stale-prs.yaml index 9a0a323809..788f30eaf7 100644 --- a/.github/workflows/mark-stale-prs.yaml +++ b/.github/workflows/mark-stale-prs.yaml @@ -1,11 +1,12 @@ -name: "Close stale pull requests" +name: Close stale pull requests on: schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' workflow_dispatch: jobs: stale: + if: github.repository_owner == 'adobecom' runs-on: ubuntu-latest steps: - uses: actions/stale@v9 diff --git a/.github/workflows/merge-to-main.js b/.github/workflows/merge-to-main.js new file mode 100644 index 0000000000..efbc9e55bc --- /dev/null +++ b/.github/workflows/merge-to-main.js @@ -0,0 +1,77 @@ +const { + slackNotification, + getLocalConfigs, + isWithinRCP, + pulls: { addLabels, addFiles, getChecks, getReviews }, +} = require('./helpers.js'); + +// Run from the root of the project for local testing: node --env-file=.env .github/workflows/merge-to-main.js +const PR_TITLE = '[Release] Stage to Main'; +const STAGE = 'stage'; +const PROD = 'main'; + +let github, owner, repo; + +const getStageToMainPR = () => + github.rest.pulls + .list({ owner, repo, state: 'open', base: PROD, head: STAGE }) + .then(({ data } = {}) => data.find(({ title } = {}) => title === PR_TITLE)) + .then((pr) => pr && addLabels({ pr, github, owner, repo })); + +const workingHours = () => { + const now = new Date(); + const day = now.getUTCDay(); + const hour = now.getUTCHours(); + const isSunday = day === 0; + const isSaturday = day === 6; + const isFriday = day === 5; + return hour >= 8 && hour <= 20 && !isFriday && !isSaturday && !isSunday; +}; + +const main = async (params) => { + github = params.github; + owner = params.context.repo.owner; + repo = params.context.repo.repo; + + if (isWithinRCP()) return console.log('Stopped, within RCP period.'); + if (!workingHours()) return console.log('Stopped, outside working hours.'); + + try { + const stageToMainPR = await getStageToMainPR(); + const signOffs = stageToMainPR?.labels.filter((l) => l.includes('SOT')); + console.log(`${signOffs.length} SOT labels on PR ${stageToMainPR.number}`); + if (signOffs.length >= 4) { + console.log('Stage to Main PR has all required labels. Merging...'); + await github.rest.pulls.merge({ + owner, + repo, + pull_number: stageToMainPR.number, + merge_method: 'merge', + }); + + await slackNotification( + `:rocket: Production release <${stageToMainPR.html_url}|${stageToMainPR.number}>` + ); + + await github.rest.repos.createDispatchEvent({ + owner, + repo, + event_type: 'merge-to-stage', + }); + } + + console.log('Process successfully executed.'); + } catch (error) { + console.error(error); + } +}; + +if (process.env.LOCAL_RUN) { + const { github, context } = getLocalConfigs(); + main({ + github, + context, + }); +} + +module.exports = main; diff --git a/.github/workflows/merge-to-main.yaml b/.github/workflows/merge-to-main.yaml new file mode 100644 index 0000000000..9b4ba782bf --- /dev/null +++ b/.github/workflows/merge-to-main.yaml @@ -0,0 +1,37 @@ +name: Merge to main + +on: + pull_request: + types: [labeled] + schedule: + - cron: '0 9 * * *' # Run every day at 9am UTC + workflow_dispatch: # Allow manual trigger + +env: + MILO_RELEASE_SLACK_WH: ${{ secrets.MILO_RELEASE_SLACK_WH }} + +jobs: + merge-to-main: + runs-on: ubuntu-latest + environment: milo_pr_merge + # Run this when manually triggered or on a schedule + # Otherwise run this only on PRs that are merged from stage to main + if: github.repository_owner == 'adobecom' && (github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.ref == 'stage')) + + steps: + - uses: actions/create-github-app-token@v1.10.0 + id: milo-pr-merge-token + with: + app-id: ${{ secrets.MILO_PR_MERGE_APP_ID }} + private-key: ${{ secrets.MILO_PR_MERGE_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@v4.1.4 + + - name: Merge to main + uses: actions/github-script@v7.0.1 + with: + github-token: ${{ steps.milo-pr-merge-token.outputs.token }} + script: | + const main = require('./.github/workflows/merge-to-main.js') + main({ github, context }) diff --git a/.github/workflows/merge-to-stage.js b/.github/workflows/merge-to-stage.js index 15106f9c6c..1ce20ca4c4 100644 --- a/.github/workflows/merge-to-stage.js +++ b/.github/workflows/merge-to-stage.js @@ -1,6 +1,7 @@ const { slackNotification, getLocalConfigs, + isWithinRCP, pulls: { addLabels, addFiles, getChecks, getReviews }, } = require('./helpers.js'); @@ -14,7 +15,6 @@ const LABELS = { highPriority: 'high priority', readyForStage: 'Ready for Stage', SOTPrefix: 'SOT', - highImpact: 'high-impact', }; const TEAM_MENTIONS = [ '@adobecom/miq-sot', @@ -24,8 +24,8 @@ const TEAM_MENTIONS = [ '@adobecom/document-cloud-sot', ]; const SLACK = { - merge: ({ html_url, number, title, highImpact }) => - `:merged:${highImpact} PR merged to stage: <${html_url}|${number}: ${title}>.`, + merge: ({ html_url, number, title }) => + `:merged: PR merged to stage: <${html_url}|${number}: ${title}>.`, openedSyncPr: ({ html_url, number }) => `:fast_forward: Created <${html_url}|Stage to Main PR ${number}>`, }; @@ -45,45 +45,6 @@ let body = ` - After: https://stage--milo--adobecom.hlx.live/?martech=off `; -const RCPDates = [ - { - start: new Date('2024-05-26T00:00:00-07:00'), - end: new Date('2024-06-01T00:00:00-07:00'), - }, - { - start: new Date('2024-06-13T11:00:00-07:00'), - end: new Date('2024-06-13T14:00:00-07:00'), - }, - { - start: new Date('2024-06-30T00:00:00-07:00'), - end: new Date('2024-07-06T00:00:00-07:00'), - }, - { - start: new Date('2024-08-25T00:00:00-07:00'), - end: new Date('2024-08-31T00:00:00-07:00'), - }, - { - start: new Date('2024-09-12T11:00:00-07:00'), - end: new Date('2024-09-12T14:00:00-07:00'), - }, - { - start: new Date('2024-10-14T00:00:00-07:00'), - end: new Date('2024-11-18T17:00:00-08:00'), - }, - { - start: new Date('2024-11-17T00:00:00-08:00'), - end: new Date('2024-11-30T00:00:00-08:00'), - }, - { - start: new Date('2024-12-12T11:00:00-08:00'), - end: new Date('2024-12-12T14:00:00-08:00'), - }, - { - start: new Date('2024-12-15T00:00:00-08:00'), - end: new Date('2025-01-02T00:00:00-08:00'), - }, -]; - const isHighPrio = (labels) => labels.includes(LABELS.highPriority); const hasFailingChecks = (checks) => @@ -124,7 +85,8 @@ const getPRs = async () => { const merge = async ({ prs }) => { console.log(`Merging ${prs.length || 0} PRs that are ready... `); - for await (const { number, files, html_url, title, labels } of prs) { + + for await (const { number, files, html_url, title } of prs) { try { if (files.some((file) => SEEN[file])) { console.log(`Skipping ${number}: ${title} due to overlap in files.`); @@ -140,24 +102,11 @@ const merge = async ({ prs }) => { }); } body = `- ${html_url}\n${body}`; - const isHighImpact = labels.includes(LABELS.highImpact); - if (isHighImpact && process.env.SLACK_HIGH_IMPACT_PR_WEBHOOK) { - await slackNotification( - SLACK.merge({ - html_url, - number, - title, - highImpact: ' :alert: High impact', - }), - process.env.SLACK_HIGH_IMPACT_PR_WEBHOOK - ); - } await slackNotification( SLACK.merge({ html_url, number, title, - highImpact: isHighImpact ? ' :alert: High impact' : '', }) ); await new Promise((resolve) => setTimeout(resolve, 5000)); @@ -230,18 +179,8 @@ const main = async (params) => { github = params.github; owner = params.context.repo.owner; repo = params.context.repo.repo; + if (isWithinRCP()) return console.log('Stopped, within RCP period.'); - const now = new Date(); - // We need to revisit this every year - if (now.getFullYear() !== 2024) { - throw new Error('ADD NEW RCPs'); - } - for (const { start, end } of RCPDates) { - if (start <= now && now <= end) { - console.log('Current date is within a RCP. Stopping execution.'); - return; - } - } try { const stageToMainPR = await getStageToMainPR(); console.log('has Stage to Main PR:', !!stageToMainPR); diff --git a/.github/workflows/merge-to-stage.yaml b/.github/workflows/merge-to-stage.yaml index 406e226527..c6457233d6 100644 --- a/.github/workflows/merge-to-stage.yaml +++ b/.github/workflows/merge-to-stage.yaml @@ -4,6 +4,8 @@ on: schedule: - cron: '0 */4 * * *' # Run every 4 hours workflow_dispatch: # Allow manual trigger + repository_dispatch: + types: [merge-to-stage] env: MILO_RELEASE_SLACK_WH: ${{ secrets.MILO_RELEASE_SLACK_WH }} @@ -12,6 +14,7 @@ env: jobs: merge-to-stage: + if: github.repository_owner == 'adobecom' runs-on: ubuntu-latest environment: milo_pr_merge diff --git a/.github/workflows/pr-reminders.yaml b/.github/workflows/pr-reminders.yaml index 539c8beb2d..6851f93de1 100644 --- a/.github/workflows/pr-reminders.yaml +++ b/.github/workflows/pr-reminders.yaml @@ -7,6 +7,7 @@ on: jobs: update: + if: github.repository_owner == 'adobecom' runs-on: ubuntu-latest steps: diff --git a/libs/blocks/global-navigation/global-navigation.js b/libs/blocks/global-navigation/global-navigation.js index edc2f9fb6f..0f87a47406 100644 --- a/libs/blocks/global-navigation/global-navigation.js +++ b/libs/blocks/global-navigation/global-navigation.js @@ -991,10 +991,20 @@ class Gnav { }; } +const getSource = async () => { + const { locale, dynamicNavKey } = getConfig(); + let url = getMetadata('gnav-source') || `${locale.contentRoot}/gnav`; + if (dynamicNavKey) { + const { default: dynamicNav } = await import('../../features/dynamic-navigation.js'); + url = dynamicNav(url, dynamicNavKey); + } + return url; +}; + export default async function init(block) { try { - const { locale, mep } = getConfig(); - const url = getMetadata('gnav-source') || `${locale.contentRoot}/gnav`; + const { mep } = getConfig(); + const url = await getSource(); const content = await fetchAndProcessPlainHtml({ url }) .catch((e) => lanaLog({ message: `Error fetching gnav content url: ${url}`, diff --git a/libs/blocks/merch-card-collection/merch-card-collection.css b/libs/blocks/merch-card-collection/merch-card-collection.css index b9a4c22a41..3f07850d91 100644 --- a/libs/blocks/merch-card-collection/merch-card-collection.css +++ b/libs/blocks/merch-card-collection/merch-card-collection.css @@ -1,3 +1,7 @@ .section[class*="-merch-cards"] .full-width { grid-column: 1 / -1; } + +merch-card-collection { + --link-color: var(--merch-color-grey-80); +} diff --git a/libs/blocks/merch-card-collection/merch-card-collection.js b/libs/blocks/merch-card-collection/merch-card-collection.js index 234f3aac19..c124d7dd8a 100644 --- a/libs/blocks/merch-card-collection/merch-card-collection.js +++ b/libs/blocks/merch-card-collection/merch-card-collection.js @@ -220,10 +220,12 @@ export default async function init(el) { ...deps, import(`${base}/features/spectrum-web-components/dist/theme.js`), import(`${base}/features/spectrum-web-components/dist/button.js`), + import(`${base}/features/spectrum-web-components/dist/action-button.js`), + import(`${base}/features/spectrum-web-components/dist/action-menu.js`), import(`${base}/features/spectrum-web-components/dist/search.js`), - import(`${base}/features/spectrum-web-components/dist/overlay.js`), import(`${base}/features/spectrum-web-components/dist/menu.js`), - import(`${base}/features/spectrum-web-components/dist/popover.js`), + import(`${base}/features/spectrum-web-components/dist/overlay.js`), + import(`${base}/features/spectrum-web-components/dist/tray.js`), ] : []; const preferences = {}; diff --git a/libs/blocks/merch-card/merch-card.css b/libs/blocks/merch-card/merch-card.css index 3211ec9b84..a48826f8dd 100644 --- a/libs/blocks/merch-card/merch-card.css +++ b/libs/blocks/merch-card/merch-card.css @@ -8,6 +8,14 @@ div[class*="-merch-card"] > div, grid-column: 1 / -1; } + merch-card .action-area, merch-card div[slot="footer"] > p { + display: contents; + } + + merch-card .action-area br { + display: none; + } + .merch-card-price { margin-top: 8px; margin-bottom: 16px; @@ -34,10 +42,11 @@ merch-card a[is="checkout-link"].upgrade:not(:first-of-type) { display: none; } -/* Tablet and larger */ -@media screen and (min-width: 768px) { - .badge-merch-cards .card-heading, - .badge-card .card-heading { - margin-top: var(--spacing-s); +@media screen and (max-width: 1199px) { + merch-card[variant="mini-compare-chart"] [slot="footer"] a.con-button { + min-width: 66px; /* same as merch links */ + padding: 4px 18px 5px 21px; + font-size: var(--consonant-merch-card-mini-compare-mobile-cta-font-size); + } } diff --git a/libs/blocks/merch-card/merch-card.js b/libs/blocks/merch-card/merch-card.js index f94dc7858e..cd71b33a6a 100644 --- a/libs/blocks/merch-card/merch-card.js +++ b/libs/blocks/merch-card/merch-card.js @@ -26,6 +26,10 @@ const HEADING_MAP = { }; const MINI_COMPARE_CHART = 'mini-compare-chart'; +const PLANS = 'plans'; +const SEGMENT = 'segment'; + +const INNER_ELEMENTS_SELECTOR = 'h2, h3, h4, h5, p, ul, em'; const MULTI_OFFER_CARDS = ['plans', 'product', MINI_COMPARE_CHART]; // Force cards to refresh once they become visible so that the footer rows are properly aligned. @@ -87,7 +91,7 @@ const parseContent = async (el, merchCard) => { await loadMnemonicList(mnemonicList); } const innerElements = [ - ...el.querySelectorAll('h2, h3, h4, h5, p, ul, em'), + ...el.querySelectorAll(INNER_ELEMENTS_SELECTOR), ]; innerElements.forEach((element) => { let { tagName } = element; @@ -282,7 +286,8 @@ const setMiniCompareOfferSlot = (merchCard, offers) => { merchCard.appendChild(miniCompareOffers); }; -const init = async (el) => { +export default async function init(el) { + if (!el.querySelector(INNER_ELEMENTS_SELECTOR)) return el; const styles = [...el.classList]; const cardType = getPodType(styles) || 'product'; if (!styles.includes(cardType)) { @@ -345,8 +350,10 @@ const init = async (el) => { } } let footerRows; - if (cardType === MINI_COMPARE_CHART) { + if ([MINI_COMPARE_CHART, PLANS, SEGMENT].includes(cardType)) { intersectionObserver.observe(merchCard); + } + if (cardType === MINI_COMPARE_CHART) { footerRows = getMiniCompareChartFooterRows(el); } const allPictures = el.querySelectorAll('picture'); @@ -390,18 +397,20 @@ const init = async (el) => { imageSlot.appendChild(image); merchCard.appendChild(imageSlot); } + parseContent(el, merchCard); if (!icons || icons.length > 0) { const iconImgs = Array.from(icons).map((icon) => { const img = { src: icon.querySelector('img').src, alt: icon.querySelector('img').alt, + href: icon.closest('a')?.href ?? '', }; return img; }); - merchCard.setAttribute( - 'icons', - JSON.stringify(Array.from(iconImgs)), - ); + iconImgs.forEach((icon) => { + const merchIcon = createTag('merch-icon', { slot: 'icons', src: icon.src, alt: icon.alt, href: icon.href, size: 'l' }); + merchCard.appendChild(merchIcon); + }); icons.forEach((icon) => icon.remove()); } @@ -411,7 +420,7 @@ const init = async (el) => { } merchCard.setAttribute('filters', categories.join(',')); merchCard.setAttribute('types', types.join(',')); - parseContent(el, merchCard); + const footer = createTag('div', { slot: 'footer' }); if (ctas) { if (merchCard.variant === 'mini-compare-chart') { @@ -419,7 +428,9 @@ const init = async (el) => { } else { decorateButtons(ctas); } - footer.append(ctas); + const links = ctas.querySelectorAll('a'); + ctas.remove(); + footer.append(...links); } merchCard.appendChild(footer); @@ -453,6 +464,4 @@ const init = async (el) => { el.replaceWith(merchCard); decorateMerchCardLinkAnalytics(merchCard); return merchCard; -}; - -export default init; +} diff --git a/libs/blocks/merch/merch.css b/libs/blocks/merch/merch.css index 85ec28055a..e4a89dad3c 100644 --- a/libs/blocks/merch/merch.css +++ b/libs/blocks/merch/merch.css @@ -18,6 +18,7 @@ span.placeholder-resolved[data-template="strikethrough"], span.price.price-strik a[is='checkout-link'] > span { display: inline-block; text-align: center; + width: 100%; min-width: 66px; } diff --git a/libs/deps/merch-card-collection.js b/libs/deps/merch-card-collection.js index d3694e3dca..c19cebe9cc 100644 --- a/libs/deps/merch-card-collection.js +++ b/libs/deps/merch-card-collection.js @@ -1,5 +1,5 @@ -// Wed, 20 Mar 2024 10:04:28 GMT -import{html as a,LitElement as A}from"/libs/deps/lit-all.min.js";import{unsafeHTML as w}from"/libs/deps/lit-all.min.js";var d=class{constructor(t,e){this.key=Symbol("match-media-key"),this.matches=!1,this.host=t,this.host.addController(this),this.media=window.matchMedia(e),this.matches=this.media.matches,this.onChange=this.onChange.bind(this),t.addController(this)}hostConnected(){var t;(t=this.media)==null||t.addEventListener("change",this.onChange)}hostDisconnected(){var t;(t=this.media)==null||t.removeEventListener("change",this.onChange)}onChange(t){this.matches!==t.matches&&(this.matches=t.matches,this.host.requestUpdate(this.key,!this.matches))}};var f="hashchange";function C(r=window.location.hash){let t=[],e=r.replace(/^#/,"").split("&");for(let o of e){let[n,i=""]=o.split("=");n&&t.push([n,decodeURIComponent(i)])}return Object.fromEntries(t)}function p(r){let t=new URLSearchParams(window.location.hash.slice(1));Object.entries(r).forEach(([e,o])=>{o?t.set(e,o):t.delete(e)}),t.sort(),window.location.hash=decodeURIComponent(t.toString())}function g(r){let t=e=>{let o=C(window.location.hash);r(o)};return t(),window.addEventListener(f,t),()=>{window.removeEventListener(f,t)}}var x=(r,t={})=>{r.querySelectorAll("span[data-placeholder]").forEach(e=>{let{placeholder:o}=e.dataset;e.innerText=t[o]??""})};var y="(max-width: 1200px)",T="(min-width: 768px)",E="(min-width: 1200px)";import{css as v,unsafeCSS as b}from"/libs/deps/lit-all.min.js";var S=v` +// branch: develop commit: f499abc85176fc7d34f43457efeeb72adb1e6103 Thu, 30 May 2024 14:05:27 GMT +import{html as a,LitElement as N}from"/libs/deps/lit-all.min.js";var m=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 E="hashchange";function S(r=window.location.hash){let e=[],t=r.replace(/^#/,"").split("&");for(let o of t){let[i,l=""]=o.split("=");i&&e.push([i,decodeURIComponent(l.replace(/\+/g," "))])}return Object.fromEntries(e)}function p(r){let e=new URLSearchParams(window.location.hash.slice(1));Object.entries(r).forEach(([i,l])=>{l?e.set(i,l):e.delete(i)}),e.sort();let t=e.toString(),o=window.scrollY||document.documentElement.scrollTop;window.location.hash=t,window.scrollTo(0,o)}function x(r){let e=()=>{let t=S(window.location.hash);r(t)};return e(),window.addEventListener(E,e),()=>{window.removeEventListener(E,e)}}var g=(r,e={})=>{r.querySelectorAll("span[data-placeholder]").forEach(t=>{let{placeholder:o}=t.dataset;t.innerText=e[o]??""})};var T="(max-width: 1199px)",y="(min-width: 768px)",C="(min-width: 1200px)";import{css as _,unsafeCSS as b}from"/libs/deps/lit-all.min.js";var w=_` #header, #resultText, #footer { @@ -16,7 +16,7 @@ import{html as a,LitElement as A}from"/libs/deps/lit-all.min.js";import{unsafeHT order: -2; display: grid; justify-items: top; - grid-template-columns: 1fr 1fr; + grid-template-columns: auto max-content; grid-template-rows: auto; row-gap: var(--consonant-merch-spacing-m); align-self: baseline; @@ -45,7 +45,11 @@ import{html as a,LitElement as A}from"/libs/deps/lit-all.min.js";import{unsafeHT justify-self: end; } - sp-menu sp-button { + sp-action-button { + align-self: baseline; + } + + sp-menu sp-action-button { min-width: 140px; } @@ -58,7 +62,7 @@ import{html as a,LitElement as A}from"/libs/deps/lit-all.min.js";import{unsafeHT } /* tablets */ - @media screen and ${b(T)} { + @media screen and ${b(y)} { #header { grid-template-columns: 1fr fit-content(100%) fit-content(100%); } @@ -77,7 +81,7 @@ import{html as a,LitElement as A}from"/libs/deps/lit-all.min.js";import{unsafeHT } /* Laptop */ - @media screen and ${b(E)} { + @media screen and ${b(C)} { #resultText { grid-column: span 2; order: -3; @@ -89,9 +93,9 @@ import{html as a,LitElement as A}from"/libs/deps/lit-all.min.js";import{unsafeHT justify-content: end; } } -`;var u=(r,t)=>r.querySelector(`[slot="${t}"]`).textContent.trim();var $="merch-card-collection",l={alphabetical:"alphabetical",authored:"authored"},k={filters:["noResultText","resultText","resultsText"],mobile:["noSearchResultsMobileText","searchResultMobileText","searchResultsMobileText"],desktop:["noSearchResultsText","searchResultText","searchResultsText"]},M=(r,{filter:t})=>r.filter(e=>e.filters.hasOwnProperty(t)),B=(r,{types:t})=>t?(t=t.split(","),r.filter(e=>t.some(o=>e.types.includes(o)))):r,N=r=>r.sort((t,e)=>(t.title??"").localeCompare(e.title??"","en",{sensitivity:"base"})),R=(r,{filter:t})=>r.sort((e,o)=>o.filters[t]?.order==null||isNaN(o.filters[t]?.order)?-1:e.filters[t]?.order==null||isNaN(e.filters[t]?.order)?1:e.filters[t].order-o.filters[t].order),L=(r,{search:t})=>t?.length?(t=t.toLowerCase(),r.filter(e=>e.includes(t))):r,m=class extends A{static 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:l.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;#t;mobileAndTablet=new d(this,y);constructor(){super(),this.filter="all",this.hasMore=!1,this.resultCount=void 0,this.#t=0,this.displayResult=!1}render(){return a`${this.header} +`;var u=(r,e)=>r.querySelector(`[slot="${e}"]`).textContent.trim();var A="merch-card-collection",n={alphabetical:"alphabetical",authored:"authored"},R={filters:["noResultText","resultText","resultsText"],mobile:["noSearchResultsMobileText","searchResultMobileText","searchResultsMobileText"],desktop:["noSearchResultsText","searchResultText","searchResultsText"]},v=(r,{filter:e})=>r.filter(t=>t.filters.hasOwnProperty(e)),M=(r,{types:e})=>e?(e=e.split(","),r.filter(t=>e.some(o=>t.types.includes(o)))):r,L=r=>r.sort((e,t)=>(e.title??"").localeCompare(t.title??"","en",{sensitivity:"base"})),D=(r,{filter:e})=>r.sort((t,o)=>o.filters[e]?.order==null||isNaN(o.filters[e]?.order)?-1:t.filters[e]?.order==null||isNaN(t.filters[e]?.order)?1:t.filters[e].order-o.filters[e].order),k=(r,{search:e})=>e?.length?(e=e.toLowerCase(),r.filter(t=>(t.title??"").toLowerCase().includes(e))):r,f=class extends N{static 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:n.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}};mobileAndTablet=new m(this,T);constructor(){super(),this.filter="all",this.hasMore=!1,this.resultCount=void 0,this.displayResult=!1}render(){return a`${this.header} - ${this.footer}`}updated(t){if(!this.querySelector("merch-card"))return;let e=[...this.children].filter(s=>s.tagName==="MERCH-CARD");if(e.length===0)return;t.has("singleApp")&&this.singleApp&&e.forEach(s=>{s.updateFilters(s.name===this.singleApp)});let o=this.sort===l.alphabetical?N:R,i=[M,B,L,o].reduce((s,c)=>c(s,this),e).map((s,c)=>[s,c]);if(this.resultCount=i.length,this.page&&this.limit){let s=this.page*this.limit;this.hasMore=i.length>s,i=i.filter(([,c])=>c{h.has(s)?(s.style.order=h.get(s),s.style.order===this.#t&&(this.#e=s),s.size=s.filters[this.filter]?.size,s.style.removeProperty("display"),s.requestUpdate()):(s.style.display="none",s.size=void 0,s.style.removeProperty("order"))}),this.updateComplete.then(()=>{let s=this.shadowRoot.getElementById("resultText")?.firstElementChild?.assignedElements?.()?.[0];s&&x(s,{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 a` @@ -135,36 +136,24 @@

Acrobat Pro

@@ -178,19 +167,8 @@

Acrobat Pro

Photography

- - - US$ - - 19 - . - 99 - /mo - per license - - +

Storage:

@@ -198,42 +176,30 @@

  • 20GB
    • - - US$ - - 9 - . - 99 - /mo - per license - - -
    • -
    • Free trial
    • -
    • Buy now
    • + data-display-tax="false" data-force-tax-exclusive="true" + data-wcs-osi="6WK1gybjBe2EKcq0HI0WvbsoiKOri2yRAwS9t_kGHoE"> + +
    • Free trial
    • +
    • Buy now
    • Lightroom, Lightroom Classic, Photoshop on desktop and iPad, and 20GB of cloud storage.
  • 1TB
    • - - US$ - - 19 - . - 99 - /mo - per license - - - /li> -
    • Free trial
    • -
    • Buy now
    • + data-display-tax="false" data-force-tax-exclusive="true" + data-wcs-osi="MzCpF9nUi8rEzyW-9slEUwtRenS69PRW5fp84a93uK4"> + /li> +
    • Free trial
    • +
    • Buy now
    • Lightroom, Lightroom Classic, Photoshop on desktop and iPad, andz 1TB of cloud storage.
  • diff --git a/test/blocks/merch/merch.test.js b/test/blocks/merch/merch.test.js index df54c08385..ec85c43b11 100644 --- a/test/blocks/merch/merch.test.js +++ b/test/blocks/merch/merch.test.js @@ -126,8 +126,8 @@ describe('Merch Block', () => { before(async () => { window.lana = { log: () => { } }; - document.head.innerHTML = await readMockText('head.html'); - document.body.innerHTML = await readMockText('body.html'); + document.head.innerHTML = await readMockText('/test/blocks/merch/mocks/head.html'); + document.body.innerHTML = await readMockText('/test/blocks/merch/mocks/body.html'); ({ setCheckoutLinkConfigs, setSubscriptionsData } = await mockFetch()); config.commerce = { priceLiteralsPromise: fetchLiterals(PRICE_LITERALS_URL) }; setCheckoutLinkConfigs(CHECKOUT_LINK_CONFIGS); @@ -309,7 +309,7 @@ describe('Merch Block', () => { const { nodeName, href } = await el.onceSettled(); expect(nodeName).to.equal('A'); expect(el.getAttribute('is')).to.equal('checkout-link'); - expect(/0ADF92A6C8514F2800BE9E87DB641D2A/.test(href)).to.be.true; + expect(/B740D1F2F6369BD1C342E6E372A61B50/.test(href)).to.be.true; }); it('renders merch link to cta with empty promo', async () => { diff --git a/test/blocks/merch/mocks/fetch.js b/test/blocks/merch/mocks/fetch.js index 98d38b8081..74e097ae5e 100644 --- a/test/blocks/merch/mocks/fetch.js +++ b/test/blocks/merch/mocks/fetch.js @@ -1,26 +1,44 @@ import sinon from 'sinon'; import { PRICE_LITERALS_URL } from '../../../../libs/blocks/merch/merch.js'; - -const MOCKS_PATH = '/test/blocks/merch/mocks'; +import { applyPlanType } from '../../../../libs/deps/commerce.js'; const { fetch } = window; -export const readMockJSON = async (fileName) => { - const json = await fetch(`${MOCKS_PATH}/${fileName}`).then((res) => res.json()); +export const readMockJSON = async (path) => { + const json = await fetch(path).then((res) => res.json()); return json; }; -export const readMockText = async (fileName) => { - const text = await fetch(`${MOCKS_PATH}/${fileName}`).then((res) => res.text()); +export const readMockText = async (path) => { + const text = await fetch(path).then((res) => res.text()); return text; }; export async function mockFetch() { // this path allows to import this mock from tests for other blocks (e.g. commerce) - const literals = await readMockJSON('literals.json'); - const offers = await readMockJSON('offers.json'); - const namedOffers = await readMockJSON('named-offers.json'); + const basePath = '/test/blocks/merch/mocks/'; + const literals = await readMockJSON(`${basePath}literals.json`); + const offers = await readMockJSON(`${basePath}offers.json`); + const namedOffers = await readMockJSON(`${basePath}named-offers.json`); + + namedOffers.forEach(({ resolvedOffers: [offer] }) => { + const { + offerSelectorIds, + productArrangement: { productFamily }, + offerType, + customerSegment, + marketSegments: [ + marketSegment, + ], + language, + } = offer; + // eslint-disable-next-line no-nested-ternary + const segment = customerSegment === 'TEAM' ? 'cct' : marketSegment === 'COM' ? 'cci' : 'cce'; + const { planType } = applyPlanType(offer); + const osi = `${productFamily}-${offerType}-${planType}-${language}-${segment}`.toLowerCase(); + offerSelectorIds.unshift(osi); + }); let checkoutLinkConfigs; const setCheckoutLinkConfigs = (data) => { @@ -45,12 +63,14 @@ export async function mockFetch() { if (pathname.endsWith('/web_commerce_artifact')) { const osis = searchParams.get('offer_selector_ids').split(','); const firstOsi = osis[0]; + const namedOffer = namedOffers + .find(({ resolvedOffers: [offer] }) => offer.offerSelectorIds.includes(firstOsi)); return Promise.resolve({ status: 200, statusText: '', ok: true, json: () => Promise.resolve( - (/^[A-Za-z]/.test(firstOsi)) ? namedOffers[firstOsi] : { + namedOffer ?? { resolvedOffers: osis.map((osi) => { let index = Number.parseInt(osi, 10); if (Number.isNaN(index) || !Number.isFinite(index) || index < 0) index = 0; diff --git a/test/blocks/merch/mocks/named-offers.json b/test/blocks/merch/mocks/named-offers.json index 02e792f95e..eb74113060 100644 --- a/test/blocks/merch/mocks/named-offers.json +++ b/test/blocks/merch/mocks/named-offers.json @@ -1,179 +1,973 @@ +[ { - "gb1": { - "resolvedOffers": [ - { - "offerSelectorIds": [ - "gb1" - ], - "offerId": "0ADF92A6C8514F2800BE9E87DB641D2A", - "priceDetails": { - "price": 273.17, - "priceWithoutTax": 0.0, - "priceWithoutDiscountAndTax": 227.64, - "usePrecision": true, - "formatString": "'£'#,##0.00", - "taxDisplay": "TAX_INCLUSIVE_DETAILS", - "taxTerm": "VAT" - }, - "analytics": "{\"offerId\":\"0ADF92A6C8514F2800BE9E87DB641D2A\",\"label\":\"phsp_direct_individual\",\"price\":\"273.17\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"GBP\"}", - "productArrangementCode": "phsp_direct_individual", - "productArrangement": { - "productFamily": "PHOTOSHOP" - }, - "buyingProgram": "RETAIL", - "commitment": "YEAR", - "term": "ANNUAL", - "customerSegment": "INDIVIDUAL", - "marketSegments": [ - "COM" - ], - "salesChannel": "DIRECT", - "offerType": "TRIAL", - "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", - "language": "MULT", - "merchant": "ADOBE" - }, - { - "offerSelectorIds": [ - "gb1" - ], - "offerId": "49133266E474B3E6EE5D1CB98B95B824", - "priceDetails": { - "price": 262.51, - "priceWithoutTax": 0.0, - "priceWithoutDiscountAndTax": 218.76, - "usePrecision": true, - "formatString": "'£'#,##0.00", - "taxDisplay": "TAX_INCLUSIVE_DETAILS", - "taxTerm": "VAT" - }, - "analytics": "{\"offerId\":\"49133266E474B3E6EE5D1CB98B95B824\",\"label\":\"phsp_direct_individual\",\"price\":\"262.51\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"GBP\"}", - "productArrangementCode": "phsp_direct_individual", - "productArrangement": { - "productFamily": "PHOTOSHOP" - }, - "buyingProgram": "RETAIL", - "commitment": "YEAR", - "term": "ANNUAL", - "customerSegment": "INDIVIDUAL", - "marketSegments": [ - "COM" - ], - "salesChannel": "DIRECT", - "offerType": "TRIAL", - "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", - "language": "EN", - "merchant": "ADOBE" - } - ] - }, - "illustrator-trial": { - "resolvedOffers": [ - { - "offerSelectorIds": [ - "illustrator-trial" - ], - "offerId": "C1C12BA6D34A45AB9C1F7836C88DD4F8", - "priceDetails": { - "price": 22.99, - "priceWithoutTax": 0.0, - "priceWithoutDiscountAndTax": 22.99, - "usePrecision": true, - "formatString": "'US$'#,##0.00", - "taxDisplay": "TAX_EXCLUSIVE", - "taxTerm": "TAX" - }, - "analytics": "{\"offerId\":\"C1C12BA6D34A45AB9C1F7836C88DD4F8\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", - "productArrangementCode": "ilst_direct_individual", - "productArrangement": { - "productFamily": "ILLUSTRATOR" - }, - "buyingProgram": "RETAIL", - "commitment": "YEAR", - "term": "MONTHLY", - "customerSegment": "INDIVIDUAL", - "marketSegments": [ - "COM" - ], - "salesChannel": "DIRECT", - "offerType": "TRIAL", - "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", - "language": "MULT", - "merchant": "ADOBE" - } - ] - }, - "premiere-trial": { - "resolvedOffers": [ - { - "offerSelectorIds": [ - "premiere-trial" - ], - "offerId": "A3E81CB2F000EA56DB1E25A35C53C15F", - "startDate": "2020-04-20T07:01:00.000Z", - "endDate": "2050-04-08T19:59:00.000Z", - "priceDetails": { - "price": 22.99, - "priceWithoutTax": 0.0, - "priceWithoutDiscountAndTax": 22.99, - "usePrecision": true, - "formatString": "'US$'#,##0.00", - "taxDisplay": "TAX_EXCLUSIVE", - "taxTerm": "TAX" - }, - "analytics": "{\"offerId\":\"A3E81CB2F000EA56DB1E25A35C53C15F\",\"label\":\"ppro_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", - "productArrangementCode": "ppro_direct_individual", - "productArrangement": { - "productFamily": "PREMIERE" - }, - "buyingProgram": "RETAIL", - "commitment": "YEAR", - "term": "MONTHLY", - "customerSegment": "INDIVIDUAL", - "marketSegments": [ - "COM" - ], - "salesChannel": "DIRECT", - "offerType": "TRIAL", - "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", - "language": "MULT", - "merchant": "ADOBE" - } - ] - }, - "illustrator": { - "resolvedOffers": [ - { - "offerSelectorIds": [ - "illustrator" - ], - "offerId": "43538F47236C326E137A08307BFA70F2", - "priceDetails": { - "price": 22.99, - "priceWithoutTax": 22.99, - "usePrecision": true, - "formatString": "'US$'#,##0.00", - "taxDisplay": "TAX_EXCLUSIVE", - "taxTerm": "TAX" - }, - "analytics": "{\"offerId\":\"43538F47236C326E137A08307BFA70F2\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"22.99\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", - "productArrangementCode": "ilst_direct_individual", - "productArrangement": { - "productFamily": "ILLUSTRATOR" - }, - "buyingProgram": "RETAIL", - "commitment": "YEAR", - "term": "MONTHLY", - "customerSegment": "INDIVIDUAL", - "marketSegments": [ - "COM" - ], - "salesChannel": "DIRECT", - "offerType": "BASE", - "pricePoint": "REGULAR", - "language": "MULT", - "merchant": "ADOBE" - } - ] - } + "resolvedOffers": [ + { + "offerSelectorIds": [ + "L2C9cKHNNDaFtBVB6GVsyNI88RlyimSlzVfkMM2gH4A" + ], + "offerId": "49133266E474B3E6EE5D1CB98B95B824", + "startDate": "2020-04-20T07:01:00.000Z", + "endDate": "2050-04-08T19:59:00.000Z", + "priceDetails": { + "price": 262.51, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 218.76, + "usePrecision": true, + "formatString": "'£'#,##0.00", + "taxDisplay": "TAX_INCLUSIVE_DETAILS", + "taxTerm": "VAT" + }, + "analytics": "{\"offerId\":\"49133266E474B3E6EE5D1CB98B95B824\",\"label\":\"phsp_direct_individual\",\"price\":\"262.51\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"GBP\"}", + "productArrangementCode": "phsp_direct_individual", + "productArrangement": { + "productFamily": "PHOTOSHOP" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", + "language": "EN", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "frr4PaPpP1IkTTLP1G6TbdQPle_7mE2P1tVg74Nsgr8" + ], + "offerId": "0DA56534F200535C111B5D8817710FD5", + "startDate": "2024-01-29T16:00:00.000Z", + "endDate": "2050-12-17T07:58:00.000Z", + "priceDetails": { + "price": 1079.88, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 1079.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"0DA56534F200535C111B5D8817710FD5\",\"label\":\"ccle_direct_indirect_team\",\"price\":\"1079.88\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccle_direct_indirect_team", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "TEAM", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_14_DAY_TWP_TEAM_DIRECT_CCT_ALL_APPS_COM", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "6QMorJyNNAuQLg35h64xQtcyXz6Gw7QE8tihSs-zciU" + ], + "offerId": "DAC628518DDD843D4D19A8BF7D8FF1FE", + "startDate": "2024-01-29T16:00:00.000Z", + "endDate": "2050-12-17T07:58:00.000Z", + "priceDetails": { + "price": 89.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 89.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"DAC628518DDD843D4D19A8BF7D8FF1FE\",\"label\":\"ccle_direct_indirect_team\",\"price\":\"89.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccle_direct_indirect_team", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "TEAM", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_14_DAY_TWP_TEAM_DIRECT_CCT_ALL_APPS_COM", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "nlYSyCqrsegoFuLBJfEe-QqgnptUzduO5I-jA06CNFI" + ], + "offerId": "A9BF1E083874F26DD3C707BD1B53CF45", + "startDate": "2021-12-08T08:01:00.000Z", + "endDate": "2050-01-31T19:59:00.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"A9BF1E083874F26DD3C707BD1B53CF45\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_BASE_OFFER_TWP_CCI_ALL_APPS_AND_SINGLE_APP_NON_CCX", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "TvnoJYwMsiSd-S7hS9FK-orjWmkhi4ufgfRJ1iaIvEM" + ], + "offerId": "3FC0FFAB1342E059CB3863F6176ECA37", + "startDate": "2021-12-08T08:01:00.000Z", + "endDate": "2050-01-31T19:59:00.000Z", + "priceDetails": { + "price": 263.88, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 263.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"3FC0FFAB1342E059CB3863F6176ECA37\",\"label\":\"ilst_direct_individual\",\"price\":\"263.88\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_BASE_OFFER_TWP_CCI_ALL_APPS_AND_SINGLE_APP_NON_CCX", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "pZrSvg9dNEHfddeT-TKYDWfAISNGyZcxJ_bwtFZRzAc" + ], + "offerId": "5866CD66539F34346816D66D0E17698D", + "startDate": "2021-12-08T08:01:00.000Z", + "endDate": "2050-01-31T19:59:00.000Z", + "priceDetails": { + "price": 34.49, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 34.49, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"5866CD66539F34346816D66D0E17698D\",\"label\":\"ilst_direct_individual\",\"price\":\"34.49\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_BASE_OFFER_TWP_CCI_ALL_APPS_AND_SINGLE_APP_NON_CCX", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "JzW8dgW8U1SrgbHDmTE-ABsOKPgtl5jugiW8bA5PtKg" + ], + "offerId": "65BA7CA7573834AC4D043B0E7CBD2349", + "startDate": "2021-12-08T08:01:00.000Z", + "endDate": "2050-01-31T19:59:00.000Z", + "priceDetails": { + "price": 59.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 59.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"65BA7CA7573834AC4D043B0E7CBD2349\",\"label\":\"ccsn_direct_individual\",\"price\":\"59.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccsn_direct_individual", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_BASE_OFFER_TWP_CCI_ALL_APPS_AND_SINGLE_APP_NON_CCX", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "7QWcHXX6VIH_2BeNYI1GizMNGHJ3ZFz9-IMoC0gC-4c" + ], + "offerId": "1AB23148DED3D18062177AFEACEA6ECE", + "startDate": "2021-12-08T08:01:00.000Z", + "endDate": "2050-01-31T19:59:00.000Z", + "priceDetails": { + "price": 659.88, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 659.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"1AB23148DED3D18062177AFEACEA6ECE\",\"label\":\"ccsn_direct_individual\",\"price\":\"659.88\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccsn_direct_individual", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_BASE_OFFER_TWP_CCI_ALL_APPS_AND_SINGLE_APP_NON_CCX", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "MasJgjrlDjj72m_B1q1_4VhTDtxldl6yG4C16DkznhI" + ], + "offerId": "76EB6C3E0486E92E67A0BC1AB3CC7E19", + "startDate": "2021-12-08T08:01:00.000Z", + "endDate": "2050-01-31T19:59:00.000Z", + "priceDetails": { + "price": 89.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 89.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"76EB6C3E0486E92E67A0BC1AB3CC7E19\",\"label\":\"ccsn_direct_individual\",\"price\":\"89.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccsn_direct_individual", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_BASE_OFFER_TWP_CCI_ALL_APPS_AND_SINGLE_APP_NON_CCX", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "xxgyCsZk7zx3WAfpZMqiE6IMtvvu0CP4JJeIey_UtYo" + ], + "offerId": "C6DBF840A991DF84B7B3F871ABAD2415", + "startDate": "2020-09-26T14:31:00.000Z", + "priceDetails": { + "price": 19.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 19.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"C6DBF840A991DF84B7B3F871ABAD2415\",\"label\":\"ccsn_direct_individual\",\"price\":\"19.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccsn_direct_individual", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "EDU" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TRIAL_STE_FIRST_YEAR_ABM_US_ONLY", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "6jAp4YpZosSe5N5bCVbDcomwBmDLgN3RqZwXmn5ZR1s" + ], + "offerId": "13F9169A5EA8997CDB23379393AC0649", + "startDate": "2020-09-26T14:46:00.000Z", + "priceDetails": { + "price": 239.88, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 239.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"13F9169A5EA8997CDB23379393AC0649\",\"label\":\"ccsn_direct_individual\",\"price\":\"239.88\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ccsn_direct_individual", + "productArrangement": { + "productFamily": "CC_ALL_APPS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "EDU" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TRIAL_STE_FIRST_YEAR_ABM_US_ONLY", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "An5oaimikvfougEJNQBSz_f3VEgmd6acfeTQGGaPCoE" + ], + "offerId": "7164A328080BC96CC60FEBF33F64342D", + "startDate": "2018-12-03T07:59:59.000Z", + "endDate": "2029-10-05T07:59:59.000Z", + "priceDetails": { + "price": 29.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 29.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"7164A328080BC96CC60FEBF33F64342D\",\"label\":\"stks_direct_individual\",\"price\":\"29.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "stks_direct_individual", + "productArrangement": { + "productFamily": "STOCK_ASSETS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_STOCK_7_DAY_TRIAL", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "UvwrHnX9p1fBz2LoI0UvEdQ8JnZ-KGQKDamDKfwtygk" + ], + "offerId": "E3171ADBB9D7A5359EC8128650B7710D", + "startDate": "2018-12-03T07:59:59.000Z", + "endDate": "2029-10-05T07:59:59.000Z", + "priceDetails": { + "price": 359.88, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 359.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"E3171ADBB9D7A5359EC8128650B7710D\",\"label\":\"stks_direct_individual\",\"price\":\"359.88\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "stks_direct_individual", + "productArrangement": { + "productFamily": "STOCK_ASSETS" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_STOCK_7_DAY_TRIAL", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "BJWO8GmMhLAjgxfL55oSz-7c7KSyLQdY9jotgROXSqM" + ], + "offerId": "3002E1908F4574F62C0A9ABA58196755", + "startDate": "2018-12-03T07:59:59.000Z", + "endDate": "2029-10-05T07:59:59.000Z", + "priceDetails": { + "price": 49.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 49.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"3002E1908F4574F62C0A9ABA58196755\",\"label\":\"stks_direct_individual\",\"price\":\"49.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "stks_direct_individual", + "productArrangement": { + "productFamily": "STOCK_ASSETS" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_STOCK_7_DAY_TRIAL", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "1KfaN_o5h4Gvmvh_QwfK7KB7xGPpNpsTXsdhqpJUT5Y" + ], + "offerId": "43538F47236C326E137A08307BFA70F2", + "startDate": "2015-11-17T20:43:19.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"43538F47236C326E137A08307BFA70F2\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"22.99\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "kVGMtXot7H9toCNBffogFGxgFEh9IBRNKFA3gQhZhpo" + ], + "offerId": "971E1ACB6EF4E30EDF890D1B230DD162", + "startDate": "2020-04-20T07:01:00.000Z", + "endDate": "2050-04-08T19:59:00.000Z", + "priceDetails": { + "price": 263.88, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 263.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"971E1ACB6EF4E30EDF890D1B230DD162\",\"label\":\"ppro_direct_individual\",\"price\":\"263.88\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ppro_direct_individual", + "productArrangement": { + "productFamily": "PREMIERE" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "zLM1ML9mB8lFrOoTdmNsV9K5-F-n5k8HLYJyE4yonV8" + ], + "offerId": "A3E81CB2F000EA56DB1E25A35C53C15F", + "startDate": "2020-04-20T07:01:00.000Z", + "endDate": "2050-04-08T19:59:00.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"A3E81CB2F000EA56DB1E25A35C53C15F\",\"label\":\"ppro_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ppro_direct_individual", + "productArrangement": { + "productFamily": "PREMIERE" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "1avoYh4OfMbgnCts12Kjik6lIBOBMYip0a5EyG7PafM" + ], + "offerId": "07AF00C11EC96DACC4ADD42020911268", + "startDate": "2017-06-23T07:07:51.000Z", + "priceDetails": { + "price": 34.49, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 34.49, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"07AF00C11EC96DACC4ADD42020911268\",\"label\":\"ppro_direct_individual\",\"price\":\"34.49\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ppro_direct_individual", + "productArrangement": { + "productFamily": "PREMIERE" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_MODEL", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "1KfaN_o5h4Gvmvh_QwfK7KB7xGPpNpsTXsdhqpJUT5Y" + ], + "offerId": "43538F47236C326E137A08307BFA70F2", + "startDate": "2015-11-17T20:43:19.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"43538F47236C326E137A08307BFA70F2\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"22.99\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "MkR_-obCKAXTVvDwFzdmlC81ozQ1oxVwvC7uVbaiyB4" + ], + "offerId": "5F2E4A8FD58D70C8860F51A4DE042E0C", + "startDate": "2015-11-17T20:43:19.000Z", + "priceDetails": { + "price": 263.88, + "priceWithoutTax": 263.88, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"5F2E4A8FD58D70C8860F51A4DE042E0C\",\"label\":\"ilst_direct_individual\",\"price\":\"263.88\",\"amountWithoutTax\":\"263.88\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"ANNUAL\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "ANNUAL", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "gJARBXxvCj1u6Csv2qMeLrdHyvEdN3y_6Cvu_uCogQs" + ], + "offerId": "DC7F4D082C8EEEBE4E0F9E6B3CFD7BC0", + "startDate": "2015-11-17T20:43:19.000Z", + "priceDetails": { + "price": 34.49, + "priceWithoutTax": 34.49, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"DC7F4D082C8EEEBE4E0F9E6B3CFD7BC0\",\"label\":\"ilst_direct_individual\",\"price\":\"34.49\",\"amountWithoutTax\":\"34.49\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "ByqyQ6QmyXhzAOnjIcfHcoF1l6nfkeLgbzWz-aeM8GQ", + "illustrator-trial" + ], + "offerId": "C1C12BA6D34A45AB9C1F7836C88DD4F8", + "startDate": "2020-04-20T07:01:00.000Z", + "endDate": "2050-04-08T19:59:00.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"C1C12BA6D34A45AB9C1F7836C88DD4F8\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "zLM1ML9mB8lFrOoTdmNsV9K5-F-n5k8HLYJyE4yonV8", + "premiere-trial" + ], + "offerId": "A3E81CB2F000EA56DB1E25A35C53C15F", + "startDate": "2020-04-20T07:01:00.000Z", + "endDate": "2050-04-08T19:59:00.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 0.0, + "priceWithoutDiscountAndTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"A3E81CB2F000EA56DB1E25A35C53C15F\",\"label\":\"ppro_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"0.0\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ppro_direct_individual", + "productArrangement": { + "productFamily": "PREMIERE" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "TRIAL", + "pricePoint": "TRIAL_TWP3060_60_DAY_TRIAL_FOR_CCI_SINGLE_APPS_WINBACK", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "1KfaN_o5h4Gvmvh_QwfK7KB7xGPpNpsTXsdhqpJUT5Y", + "illustrator" + ], + "offerId": "43538F47236C326E137A08307BFA70F2", + "startDate": "2015-11-17T20:43:19.000Z", + "priceDetails": { + "price": 22.99, + "priceWithoutTax": 22.99, + "usePrecision": true, + "formatString": "'US$'#,##0.00", + "taxDisplay": "TAX_EXCLUSIVE", + "taxTerm": "TAX" + }, + "analytics": "{\"offerId\":\"43538F47236C326E137A08307BFA70F2\",\"label\":\"ilst_direct_individual\",\"price\":\"22.99\",\"amountWithoutTax\":\"22.99\",\"commitmentType\":\"YEAR\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"USD\"}", + "productArrangementCode": "ilst_direct_individual", + "productArrangement": { + "productFamily": "ILLUSTRATOR" + }, + "buyingProgram": "RETAIL", + "commitment": "YEAR", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "MULT", + "merchant": "ADOBE" + } + ] + }, + { + "resolvedOffers": [ + { + "offerSelectorIds": [ + "4z5djtg8zeOjZgMJ3jRwB3Uo1PJh7Y5ZzCADM_AbDDs", + "gb1" + ], + "offerId": "B740D1F2F6369BD1C342E6E372A61B50", + "startDate": "2015-11-17T20:52:25.000Z", + "priceDetails": { + "price": 34.16, + "priceWithoutTax": 28.47, + "usePrecision": true, + "formatString": "'£'#,##0.00", + "taxDisplay": "TAX_INCLUSIVE_DETAILS", + "taxTerm": "VAT" + }, + "analytics": "{\"offerId\":\"B740D1F2F6369BD1C342E6E372A61B50\",\"label\":\"phsp_direct_individual\",\"price\":\"34.16\",\"amountWithoutTax\":\"28.47\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"GBP\"}", + "productArrangementCode": "phsp_direct_individual", + "productArrangement": { + "productFamily": "PHOTOSHOP" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "MULT", + "merchant": "ADOBE" + }, + { + "offerSelectorIds": [ + "4z5djtg8zeOjZgMJ3jRwB3Uo1PJh7Y5ZzCADM_AbDDs" + ], + "offerId": "D0B190C16F2CC5DEC4E549AD696B2D20", + "startDate": "2015-11-17T20:52:25.000Z", + "priceDetails": { + "price": 32.98, + "priceWithoutTax": 27.48, + "usePrecision": true, + "formatString": "'£'#,##0.00", + "taxDisplay": "TAX_INCLUSIVE_DETAILS", + "taxTerm": "VAT" + }, + "analytics": "{\"offerId\":\"D0B190C16F2CC5DEC4E549AD696B2D20\",\"label\":\"phsp_direct_individual\",\"price\":\"32.98\",\"amountWithoutTax\":\"27.48\",\"commitmentType\":\"MONTH\",\"billingFrequency\":\"MONTHLY\",\"currencyCode\":\"GBP\"}", + "productArrangementCode": "phsp_direct_individual", + "productArrangement": { + "productFamily": "PHOTOSHOP" + }, + "buyingProgram": "RETAIL", + "commitment": "MONTH", + "term": "MONTHLY", + "customerSegment": "INDIVIDUAL", + "marketSegments": [ + "COM" + ], + "salesChannel": "DIRECT", + "offerType": "BASE", + "pricePoint": "REGULAR", + "language": "EN", + "merchant": "ADOBE" + } + ] } +] diff --git a/test/features/dynamic-nav/dynamicNav.test.js b/test/features/dynamic-nav/dynamicNav.test.js new file mode 100644 index 0000000000..47b168ccfa --- /dev/null +++ b/test/features/dynamic-nav/dynamicNav.test.js @@ -0,0 +1,48 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import { setConfig } from '../../../libs/utils/utils.js'; +import dynamicNav from '../../../libs/features/dynamic-navigation.js'; + +describe('Dynamic nav', () => { + beforeEach(() => { + const conf = { dynamicNavKey: 'bacom' }; + setConfig(conf); + window.sessionStorage.setItem('gnavSource', 'some-source-string'); + }); + + it('Saves the gnavSource and dynamicNavKey to session storage', async () => { + document.head.innerHTML = await readFile({ path: './mocks/entry.html' }); + window.sessionStorage.removeItem('gnavSource'); + dynamicNav('gnav/aem-sites', 'bacom'); + expect(window.sessionStorage.getItem('gnavSource')).to.equal('gnav/aem-sites'); + expect(window.sessionStorage.getItem('dynamicNavKey')).to.equal('bacom'); + }); + + it('Returns the provided url when the dynamic nav metadata is not present', async () => { + document.head.innerHTML = await readFile({ path: './mocks/off.html' }); + const url = dynamicNav('gnav/aem-sites', 'nocom'); + expect(window.sessionStorage.getItem('gnavSource')).to.equal('some-source-string'); + expect(url).to.equal('gnav/aem-sites'); + }); + + it('Returns the provided url with when the wrong dynamicNavKey is passed', async () => { + document.head.innerHTML = await readFile({ path: './mocks/on.html' }); + const url = dynamicNav('gnav/aem-sites', 'nocom'); + expect(window.sessionStorage.getItem('gnavSource')).to.equal('some-source-string'); + expect(url).to.equal('gnav/aem-sites'); + }); + + it('Returns the sessionStorage url if the item exists, the keys match, and dynamic nav is on', async () => { + document.head.innerHTML = await readFile({ path: './mocks/on.html' }); + const url = dynamicNav('gnav/aem-sites', 'bacom'); + expect(window.sessionStorage.getItem('gnavSource')).to.equal('some-source-string'); + expect(url).to.equal('some-source-string'); + }); + + it('Returns the pprovided url if it does not find an item in sessionStorage and dynamic nav is on', async () => { + document.head.innerHTML = await readFile({ path: './mocks/on.html' }); + window.sessionStorage.removeItem('gnavSource'); + const url = dynamicNav('gnav/aem-sites', 'bacom'); + expect(url).to.equal('gnav/aem-sites'); + }); +}); diff --git a/test/features/dynamic-nav/mocks/entry.html b/test/features/dynamic-nav/mocks/entry.html new file mode 100644 index 0000000000..aeb74d8121 --- /dev/null +++ b/test/features/dynamic-nav/mocks/entry.html @@ -0,0 +1 @@ + diff --git a/test/features/dynamic-nav/mocks/off.html b/test/features/dynamic-nav/mocks/off.html new file mode 100644 index 0000000000..60feb7b764 --- /dev/null +++ b/test/features/dynamic-nav/mocks/off.html @@ -0,0 +1 @@ + diff --git a/test/features/dynamic-nav/mocks/on.html b/test/features/dynamic-nav/mocks/on.html new file mode 100644 index 0000000000..43ea6ee38b --- /dev/null +++ b/test/features/dynamic-nav/mocks/on.html @@ -0,0 +1 @@ +