From 5af19251aa86cb61c8e2d18ab76802450c5731b3 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Tue, 28 Jan 2025 15:12:55 -0600 Subject: [PATCH 01/25] refactor: update fetchPlaceholders import path and enhance multi-store support --- .../commerce-order-header.js | 2 +- .../commerce-return-header.js | 2 +- blocks/product-details/product-details.js | 2 +- scripts/configs.js | 14 +++++++---- scripts/initializers/account.js | 2 +- scripts/initializers/auth.js | 2 +- scripts/initializers/cart.js | 2 +- scripts/initializers/checkout.js | 2 +- scripts/initializers/order.js | 2 +- scripts/initializers/pdp.js | 4 +-- scripts/scripts.js | 25 +++++++++++++++++++ 11 files changed, 44 insertions(+), 15 deletions(-) diff --git a/blocks/commerce-order-header/commerce-order-header.js b/blocks/commerce-order-header/commerce-order-header.js index 843eb6e0fe..ca5d3b1d9c 100644 --- a/blocks/commerce-order-header/commerce-order-header.js +++ b/blocks/commerce-order-header/commerce-order-header.js @@ -3,7 +3,7 @@ import { events } from '@dropins/tools/event-bus.js'; import { Header, provider as uiProvider } from '@dropins/tools/components.js'; import { CUSTOMER_ORDER_DETAILS_PATH, CUSTOMER_ORDERS_PATH } from '../../scripts/constants.js'; -import { fetchPlaceholders } from '../../scripts/aem.js'; +import { fetchPlaceholders } from '../../scripts/scripts.js'; export default async function decorate(block) { block.innerHTML = ''; diff --git a/blocks/commerce-return-header/commerce-return-header.js b/blocks/commerce-return-header/commerce-return-header.js index 47bf19ea4f..29b58592b6 100644 --- a/blocks/commerce-return-header/commerce-return-header.js +++ b/blocks/commerce-return-header/commerce-return-header.js @@ -3,7 +3,7 @@ import { events } from '@dropins/tools/event-bus.js'; import { Header, provider as uiProvider } from '@dropins/tools/components.js'; import { CUSTOMER_RETURN_DETAILS_PATH, CUSTOMER_RETURNS_PATH } from '../../scripts/constants.js'; -import { fetchPlaceholders } from '../../scripts/aem.js'; +import { fetchPlaceholders } from '../../scripts/scripts.js'; export default async function decorate(block) { block.innerHTML = ''; diff --git a/blocks/product-details/product-details.js b/blocks/product-details/product-details.js index 4125f0e999..27c08a88ca 100644 --- a/blocks/product-details/product-details.js +++ b/blocks/product-details/product-details.js @@ -22,7 +22,7 @@ import ProductGallery from '@dropins/storefront-pdp/containers/ProductGallery.js // Libs import { setJsonLd } from '../../scripts/commerce.js'; -import { fetchPlaceholders } from '../../scripts/aem.js'; +import { fetchPlaceholders } from '../../scripts/scripts.js'; // Initializers import { IMAGES_SIZES } from '../../scripts/initializers/pdp.js'; diff --git a/scripts/configs.js b/scripts/configs.js index 93e69e2cbe..50ac3a0645 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -1,3 +1,5 @@ +import { getRootPath } from './scripts.js'; + const ALLOWED_CONFIGS = ['prod', 'stage', 'dev']; /** @@ -29,21 +31,23 @@ export const calcEnvironment = () => { return environment; }; -function buildConfigURL(environment) { +function buildConfigURL(environment, root = '/') { const env = environment || calcEnvironment(); let fileName = 'configs.json'; if (env !== 'prod') { fileName = `configs-${env}.json`; } - const configURL = new URL(`${window.location.origin}/${fileName}`); + + const configURL = new URL(`${window.location.origin}${root}${fileName}`); return configURL; } const getConfigForEnvironment = async (environment) => { const env = environment || calcEnvironment(); + const root = getRootPath(); try { - const configJSON = window.sessionStorage.getItem(`config:${env}`); + const configJSON = window.sessionStorage.getItem(`config:${env}:${root}:${root}`); if (!configJSON) { throw new Error('No config in session storage'); } @@ -55,13 +59,13 @@ const getConfigForEnvironment = async (environment) => { return parsedConfig; } catch (e) { - let configJSON = await fetch(buildConfigURL(env)); + let configJSON = await fetch(buildConfigURL(env, root)); if (!configJSON.ok) { throw new Error(`Failed to fetch config for ${env}`); } configJSON = await configJSON.json(); configJSON[':expiry'] = Math.round(Date.now() / 1000) + 7200; - window.sessionStorage.setItem(`config:${env}`, JSON.stringify(configJSON)); + window.sessionStorage.setItem(`config:${env}:${root}`, JSON.stringify(configJSON)); return configJSON; } }; diff --git a/scripts/initializers/account.js b/scripts/initializers/account.js index 87423cbb41..b6688fe1db 100644 --- a/scripts/initializers/account.js +++ b/scripts/initializers/account.js @@ -1,7 +1,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-account/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../aem.js'; +import { fetchPlaceholders } from '../scripts.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/auth.js b/scripts/initializers/auth.js index 91f243fe4d..3196d9a7fa 100644 --- a/scripts/initializers/auth.js +++ b/scripts/initializers/auth.js @@ -2,7 +2,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-auth/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../aem.js'; +import { fetchPlaceholders } from '../scripts.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/cart.js b/scripts/initializers/cart.js index 71703a5891..135ca94928 100644 --- a/scripts/initializers/cart.js +++ b/scripts/initializers/cart.js @@ -2,7 +2,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-cart/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../aem.js'; +import { fetchPlaceholders } from '../scripts.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/checkout.js b/scripts/initializers/checkout.js index 857b61ff4c..1360b31d51 100644 --- a/scripts/initializers/checkout.js +++ b/scripts/initializers/checkout.js @@ -1,7 +1,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-checkout/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../aem.js'; +import { fetchPlaceholders } from '../scripts.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/order.js b/scripts/initializers/order.js index 6a10da04df..d720394816 100644 --- a/scripts/initializers/order.js +++ b/scripts/initializers/order.js @@ -3,7 +3,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-order/api.js'; import { checkIsAuthenticated, getHeaders } from '../configs.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../aem.js'; +import { fetchPlaceholders } from '../scripts.js'; import { CUSTOMER_ORDER_DETAILS_PATH, diff --git a/scripts/initializers/pdp.js b/scripts/initializers/pdp.js index 2b5223e26f..231b690f9e 100644 --- a/scripts/initializers/pdp.js +++ b/scripts/initializers/pdp.js @@ -1,5 +1,5 @@ +/* eslint-disable import/no-cycle */ /* eslint-disable import/prefer-default-export */ -/* eslint import/no-cycle: [2, { maxDepth: 1 }] */ import { initializers } from '@dropins/tools/initializer.js'; import { Image, provider as UI } from '@dropins/tools/components.js'; @@ -17,7 +17,7 @@ import { loadErrorPage, } from '../commerce.js'; import { getHeaders } from '../configs.js'; -import { fetchPlaceholders } from '../aem.js'; +import { fetchPlaceholders } from '../scripts.js'; export const IMAGES_SIZES = { width: 960, diff --git a/scripts/scripts.js b/scripts/scripts.js index d2edf055ec..b8199c66f6 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -20,6 +20,7 @@ import { loadSections, loadCSS, sampleRUM, + fetchPlaceholders as _fetchPlaceholders, } from './aem.js'; import { trackHistory } from './commerce.js'; import initializeDropins from './initializers/index.js'; @@ -356,6 +357,30 @@ export async function fetchIndex(indexFile, pageSize = 500) { return newIndex; } +/** + * Get root path + */ +export function getRootPath() { + return window.localStorage.getItem('root_path') ?? '/'; +} + +/** + * Set root path + */ +export function setRootPath(root) { + window.localStorage.setItem('root_path', root); +} + +/** + * Fetch Placeholders with multi-store support. + */ +export async function fetchPlaceholders() { + const root = getRootPath().replace(/\/$/, ''); // remove trailing slash + const requests = [_fetchPlaceholders(), _fetchPlaceholders(root)]; + const [placeholders, placeholdersRoot = {}] = await Promise.all(requests); + return { ...placeholders, ...placeholdersRoot }; +} + /** * Check if consent was given for a specific topic. * @param {*} topic Topic identifier From 6d845e699e8adbd1b427a7eee98242bfe7c5bb97 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Tue, 28 Jan 2025 15:15:11 -0600 Subject: [PATCH 02/25] fix: disable eslint rule for cyclic imports in configs.js --- scripts/configs.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/configs.js b/scripts/configs.js index 50ac3a0645..c44bda794c 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -1,3 +1,5 @@ +/* eslint-disable import/no-cycle */ + import { getRootPath } from './scripts.js'; const ALLOWED_CONFIGS = ['prod', 'stage', 'dev']; From a60bc9c58941ed1ce5291c34f55ee643c84c6721 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Tue, 28 Jan 2025 15:36:14 -0600 Subject: [PATCH 03/25] refactor: update fetchPlaceholders function for improved multi-store support and remove unused preload link --- head.html | 1 - scripts/scripts.js | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/head.html b/head.html index 756a1871d9..53dd9769e9 100644 --- a/head.html +++ b/head.html @@ -31,7 +31,6 @@ - diff --git a/scripts/scripts.js b/scripts/scripts.js index b8199c66f6..c40ac52478 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -375,10 +375,12 @@ export function setRootPath(root) { * Fetch Placeholders with multi-store support. */ export async function fetchPlaceholders() { - const root = getRootPath().replace(/\/$/, ''); // remove trailing slash - const requests = [_fetchPlaceholders(), _fetchPlaceholders(root)]; - const [placeholders, placeholdersRoot = {}] = await Promise.all(requests); - return { ...placeholders, ...placeholdersRoot }; + const market = getRootPath().replace(/\/$/, '') ?? undefined; + const lang = market ? `/${market.split('/')[1]}` : undefined; + const requests = [_fetchPlaceholders(lang)]; + if (market) requests.push(_fetchPlaceholders(market)); + const [langPlaceholders, marketPlaceholders = {}] = await Promise.all(requests); + return { ...langPlaceholders, ...marketPlaceholders }; } /** From 1433d1aa03f33bce1d04a1d323543552d1486674 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Tue, 28 Jan 2025 17:11:55 -0600 Subject: [PATCH 04/25] index all pages in the two-tiers structure --- helix-query.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/helix-query.yaml b/helix-query.yaml index 03533b45e3..bf4d2cbfd7 100644 --- a/helix-query.yaml +++ b/helix-query.yaml @@ -52,3 +52,16 @@ indices: select: head > meta[name="enrichment-positions"] values: | match(attribute(el, 'content'), '([^,]+)') + tiers: + parget: /tiers.json + include: + - '**/**/**' + properties: + title: + select: head > meta[property="og:title"] + value: | + attribute(el, 'content') + path: + select: none + value: | + path \ No newline at end of file From 4174060d7b07c456978a924e045ccfaafad278db Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Tue, 28 Jan 2025 17:23:30 -0600 Subject: [PATCH 05/25] refactor: update helix-query.yaml to exclude drafts, enrichment, and fragments from indexing --- helix-query.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/helix-query.yaml b/helix-query.yaml index bf4d2cbfd7..e5ea8038c3 100644 --- a/helix-query.yaml +++ b/helix-query.yaml @@ -54,8 +54,10 @@ indices: match(attribute(el, 'content'), '([^,]+)') tiers: parget: /tiers.json - include: - - '**/**/**' + exclude: + - 'drafts/**' + - 'enrichment/**' + - 'fragments/**' properties: title: select: head > meta[property="og:title"] From 3ef24518ebd5e22ed2c21d42cf065a8fd101965b Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Thu, 30 Jan 2025 14:01:56 -0600 Subject: [PATCH 06/25] refactor: remove tiers configuration from helix-query.yaml --- helix-query.yaml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/helix-query.yaml b/helix-query.yaml index e5ea8038c3..03533b45e3 100644 --- a/helix-query.yaml +++ b/helix-query.yaml @@ -52,18 +52,3 @@ indices: select: head > meta[name="enrichment-positions"] values: | match(attribute(el, 'content'), '([^,]+)') - tiers: - parget: /tiers.json - exclude: - - 'drafts/**' - - 'enrichment/**' - - 'fragments/**' - properties: - title: - select: head > meta[property="og:title"] - value: | - attribute(el, 'content') - path: - select: none - value: | - path \ No newline at end of file From 5517558392c7e47b95de16275c216a8ea2d903b6 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Thu, 30 Jan 2025 14:04:52 -0600 Subject: [PATCH 07/25] refactor: simplify buildConfigURL and remove unused root path handling in configs.js --- scripts/configs.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/scripts/configs.js b/scripts/configs.js index c44bda794c..fca5162f28 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -1,7 +1,3 @@ -/* eslint-disable import/no-cycle */ - -import { getRootPath } from './scripts.js'; - const ALLOWED_CONFIGS = ['prod', 'stage', 'dev']; /** @@ -33,23 +29,21 @@ export const calcEnvironment = () => { return environment; }; -function buildConfigURL(environment, root = '/') { +function buildConfigURL(environment) { const env = environment || calcEnvironment(); let fileName = 'configs.json'; if (env !== 'prod') { fileName = `configs-${env}.json`; } - - const configURL = new URL(`${window.location.origin}${root}${fileName}`); + const configURL = new URL(`${window.location.origin}/${fileName}`); return configURL; } const getConfigForEnvironment = async (environment) => { const env = environment || calcEnvironment(); - const root = getRootPath(); try { - const configJSON = window.sessionStorage.getItem(`config:${env}:${root}:${root}`); + const configJSON = window.sessionStorage.getItem(`config:${env}`); if (!configJSON) { throw new Error('No config in session storage'); } @@ -61,13 +55,13 @@ const getConfigForEnvironment = async (environment) => { return parsedConfig; } catch (e) { - let configJSON = await fetch(buildConfigURL(env, root)); + let configJSON = await fetch(buildConfigURL(env)); if (!configJSON.ok) { throw new Error(`Failed to fetch config for ${env}`); } configJSON = await configJSON.json(); configJSON[':expiry'] = Math.round(Date.now() / 1000) + 7200; - window.sessionStorage.setItem(`config:${env}:${root}`, JSON.stringify(configJSON)); + window.sessionStorage.setItem(`config:${env}`, JSON.stringify(configJSON)); return configJSON; } }; @@ -118,4 +112,4 @@ export const getCookie = (cookieName) => { return foundValue; }; -export const checkIsAuthenticated = () => !!getCookie('auth_dropin_user_token') ?? false; +export const checkIsAuthenticated = () => !!getCookie('auth_dropin_user_token') ?? false; \ No newline at end of file From 09f2ed1e775149a5d6848845d1376fbf6dc13be8 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Thu, 30 Jan 2025 14:05:25 -0600 Subject: [PATCH 08/25] fix: ensure checkIsAuthenticated returns a boolean value --- scripts/configs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/configs.js b/scripts/configs.js index fca5162f28..93e69e2cbe 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -112,4 +112,4 @@ export const getCookie = (cookieName) => { return foundValue; }; -export const checkIsAuthenticated = () => !!getCookie('auth_dropin_user_token') ?? false; \ No newline at end of file +export const checkIsAuthenticated = () => !!getCookie('auth_dropin_user_token') ?? false; From f50a66e3594e60b9a6310df95c840b54afbd4296 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Thu, 30 Jan 2025 15:57:58 -0600 Subject: [PATCH 09/25] refactor: enhance buildConfigURL to accept dynamic root path and update session storage keys --- scripts/configs.js | 23 +++++++++++++++++------ scripts/scripts.js | 10 ++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/scripts/configs.js b/scripts/configs.js index 93e69e2cbe..1b7837f23b 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -1,3 +1,5 @@ +import { getRootPath } from './scripts.js'; + const ALLOWED_CONFIGS = ['prod', 'stage', 'dev']; /** @@ -29,21 +31,22 @@ export const calcEnvironment = () => { return environment; }; -function buildConfigURL(environment) { +function buildConfigURL(environment, root = '/') { const env = environment || calcEnvironment(); let fileName = 'configs.json'; if (env !== 'prod') { fileName = `configs-${env}.json`; } - const configURL = new URL(`${window.location.origin}/${fileName}`); + const configURL = new URL(`${window.location.origin}${root}${fileName}`); return configURL; } const getConfigForEnvironment = async (environment) => { const env = environment || calcEnvironment(); + const root = getRootPath() || '/'; try { - const configJSON = window.sessionStorage.getItem(`config:${env}`); + const configJSON = window.sessionStorage.getItem(`config:${env}:${root}:${root}`); if (!configJSON) { throw new Error('No config in session storage'); } @@ -55,13 +58,13 @@ const getConfigForEnvironment = async (environment) => { return parsedConfig; } catch (e) { - let configJSON = await fetch(buildConfigURL(env)); + let configJSON = await fetch(buildConfigURL(env, root)); if (!configJSON.ok) { throw new Error(`Failed to fetch config for ${env}`); } configJSON = await configJSON.json(); configJSON[':expiry'] = Math.round(Date.now() / 1000) + 7200; - window.sessionStorage.setItem(`config:${env}`, JSON.stringify(configJSON)); + window.sessionStorage.setItem(`config:${env}:${root}`, JSON.stringify(configJSON)); return configJSON; } }; @@ -87,13 +90,21 @@ export const getConfigValue = async (configParam, environment) => { export const getHeaders = async (scope, environment) => { const env = environment || calcEnvironment(); const config = await getConfigForEnvironment(env); - const configElements = config.data.filter((el) => el?.key.includes(`headers.${scope}`)); + const configElements = config.data.filter((el) => el?.key.includes('headers.all') || el?.key.includes(`headers.${scope}`)); return configElements.reduce((obj, item) => { let { key } = item; + + // global values + if (key.includes('commerce.headers.all.')) { + key = key.replace('commerce.headers.all.', ''); + } + + // scoped values if (key.includes(`commerce.headers.${scope}.`)) { key = key.replace(`commerce.headers.${scope}.`, ''); } + return { ...obj, [key]: item.value }; }, {}); }; diff --git a/scripts/scripts.js b/scripts/scripts.js index c40ac52478..8e35367fca 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -361,14 +361,8 @@ export async function fetchIndex(indexFile, pageSize = 500) { * Get root path */ export function getRootPath() { - return window.localStorage.getItem('root_path') ?? '/'; -} - -/** - * Set root path - */ -export function setRootPath(root) { - window.localStorage.setItem('root_path', root); + window.ROOT_PATH = window.rootPath || getMetadata('root') || '/'; + return window.ROOT_PATH; } /** From 6bccb24733be745deee71faa157ac35f0ad784cb Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Thu, 30 Jan 2025 16:08:57 -0600 Subject: [PATCH 10/25] refactor: simplify fetchPlaceholders to support single store fetching --- scripts/scripts.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/scripts.js b/scripts/scripts.js index 8e35367fca..9b756c3208 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -369,12 +369,8 @@ export function getRootPath() { * Fetch Placeholders with multi-store support. */ export async function fetchPlaceholders() { - const market = getRootPath().replace(/\/$/, '') ?? undefined; - const lang = market ? `/${market.split('/')[1]}` : undefined; - const requests = [_fetchPlaceholders(lang)]; - if (market) requests.push(_fetchPlaceholders(market)); - const [langPlaceholders, marketPlaceholders = {}] = await Promise.all(requests); - return { ...langPlaceholders, ...marketPlaceholders }; + const lang = getRootPath().replace(/\/$/, '') ?? undefined; + return _fetchPlaceholders(lang); } /** From f7458e3771e3555b05b5f88522faa22a6bce8f01 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Thu, 30 Jan 2025 16:31:06 -0600 Subject: [PATCH 11/25] refactor: update fetchPlaceholders import paths to use aem.js --- blocks/commerce-order-header/commerce-order-header.js | 2 +- blocks/commerce-return-header/commerce-return-header.js | 2 +- blocks/product-details/product-details.js | 2 +- scripts/configs.js | 2 ++ scripts/initializers/account.js | 2 +- scripts/initializers/auth.js | 2 +- scripts/initializers/cart.js | 2 +- scripts/initializers/checkout.js | 2 +- scripts/initializers/order.js | 2 +- scripts/initializers/pdp.js | 2 +- scripts/scripts.js | 9 --------- 11 files changed, 11 insertions(+), 18 deletions(-) diff --git a/blocks/commerce-order-header/commerce-order-header.js b/blocks/commerce-order-header/commerce-order-header.js index ca5d3b1d9c..843eb6e0fe 100644 --- a/blocks/commerce-order-header/commerce-order-header.js +++ b/blocks/commerce-order-header/commerce-order-header.js @@ -3,7 +3,7 @@ import { events } from '@dropins/tools/event-bus.js'; import { Header, provider as uiProvider } from '@dropins/tools/components.js'; import { CUSTOMER_ORDER_DETAILS_PATH, CUSTOMER_ORDERS_PATH } from '../../scripts/constants.js'; -import { fetchPlaceholders } from '../../scripts/scripts.js'; +import { fetchPlaceholders } from '../../scripts/aem.js'; export default async function decorate(block) { block.innerHTML = ''; diff --git a/blocks/commerce-return-header/commerce-return-header.js b/blocks/commerce-return-header/commerce-return-header.js index 29b58592b6..47bf19ea4f 100644 --- a/blocks/commerce-return-header/commerce-return-header.js +++ b/blocks/commerce-return-header/commerce-return-header.js @@ -3,7 +3,7 @@ import { events } from '@dropins/tools/event-bus.js'; import { Header, provider as uiProvider } from '@dropins/tools/components.js'; import { CUSTOMER_RETURN_DETAILS_PATH, CUSTOMER_RETURNS_PATH } from '../../scripts/constants.js'; -import { fetchPlaceholders } from '../../scripts/scripts.js'; +import { fetchPlaceholders } from '../../scripts/aem.js'; export default async function decorate(block) { block.innerHTML = ''; diff --git a/blocks/product-details/product-details.js b/blocks/product-details/product-details.js index 27c08a88ca..4125f0e999 100644 --- a/blocks/product-details/product-details.js +++ b/blocks/product-details/product-details.js @@ -22,7 +22,7 @@ import ProductGallery from '@dropins/storefront-pdp/containers/ProductGallery.js // Libs import { setJsonLd } from '../../scripts/commerce.js'; -import { fetchPlaceholders } from '../../scripts/scripts.js'; +import { fetchPlaceholders } from '../../scripts/aem.js'; // Initializers import { IMAGES_SIZES } from '../../scripts/initializers/pdp.js'; diff --git a/scripts/configs.js b/scripts/configs.js index 1b7837f23b..413d223b8f 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -1,3 +1,5 @@ +/* eslint-disable import/no-cycle */ + import { getRootPath } from './scripts.js'; const ALLOWED_CONFIGS = ['prod', 'stage', 'dev']; diff --git a/scripts/initializers/account.js b/scripts/initializers/account.js index b6688fe1db..87423cbb41 100644 --- a/scripts/initializers/account.js +++ b/scripts/initializers/account.js @@ -1,7 +1,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-account/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../scripts.js'; +import { fetchPlaceholders } from '../aem.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/auth.js b/scripts/initializers/auth.js index 3196d9a7fa..91f243fe4d 100644 --- a/scripts/initializers/auth.js +++ b/scripts/initializers/auth.js @@ -2,7 +2,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-auth/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../scripts.js'; +import { fetchPlaceholders } from '../aem.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/cart.js b/scripts/initializers/cart.js index 135ca94928..71703a5891 100644 --- a/scripts/initializers/cart.js +++ b/scripts/initializers/cart.js @@ -2,7 +2,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-cart/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../scripts.js'; +import { fetchPlaceholders } from '../aem.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/checkout.js b/scripts/initializers/checkout.js index 1360b31d51..857b61ff4c 100644 --- a/scripts/initializers/checkout.js +++ b/scripts/initializers/checkout.js @@ -1,7 +1,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-checkout/api.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../scripts.js'; +import { fetchPlaceholders } from '../aem.js'; import { getHeaders } from '../configs.js'; await initializeDropin(async () => { diff --git a/scripts/initializers/order.js b/scripts/initializers/order.js index d720394816..6a10da04df 100644 --- a/scripts/initializers/order.js +++ b/scripts/initializers/order.js @@ -3,7 +3,7 @@ import { initializers } from '@dropins/tools/initializer.js'; import { initialize, setFetchGraphQlHeaders } from '@dropins/storefront-order/api.js'; import { checkIsAuthenticated, getHeaders } from '../configs.js'; import { initializeDropin } from './index.js'; -import { fetchPlaceholders } from '../scripts.js'; +import { fetchPlaceholders } from '../aem.js'; import { CUSTOMER_ORDER_DETAILS_PATH, diff --git a/scripts/initializers/pdp.js b/scripts/initializers/pdp.js index 231b690f9e..8871141599 100644 --- a/scripts/initializers/pdp.js +++ b/scripts/initializers/pdp.js @@ -17,7 +17,7 @@ import { loadErrorPage, } from '../commerce.js'; import { getHeaders } from '../configs.js'; -import { fetchPlaceholders } from '../scripts.js'; +import { fetchPlaceholders } from '../aem.js'; export const IMAGES_SIZES = { width: 960, diff --git a/scripts/scripts.js b/scripts/scripts.js index 9b756c3208..3e358baef2 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -20,7 +20,6 @@ import { loadSections, loadCSS, sampleRUM, - fetchPlaceholders as _fetchPlaceholders, } from './aem.js'; import { trackHistory } from './commerce.js'; import initializeDropins from './initializers/index.js'; @@ -365,14 +364,6 @@ export function getRootPath() { return window.ROOT_PATH; } -/** - * Fetch Placeholders with multi-store support. - */ -export async function fetchPlaceholders() { - const lang = getRootPath().replace(/\/$/, '') ?? undefined; - return _fetchPlaceholders(lang); -} - /** * Check if consent was given for a specific topic. * @param {*} topic Topic identifier From 4af4b69cfaa74b0d6272ab17ab96de77b6cd55c6 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" <316104+fnhipster@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:40:49 -0600 Subject: [PATCH 12/25] Update scripts/configs.js Co-authored-by: Stephen --- scripts/configs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/configs.js b/scripts/configs.js index 413d223b8f..95dd232739 100644 --- a/scripts/configs.js +++ b/scripts/configs.js @@ -48,7 +48,7 @@ const getConfigForEnvironment = async (environment) => { const root = getRootPath() || '/'; try { - const configJSON = window.sessionStorage.getItem(`config:${env}:${root}:${root}`); + const configJSON = window.sessionStorage.getItem(`config:${env}:${root}`); if (!configJSON) { throw new Error('No config in session storage'); } From 30be7c534814d83429c2a80a0ae229e964474a9f Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Fri, 31 Jan 2025 10:24:09 -0600 Subject: [PATCH 13/25] refactor: enhance fetchPlaceholders to support multiple source fetching and caching --- scripts/aem.js | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/scripts/aem.js b/scripts/aem.js index ec275180fb..75c0a7eed9 100644 --- a/scripts/aem.js +++ b/scripts/aem.js @@ -503,20 +503,35 @@ function decorateSections(main) { */ // eslint-disable-next-line import/prefer-default-export async function fetchPlaceholders(prefix = 'default') { + const overrides = getMetadata('placeholders') || []; + const [fallback, override] = overrides.split('\n'); window.placeholders = window.placeholders || {}; if (!window.placeholders[prefix]) { window.placeholders[prefix] = new Promise((resolve) => { - const url = getMetadata('placeholders') || `${prefix === 'default' ? '' : prefix}/placeholders.json`; - fetch(url) - .then((resp) => { + const url = fallback || `${prefix === 'default' ? '' : prefix}/placeholders.json`; + Promise.all([fetch(url), override ? fetch(override) : Promise.resolve()]) + .then(async ([resp, oResp]) => { if (resp.ok) { - return resp.json(); + if (oResp?.ok) { + return Promise.all([resp.json(), await oResp.json()]); + } + return Promise.all([resp.json(), {}]); } return {}; }) - .then((json) => { + + .then(([json, oJson]) => { const placeholders = {}; + // build placeholders object json.data.forEach(({ Key, Value }) => { + // check for overrides + if (oJson?.data) { + const overrideItem = oJson.data.find((item) => item.Key === Key); + if (overrideItem) { + // eslint-disable-next-line no-param-reassign + Value = overrideItem.Value; + } + } if (Key) { const keys = Key.split('.'); const lastKey = keys.pop(); @@ -527,10 +542,13 @@ async function fetchPlaceholders(prefix = 'default') { target[lastKey] = Value; } }); + // cache placeholders window.placeholders[prefix] = placeholders; + // return placeholders resolve(window.placeholders[prefix]); }) - .catch(() => { + .catch((error) => { + console.error('error loading placeholders', error); // error loading placeholders window.placeholders[prefix] = {}; resolve(window.placeholders[prefix]); From 396deb28521c55c21f5af2daed2940e9f9880ede Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Fri, 31 Jan 2025 12:28:51 -0600 Subject: [PATCH 14/25] refactor: update fetchPlaceholders to handle empty string for overrides --- scripts/aem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/aem.js b/scripts/aem.js index 75c0a7eed9..825d2e680e 100644 --- a/scripts/aem.js +++ b/scripts/aem.js @@ -503,7 +503,7 @@ function decorateSections(main) { */ // eslint-disable-next-line import/prefer-default-export async function fetchPlaceholders(prefix = 'default') { - const overrides = getMetadata('placeholders') || []; + const overrides = getMetadata('placeholders') || ''; const [fallback, override] = overrides.split('\n'); window.placeholders = window.placeholders || {}; if (!window.placeholders[prefix]) { From a0fa27a462669cf756371e32eba512ccb845c5bb Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Fri, 31 Jan 2025 15:04:39 -0600 Subject: [PATCH 15/25] refactor: update loadFragment to use getRootPath for dynamic URL construction --- blocks/fragment/fragment.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/blocks/fragment/fragment.js b/blocks/fragment/fragment.js index ed8ba22f6d..c86061cd83 100644 --- a/blocks/fragment/fragment.js +++ b/blocks/fragment/fragment.js @@ -7,6 +7,7 @@ import { decorateMain, + getRootPath, } from '../../scripts/scripts.js'; import { @@ -20,7 +21,9 @@ import { */ export async function loadFragment(path) { if (path && path.startsWith('/')) { - const resp = await fetch(`${path}.plain.html`); + const root = getRootPath().replace(/\/$/, ''); + const url = `${root}${path}.plain.html`; + const resp = await fetch(url); if (resp.ok) { const main = document.createElement('main'); main.innerHTML = await resp.text(); From 5f7882904f45e61728b7cd3f2d7ec5020af4e91f Mon Sep 17 00:00:00 2001 From: Anthoula Wojczak Date: Fri, 31 Jan 2025 16:32:54 -0600 Subject: [PATCH 16/25] USF-1918: Sharepoint documents have a two-tier structure with English as the default - decorate links for EDS pages - localize links for Blocks --- .../commerce-mini-cart/commerce-mini-cart.js | 3 +- scripts/scripts.js | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/blocks/commerce-mini-cart/commerce-mini-cart.js b/blocks/commerce-mini-cart/commerce-mini-cart.js index 11c05b094f..dd0e25d1ea 100644 --- a/blocks/commerce-mini-cart/commerce-mini-cart.js +++ b/blocks/commerce-mini-cart/commerce-mini-cart.js @@ -5,6 +5,7 @@ import MiniCart from '@dropins/storefront-cart/containers/MiniCart.js'; import '../../scripts/initializers/cart.js'; import { readBlockConfig } from '../../scripts/aem.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { const { @@ -18,7 +19,7 @@ export default async function decorate(block) { return provider.render(MiniCart, { routeEmptyCartCTA: startShoppingURL ? () => startShoppingURL : undefined, routeCart: cartURL ? () => cartURL : undefined, - routeCheckout: checkoutURL ? () => checkoutURL : undefined, + routeCheckout: checkoutURL ? () => localizeLink(checkoutURL) : undefined, routeProduct: (product) => `/products/${product.url.urlKey}/${product.topLevelSku}`, })(block); } diff --git a/scripts/scripts.js b/scripts/scripts.js index 3e358baef2..92245b1149 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -150,6 +150,7 @@ export function decorateMain(main) { buildAutoBlocks(main); decorateSections(main); decorateBlocks(main); + decorateLinks(main); } function preloadFile(href, as) { @@ -364,6 +365,37 @@ export function getRootPath() { return window.ROOT_PATH; } +/** + * Decorates links. + * @param {Element} main The main element + */ +export function decorateLinks(main) { + const root = getRootPath(); + if (root === '/') return; + const links = main.querySelectorAll('a'); + + links.forEach((link) => { + if (link.href.startsWith('//' || link.href.startsWith(root))) return; + + if ( + link.href.startsWith('/') + || link.href.startsWith(window.location.origin) + ) { + const url = new URL(link.href, window.location.origin); + link.href = `${root}${url.pathname.substring(1)}${url.search}${url.hash}`; + } + }); +} + +/** + * Decorates links. + * @param {string} [url] url to be localized + */ +export function localizeLink(link) { + const root = getRootPath().replace(/\/$/, ''); + return `${root}${link}`; +} + /** * Check if consent was given for a specific topic. * @param {*} topic Topic identifier From 9156bd907581ed3e1463e2dc2d193df861a3f031 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Sat, 1 Feb 2025 10:34:38 -0600 Subject: [PATCH 17/25] fix: correct logical condition for link href validation --- scripts/scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scripts.js b/scripts/scripts.js index 92245b1149..b503c6c0d1 100644 --- a/scripts/scripts.js +++ b/scripts/scripts.js @@ -375,7 +375,7 @@ export function decorateLinks(main) { const links = main.querySelectorAll('a'); links.forEach((link) => { - if (link.href.startsWith('//' || link.href.startsWith(root))) return; + if (link.href.startsWith('//') || link.href.startsWith(root)) return; if ( link.href.startsWith('/') From 7e9133b9bdde8032f3a12e9eff78dc2c436da6b8 Mon Sep 17 00:00:00 2001 From: Anthoula Wojczak Date: Mon, 3 Feb 2025 15:08:33 -0600 Subject: [PATCH 18/25] USF-1918: Sharepoint documents have a two-tier structure with English as the default - localize links for Blocks --- .../commerce-account-sidebar.js | 5 +++-- blocks/commerce-cart/commerce-cart.js | 11 ++++++----- blocks/commerce-checkout/commerce-checkout.js | 11 ++++++----- .../commerce-mini-cart/commerce-mini-cart.js | 6 +++--- .../commerce-order-product-list.js | 3 ++- .../commerce-order-returns.js | 3 ++- .../commerce-orders-list.js | 3 ++- .../commerce-returns-list.js | 3 ++- .../commerce-shipping-status.js | 5 +++-- blocks/header/renderAuthCombine.js | 3 ++- blocks/header/renderAuthDropdown.js | 7 ++++--- blocks/header/searchbar.js | 5 +++-- blocks/product-details/product-details.js | 5 +++-- .../product-list-page-custom.js | 3 ++- blocks/product-list-page/product-list-page.js | 3 ++- scripts/constants.js | 18 ++++++++++-------- 16 files changed, 55 insertions(+), 39 deletions(-) diff --git a/blocks/commerce-account-sidebar/commerce-account-sidebar.js b/blocks/commerce-account-sidebar/commerce-account-sidebar.js index b953ec49e2..3971561146 100644 --- a/blocks/commerce-account-sidebar/commerce-account-sidebar.js +++ b/blocks/commerce-account-sidebar/commerce-account-sidebar.js @@ -2,6 +2,7 @@ import { Icon, provider as uiProvider } from '@dropins/tools/components.js'; import { render as accountRenderer } from '@dropins/storefront-account/render.js'; import { loadFragment } from '../fragment/fragment.js'; import { CUSTOMER_ORDERS_PATH } from '../../scripts/constants.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { const fragment = await loadFragment('/customer/sidebar-fragment'); @@ -11,13 +12,13 @@ export default async function decorate(block) { const itemConfig = { itemTitle: item.childNodes[0]?.textContent.trim() || 'Default Title', itemSubtitle: itemParams[0]?.innerText || '', - itemLink: itemParams[1]?.innerText || '#', + itemLink: itemParams[1]?.innerText || localizeLink('#'), itemIcon: itemParams[2]?.innerText || 'Placeholder', }; const menuItemEl = document.createElement('a'); menuItemEl.classList.add('commerce-account-sidebar-item'); - menuItemEl.href = itemConfig.itemLink; + menuItemEl.href = localizeLink(itemConfig.itemLink); const isItemActive = ( itemConfig.itemLink === CUSTOMER_ORDERS_PATH diff --git a/blocks/commerce-cart/commerce-cart.js b/blocks/commerce-cart/commerce-cart.js index bc1daf387e..168dd1f63e 100644 --- a/blocks/commerce-cart/commerce-cart.js +++ b/blocks/commerce-cart/commerce-cart.js @@ -16,6 +16,7 @@ import { publishShoppingCartViewEvent } from '@dropins/storefront-cart/api.js'; import '../../scripts/initializers/cart.js'; import { readBlockConfig } from '../../scripts/aem.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { // Configuration @@ -74,8 +75,8 @@ export default async function decorate(block) { // Cart List provider.render(CartSummaryList, { hideHeading: hideHeading === 'true', - routeProduct: (product) => `/products/${product.url.urlKey}/${product.topLevelSku}`, - routeEmptyCartCTA: startShoppingURL ? () => startShoppingURL : undefined, + routeProduct: (product) => localizeLink(`/products/${product.url.urlKey}/${product.topLevelSku}`), + routeEmptyCartCTA: startShoppingURL ? () => localizeLink(startShoppingURL) : undefined, maxItems: parseInt(maxItems, 10) || undefined, attributesToHide: hideAttributes.split(',').map((attr) => attr.trim().toLowerCase()), enableUpdateItemQuantity: enableUpdateItemQuantity === 'true', @@ -84,8 +85,8 @@ export default async function decorate(block) { // Order Summary provider.render(OrderSummary, { - routeProduct: (product) => `/products/${product.url.urlKey}/${product.topLevelSku}`, - routeCheckout: checkoutURL ? () => checkoutURL : undefined, + routeProduct: (product) => localizeLink(`/products/${product.url.urlKey}/${product.topLevelSku}`), + routeCheckout: checkoutURL ? () => localizeLink(checkoutURL) : undefined, slots: { EstimateShipping: async (ctx) => { if (enableEstimateShipping === 'true') { @@ -106,7 +107,7 @@ export default async function decorate(block) { // Empty Cart provider.render(EmptyCart, { - routeCTA: startShoppingURL ? () => startShoppingURL : undefined, + routeCTA: startShoppingURL ? () => localizeLink(startShoppingURL) : undefined, })($emptyCart), ]); diff --git a/blocks/commerce-checkout/commerce-checkout.js b/blocks/commerce-checkout/commerce-checkout.js index a20ba410ed..376344a0b4 100644 --- a/blocks/commerce-checkout/commerce-checkout.js +++ b/blocks/commerce-checkout/commerce-checkout.js @@ -70,6 +70,7 @@ import { scrollToElement, setAddressOnCart, } from '../../scripts/checkout.js'; +import { localizeLink } from '../../scripts/scripts.js'; function createMetaTag(property, content, type) { if (!property || !type) { @@ -231,7 +232,7 @@ export default async function decorate(block) { })($serverError), CheckoutProvider.render(OutOfStock, { - routeCart: () => '/cart', + routeCart: () => localizeLink('/cart'), onCartProductsUpdate: (items) => { cartApi.updateProductsFromCart(items).catch(console.error); }, @@ -333,7 +334,7 @@ export default async function decorate(block) { ); const editCartLink = document.createElement('a'); editCartLink.classList.add('cart-summary-list__edit'); - editCartLink.href = '/cart'; + editCartLink.href = localizeLink('/cart'); editCartLink.rel = 'noreferrer'; editCartLink.innerText = 'Edit'; @@ -411,7 +412,7 @@ export default async function decorate(block) { if (emptyCart) return; emptyCart = await CartProvider.render(EmptyCart, { - routeCTA: () => '/', + routeCTA: () => localizeLink('/'), })($emptyCart); $content.classList.add('checkout__content--empty'); @@ -734,8 +735,8 @@ export default async function decorate(block) { const handleSignUpClick = async ({ inputsDefaultValueSet, addressesData }) => { const signUpForm = document.createElement('div'); AuthProvider.render(SignUp, { - routeSignIn: () => '/customer/login', - routeRedirectOnEmailConfirmationClose: () => '/customer/account', + routeSignIn: () => localizeLink('/customer/login'), + routeRedirectOnEmailConfirmationClose: () => localizeLink('/customer/account'), inputsDefaultValueSet, addressesData, })(signUpForm); diff --git a/blocks/commerce-mini-cart/commerce-mini-cart.js b/blocks/commerce-mini-cart/commerce-mini-cart.js index dd0e25d1ea..564c0e0a51 100644 --- a/blocks/commerce-mini-cart/commerce-mini-cart.js +++ b/blocks/commerce-mini-cart/commerce-mini-cart.js @@ -17,9 +17,9 @@ export default async function decorate(block) { block.innerHTML = ''; return provider.render(MiniCart, { - routeEmptyCartCTA: startShoppingURL ? () => startShoppingURL : undefined, - routeCart: cartURL ? () => cartURL : undefined, + routeEmptyCartCTA: startShoppingURL ? () => localizeLink(startShoppingURL) : undefined, + routeCart: cartURL ? () => localizeLink(cartURL) : undefined, routeCheckout: checkoutURL ? () => localizeLink(checkoutURL) : undefined, - routeProduct: (product) => `/products/${product.url.urlKey}/${product.topLevelSku}`, + routeProduct: (product) => localizeLink(`/products/${product.url.urlKey}/${product.topLevelSku}`), })(block); } diff --git a/blocks/commerce-order-product-list/commerce-order-product-list.js b/blocks/commerce-order-product-list/commerce-order-product-list.js index 20e641d248..b555f4ca10 100644 --- a/blocks/commerce-order-product-list/commerce-order-product-list.js +++ b/blocks/commerce-order-product-list/commerce-order-product-list.js @@ -5,9 +5,10 @@ import { OrderProductList } from '@dropins/storefront-order/containers/OrderProd // Initialize import '../../scripts/initializers/order.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { await orderRenderer.render(OrderProductList, { - routeProductDetails: (product) => `/products/${product.productUrlKey}/${product.product.sku}`, + routeProductDetails: (product) => localizeLink(`/products/${product.productUrlKey}/${product.product.sku}`), })(block); } diff --git a/blocks/commerce-order-returns/commerce-order-returns.js b/blocks/commerce-order-returns/commerce-order-returns.js index 1f2658f469..c505d2f8b0 100644 --- a/blocks/commerce-order-returns/commerce-order-returns.js +++ b/blocks/commerce-order-returns/commerce-order-returns.js @@ -11,6 +11,7 @@ import { // Initialize import '../../scripts/initializers/order.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { const isAuthenticated = checkIsAuthenticated(); @@ -34,6 +35,6 @@ export default async function decorate(block) { return `${returnDetailsPath}?orderRef=${encodedOrderRef}&returnRef=${returnNumber}`; }, - routeProductDetails: (productData) => (productData?.product ? `/products/${productData.product.urlKey}/${productData.product.sku}` : '#'), + routeProductDetails: (productData) => (productData?.product ? localizeLink(`/products/${productData.product.urlKey}/${productData.product.sku}`) : '#'), })(block); } diff --git a/blocks/commerce-orders-list/commerce-orders-list.js b/blocks/commerce-orders-list/commerce-orders-list.js index f84066106c..e3217b142c 100644 --- a/blocks/commerce-orders-list/commerce-orders-list.js +++ b/blocks/commerce-orders-list/commerce-orders-list.js @@ -14,6 +14,7 @@ import { // Initialize import '../../scripts/initializers/account.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { const { 'minified-view': minifiedViewConfig = 'false' } = readBlockConfig(block); @@ -32,7 +33,7 @@ export default async function decorate(block) { routeOrdersList: () => CUSTOMER_ORDERS_PATH, routeOrderDetails: (orderNumber) => `${CUSTOMER_ORDER_DETAILS_PATH}?orderRef=${orderNumber}`, routeReturnDetails: ({ orderNumber, returnNumber }) => `${CUSTOMER_RETURN_DETAILS_PATH}?orderRef=${orderNumber}&returnRef=${returnNumber}`, - routeOrderProduct: (productData) => (productData?.product ? `/products/${productData.product.urlKey}/${productData.product.sku}` : '#'), + routeOrderProduct: (productData) => (productData?.product ? localizeLink(`/products/${productData.product.urlKey}/${productData.product.sku}`) : '#'), })(block); } } diff --git a/blocks/commerce-returns-list/commerce-returns-list.js b/blocks/commerce-returns-list/commerce-returns-list.js index 3a18d05424..e4e38aac78 100644 --- a/blocks/commerce-returns-list/commerce-returns-list.js +++ b/blocks/commerce-returns-list/commerce-returns-list.js @@ -4,6 +4,7 @@ import { render as orderRenderer } from '@dropins/storefront-order/render.js'; import ReturnsList from '@dropins/storefront-order/containers/ReturnsList.js'; import { readBlockConfig } from '../../scripts/aem.js'; import { checkIsAuthenticated } from '../../scripts/configs.js'; +import { localizeLink } from '../../scripts/scripts.js'; import { CUSTOMER_LOGIN_PATH, CUSTOMER_RETURN_DETAILS_PATH, @@ -34,7 +35,7 @@ export default async function decorate(block) { routeReturnDetails: ({ orderNumber, returnNumber }) => `${CUSTOMER_RETURN_DETAILS_PATH}?orderRef=${orderNumber}&returnRef=${returnNumber}`, routeOrderDetails: ({ orderNumber }) => `${CUSTOMER_ORDER_DETAILS_PATH}?orderRef=${orderNumber}`, routeReturnsList: () => CUSTOMER_RETURNS_PATH, - routeProductDetails: (productData) => (productData?.product ? `/products/${productData.product.urlKey}/${productData.product.sku}` : '#'), + routeProductDetails: (productData) => (productData?.product ? localizeLink(`/products/${productData.product.urlKey}/${productData.product.sku}`) : '#'), })(block); } } diff --git a/blocks/commerce-shipping-status/commerce-shipping-status.js b/blocks/commerce-shipping-status/commerce-shipping-status.js index 14ae426af1..b9c35f0240 100644 --- a/blocks/commerce-shipping-status/commerce-shipping-status.js +++ b/blocks/commerce-shipping-status/commerce-shipping-status.js @@ -3,6 +3,7 @@ import { render as orderRenderer } from '@dropins/storefront-order/render.js'; import { ShippingStatus } from '@dropins/storefront-order/containers/ShippingStatus.js'; import { UPS_TRACKING_URL } from '../../scripts/constants.js'; +import { localizeLink } from '../../scripts/scripts.js'; // Initialize import '../../scripts/initializers/order.js'; @@ -17,10 +18,10 @@ export default async function decorate(block) { }, routeProductDetails: (data) => { if (data?.orderItem) { - return `/products/${data?.orderItem?.productUrlKey}/${data?.orderItem?.product?.sku}`; + return localizeLink(`/products/${data?.orderItem?.productUrlKey}/${data?.orderItem?.product?.sku}`); } if (data?.product) { - return `/products/${data?.product?.urlKey}/${data?.product?.sku}`; + return localizeLink(`/products/${data?.product?.urlKey}/${data?.product?.sku}`); } return '#'; }, diff --git a/blocks/header/renderAuthCombine.js b/blocks/header/renderAuthCombine.js index 18797b1e23..5ac9e89425 100644 --- a/blocks/header/renderAuthCombine.js +++ b/blocks/header/renderAuthCombine.js @@ -10,6 +10,7 @@ import { events } from '@dropins/tools/event-bus.js'; import { Button } from '@dropins/tools/components.js'; import { getCookie } from '../../scripts/configs.js'; import { CUSTOMER_ACCOUNT_PATH, CUSTOMER_FORGOTPASSWORD_PATH, CUSTOMER_LOGIN_PATH } from '../../scripts/constants.js'; +import { localizeLink } from '../../scripts/scripts.js'; const signInFormConfig = { renderSignUpLink: true, @@ -49,7 +50,7 @@ const signInFormConfig = { variant: 'tertiary', onClick: async () => { await authApi.revokeCustomerToken(); - window.location.href = '/'; + window.location.href = localizeLink('/'); }, })(secondaryButton); diff --git a/blocks/header/renderAuthDropdown.js b/blocks/header/renderAuthDropdown.js index 24fee542ac..f358e5ac4b 100644 --- a/blocks/header/renderAuthDropdown.js +++ b/blocks/header/renderAuthDropdown.js @@ -5,6 +5,7 @@ import { SignIn } from '@dropins/storefront-auth/containers/SignIn.js'; import { events } from '@dropins/tools/event-bus.js'; import { getCookie } from '../../scripts/configs.js'; import { CUSTOMER_FORGOTPASSWORD_PATH } from '../../scripts/constants.js'; +import { localizeLink } from '../../scripts/scripts.js'; function checkAndRedirect(redirections) { Object.entries(redirections).some(([currentPath, redirectPath]) => { @@ -31,7 +32,7 @@ export function renderAuthDropdown(navTools) { @@ -75,8 +76,8 @@ export function renderAuthDropdown(navTools) { logoutButtonElement.addEventListener('click', async () => { await authApi.revokeCustomerToken(); checkAndRedirect({ - '/customer': '/customer/login', - '/order-details': '/', + '/customer': localizeLink('/customer/login'), + '/order-details': localizeLink('/'), }); }); diff --git a/blocks/header/searchbar.js b/blocks/header/searchbar.js index fe0a67a023..609164b433 100644 --- a/blocks/header/searchbar.js +++ b/blocks/header/searchbar.js @@ -1,4 +1,5 @@ import { loadScript } from '../../scripts/aem.js'; +import { localizeLink } from '../../scripts/scripts.js'; import { getConfigValue } from '../../scripts/configs.js'; (async () => { @@ -28,9 +29,9 @@ import { getConfigValue } from '../../scripts/configs.js'; context: { customerGroup: await getConfigValue('commerce.headers.cs.Magento-Customer-Group'), }, - route: ({ sku, urlKey }) => `/products/${urlKey}/${sku}`, + route: ({ sku, urlKey }) => localizeLink(`/products/${urlKey}/${sku}`), searchRoute: { - route: '/search', + route: localizeLink('/search'), query: 'q', }, }; diff --git a/blocks/product-details/product-details.js b/blocks/product-details/product-details.js index 4125f0e999..daf97e32ec 100644 --- a/blocks/product-details/product-details.js +++ b/blocks/product-details/product-details.js @@ -27,6 +27,7 @@ import { fetchPlaceholders } from '../../scripts/aem.js'; // Initializers import { IMAGES_SIZES } from '../../scripts/initializers/pdp.js'; import '../../scripts/initializers/cart.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { // eslint-disable-next-line no-underscore-dangle @@ -297,9 +298,9 @@ async function setJsonLdProduct(product) { '@type': 'Brand', name: brand?.value, }, - url: new URL(`/products/${urlKey}/${sku}`, window.location), + url: new URL(localizeLink(`/products/${urlKey}/${sku}`), window.location), sku, - '@id': new URL(`/products/${urlKey}/${sku}`, window.location), + '@id': new URL(localizeLink(`/products/${urlKey}/${sku}`), window.location), }; if (variants.length > 1) { diff --git a/blocks/product-list-page-custom/product-list-page-custom.js b/blocks/product-list-page-custom/product-list-page-custom.js index 81c7018a06..2ba2dac635 100644 --- a/blocks/product-list-page-custom/product-list-page-custom.js +++ b/blocks/product-list-page-custom/product-list-page-custom.js @@ -6,6 +6,7 @@ import ProductList from './ProductList.js'; import FacetList from './FacetList.js'; import { readBlockConfig, sampleRUM } from '../../scripts/aem.js'; import { priceFieldsFragment, performCatalogServiceQuery } from '../../scripts/commerce.js'; +import { localizeLink } from '../../scripts/scripts.js'; const html = htm.bind(h); @@ -411,7 +412,7 @@ class ProductListPage extends Component { products: this.state.products.items.map((p, index) => ({ name: p.name, sku: p.sku, - url: new URL(`/products/${p.urlKey}/${p.sku}`, window.location).toString(), + url: new URL(localizeLink(`/products/${p.urlKey}/${p.sku}`), window.location).toString(), imageUrl: p.images?.length ? p.images[0].url : '', price: p.price?.final?.amount?.value ?? p.priceRange?.minimum?.final?.amount?.value, rank: index, diff --git a/blocks/product-list-page/product-list-page.js b/blocks/product-list-page/product-list-page.js index aeea894fd0..f0f3cf11f2 100644 --- a/blocks/product-list-page/product-list-page.js +++ b/blocks/product-list-page/product-list-page.js @@ -1,5 +1,6 @@ import { readBlockConfig } from '../../scripts/aem.js'; import { getConfigValue } from '../../scripts/configs.js'; +import { localizeLink } from '../../scripts/scripts.js'; export default async function decorate(block) { // eslint-disable-next-line import/no-absolute-path, import/no-unresolved @@ -46,7 +47,7 @@ export default async function decorate(block) { }, route: ({ sku, urlKey }) => { const a = new URL(window.location.origin); - a.pathname = `/products/${urlKey}/${sku}`; + a.pathname = localizeLink(`/products/${urlKey}/${sku}`); return a.toString(); }, }; diff --git a/scripts/constants.js b/scripts/constants.js index 31c9a3a26b..8bdf14426a 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -1,14 +1,16 @@ -export const SUPPORT_PATH = '/support'; +import { localizeLink } from './scripts.js'; + +export const SUPPORT_PATH = localizeLink('/support'); // GUEST -export const ORDER_STATUS_PATH = '/order-status'; -export const ORDER_DETAILS_PATH = '/order-details'; -export const RETURN_DETAILS_PATH = '/return-details'; -export const CREATE_RETURN_PATH = '/create-return'; -export const SALES_GUEST_VIEW_PATH = '/sales/guest/view/'; +export const ORDER_STATUS_PATH = localizeLink('/order-status'); +export const ORDER_DETAILS_PATH = localizeLink('/order-details'); +export const RETURN_DETAILS_PATH = localizeLink('/return-details'); +export const CREATE_RETURN_PATH = localizeLink('/create-return'); +export const SALES_GUEST_VIEW_PATH = localizeLink('/sales/guest/view/'); // CUSTOMER -export const CUSTOMER_PATH = '/customer'; +export const CUSTOMER_PATH = localizeLink('/customer'); export const CUSTOMER_ORDER_DETAILS_PATH = `${CUSTOMER_PATH}${ORDER_DETAILS_PATH}`; export const CUSTOMER_RETURN_DETAILS_PATH = `${CUSTOMER_PATH}${RETURN_DETAILS_PATH}`; export const CUSTOMER_CREATE_RETURN_PATH = `${CUSTOMER_PATH}${CREATE_RETURN_PATH}`; @@ -18,7 +20,7 @@ export const CUSTOMER_ADDRESS_PATH = `${CUSTOMER_PATH}/address`; export const CUSTOMER_LOGIN_PATH = `${CUSTOMER_PATH}/login`; export const CUSTOMER_ACCOUNT_PATH = `${CUSTOMER_PATH}/account`; export const CUSTOMER_FORGOTPASSWORD_PATH = `${CUSTOMER_PATH}/forgotpassword`; -export const SALES_ORDER_VIEW_PATH = '/sales/order/view/'; +export const SALES_ORDER_VIEW_PATH = localizeLink('/sales/order/view/'); // TRACKING export const UPS_TRACKING_URL = 'https://www.ups.com/track'; From 91a34b7f3d2f4deb299c606175d5d478623cc9c8 Mon Sep 17 00:00:00 2001 From: "Carlos A. Cabrera" Date: Mon, 3 Feb 2025 16:00:40 -0600 Subject: [PATCH 19/25] feat: add dynamic metadata fetching for 404 page based on URL patterns --- 404.html | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/404.html b/404.html index 94288e04da..159f44a7ee 100644 --- a/404.html +++ b/404.html @@ -18,6 +18,42 @@ +