Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Release] Stage to Main #2722

Merged
merged 6 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 55 additions & 38 deletions libs/blocks/marketo/marketo.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ const ROOT_MARGIN = 1000;
const FORM_ID = 'form id';
const BASE_URL = 'marketo host';
const MUNCHKIN_ID = 'marketo munckin';
const SUCCESS_TYPE = 'form.success.type';
const SUCCESS_CONTENT = 'form.success.content';
const SUCCESS_SECTION = 'form.success.section';
const FORM_MAP = {
'destination-url': 'form.success.content',
'success-type': SUCCESS_TYPE,
'destination-type': SUCCESS_TYPE,
'success-content': SUCCESS_CONTENT,
'destination-url': SUCCESS_CONTENT,
'success-section': SUCCESS_SECTION,
'co-partner-names': 'program.copartnernames',
'sfdc-campaign-id': 'program.campaignids.sfdc',
};

export const formValidate = (form) => {
const formEl = form.getFormElem().get(0);
export const formValidate = (formEl) => {
formEl.classList.remove('hide-errors');
formEl.classList.add('show-warnings');
};
Expand Down Expand Up @@ -61,9 +67,24 @@ export const decorateURL = (destination, baseURL = window.location) => {
return null;
};

export const formSuccess = (form) => {
const formEl = form.getFormElem().get(0);
const parentModal = formEl.closest('.dialog-modal');
const setPreference = (key = '', value = '') => {
if (!value || !key.includes('.')) return;
const keyParts = key.split('.');
const lastKey = keyParts.pop();
const formDataObject = keyParts.reduce((obj, part) => {
obj[part] = obj[part] || {};
return obj[part];
}, window.mcz_marketoForm_pref);
formDataObject[lastKey] = value;
};

export const setPreferences = (formData) => {
window.mcz_marketoForm_pref = window.mcz_marketoForm_pref || {};
Object.entries(formData).forEach(([key, value]) => setPreference(key, value));
};

export const formSuccess = (formEl, formData) => {
const parentModal = formEl?.closest('.dialog-modal');
const mktoSubmit = new Event('mktoSubmit');

window.dispatchEvent(mktoSubmit);
Expand All @@ -76,10 +97,23 @@ export const formSuccess = (form) => {
return false;
}

return true;
if (formData?.[SUCCESS_TYPE] !== 'section') return true;

try {
const section = formData[SUCCESS_SECTION].toLowerCase().replaceAll(' ', '-');
const success = document.querySelector(`.section.${section}`);
success.classList.remove('hide-block');
success.scrollIntoView({ behavior: 'smooth' });
setPreference(SUCCESS_TYPE, 'message');
} catch (e) {
/* c8 ignore next 2 */
window.lana?.log('Error showing Marketo success section', { tags: 'errorType=warn,module=marketo' });
}

return false;
};

const readyForm = (form) => {
const readyForm = (form, formData) => {
const formEl = form.getFormElem().get(0);
const isDesktop = matchMedia('(min-width: 900px)');

Expand All @@ -95,58 +129,42 @@ const readyForm = (form) => {
const offsetPosition = targetPosition + window.pageYOffset - pageTop - window.innerHeight / 2;
window.scrollTo(0, offsetPosition);
}, true);
form.onValidate(() => formValidate(form));
form.onSuccess(() => formSuccess(form));
};

const setPreference = (key, value) => {
if (value && key?.includes('.')) {
const keyParts = key.split('.');
const lastKey = keyParts.pop();
const formDataObject = keyParts.reduce((obj, part) => {
obj[part] = obj[part] || {};
return obj[part];
}, window.mcz_marketoForm_pref);
formDataObject[lastKey] = value;
}
};

export const setPreferences = (formData) => {
window.mcz_marketoForm_pref = window.mcz_marketoForm_pref || {};
Object.entries(formData).forEach(([key, value]) => setPreference(key, value));
form.onValidate(() => formValidate(formEl));
form.onSuccess(() => formSuccess(formEl, formData));
};

export const loadMarketo = (el, formData) => {
const baseURL = formData[BASE_URL];
const munchkinID = formData[MUNCHKIN_ID];
const formID = formData[FORM_ID];

loadScript(`https://${baseURL}/js/forms2/js/forms2.min.js`)
.then(() => {
const { MktoForms2 } = window;
if (!MktoForms2) throw new Error('Marketo forms not loaded');

MktoForms2.loadForm(`//${baseURL}`, formData[MUNCHKIN_ID], formData[FORM_ID]);
MktoForms2.loadForm(`//${baseURL}`, munchkinID, formID);
MktoForms2.whenReady((form) => { readyForm(form, formData); });
})
.catch(() => {
/* c8 ignore next */
/* c8 ignore next 2 */
el.style.display = 'none';
window.lana?.log(`Error loading Marketo form for ${munchkinID}_${formID}`, { tags: 'errorType=error,module=marketo' });
});
};

export default function init(el) {
const children = Array.from(el.querySelectorAll(':scope > div'));
const encodedConfigDiv = children.shift();
const link = encodedConfigDiv.querySelector('a');
let formData = {};

if (!link?.href) {
el.style.display = 'none';
return;
}

const encodedConfig = link.href.split('#')[1];

formData = parseEncodedConfig(encodedConfig);
const formData = parseEncodedConfig(encodedConfig);

children.forEach((element) => {
const key = element.children[0]?.textContent.trim().toLowerCase().replaceAll(' ', '-');
Expand All @@ -168,13 +186,12 @@ export default function init(el) {
return;
}

if (formData['form.success.content']) {
const destinationUrl = decorateURL(formData['form.success.content']);
formData[SUCCESS_TYPE] = formData[SUCCESS_TYPE] || 'redirect';

if (destinationUrl) {
formData['form.success.type'] = 'redirect';
formData['form.success.content'] = destinationUrl;
}
if (formData[SUCCESS_TYPE] === 'redirect') {
const destinationUrl = decorateURL(formData[SUCCESS_CONTENT]);

if (destinationUrl) formData[SUCCESS_CONTENT] = destinationUrl;
}

setPreferences(formData);
Expand Down
60 changes: 48 additions & 12 deletions libs/blocks/merch/merch.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,28 +192,48 @@ export async function fetchCheckoutLinkConfigs(base = '') {
?? fetch(`${base}${CHECKOUT_LINK_CONFIG_PATH}`).catch((e) => {
log?.error('Failed to fetch checkout link configs', e);
}).then((mappings) => {
if (!mappings?.ok) return undefined;
if (!mappings?.ok) return { data: [] };
return mappings.json();
});
return fetchCheckoutLinkConfigs.promise;
}

export async function getCheckoutLinkConfig(productFamily) {
export async function getCheckoutLinkConfig(productFamily, productCode, paCode) {
let { base } = getConfig();
if (/\.page$/.test(document.location.origin)) {
/* c8 ignore next 2 */
base = base.replace('.live', '.page');
}
const checkoutLinkConfigs = await fetchCheckoutLinkConfigs(base);
if (!checkoutLinkConfigs.data.length) return undefined;
const { locale: { region } } = getConfig();
const productFamilyConfigs = checkoutLinkConfigs.data?.filter(
({ [NAME_PRODUCT_FAMILY]: mappingProductFamily }) => mappingProductFamily === productFamily,
);
if (productFamilyConfigs.length === 0) return undefined;
const checkoutLinkConfig = productFamilyConfigs.find(

const {
paCodeConfigs,
productCodeConfigs,
productFamilyConfigs,
} = checkoutLinkConfigs.data.reduce((acc, config) => {
if (config[NAME_PRODUCT_FAMILY] === paCode) {
acc.paCodeConfigs.push(config);
} else if (config[NAME_PRODUCT_FAMILY] === productCode) {
acc.productCodeConfigs.push(config);
} else if (config[NAME_PRODUCT_FAMILY] === productFamily) {
acc.productFamilyConfigs.push(config);
}
return acc;
}, { paCodeConfigs: [], productCodeConfigs: [], productFamilyConfigs: [] });

// helps to fallback to product family config
// if no locale specific config is found below.
const productCheckoutLinkConfigs = [
...paCodeConfigs, ...productCodeConfigs, ...productFamilyConfigs,
];

if (!productCheckoutLinkConfigs.length) return undefined;
const checkoutLinkConfig = productCheckoutLinkConfigs.find(
({ [NAME_LOCALE]: locale }) => locale === '',
);
const checkoutLinkConfigOverride = productFamilyConfigs.find(
const checkoutLinkConfigOverride = productCheckoutLinkConfigs.find(
({ [NAME_LOCALE]: locale }) => locale === region,
) ?? {};
const overrides = Object.fromEntries(
Expand All @@ -231,14 +251,22 @@ export async function getCheckoutLinkConfig(productFamily) {
export async function getDownloadAction(
options,
imsSignedInPromise,
[{ offerType, productArrangement: { productFamily: offerFamily } = {} }],
[{
offerType,
productArrangementCode,
productArrangement: { productCode, productFamily: offerFamily } = {},
}],
) {
if (options.entitlement !== true) return undefined;
const loggedIn = await imsSignedInPromise;
if (!loggedIn) return undefined;
const entitlements = await fetchEntitlements();
if (!entitlements?.length) return undefined;
const checkoutLinkConfig = await getCheckoutLinkConfig(offerFamily);
const checkoutLinkConfig = await getCheckoutLinkConfig(
offerFamily,
productCode,
productArrangementCode,
);
if (!checkoutLinkConfig?.DOWNLOAD_URL) return undefined;
const offer = entitlements.find((
{ offer: { product_arrangement: { family: subscriptionFamily } } },
Expand Down Expand Up @@ -355,9 +383,17 @@ export async function openModal(e, url, offerType) {
}

export async function getModalAction(offers, options) {
const [{ offerType, productArrangement: { productFamily: offerFamily } = {} }] = offers ?? [{}];
const [{
offerType,
productArrangementCode,
productArrangement: { productCode, productFamily: offerFamily } = {},
}] = offers ?? [{}];
if (options.modal !== true) return undefined;
const checkoutLinkConfig = await getCheckoutLinkConfig(offerFamily);
const checkoutLinkConfig = await getCheckoutLinkConfig(
offerFamily,
productCode,
productArrangementCode,
);
if (!checkoutLinkConfig) return undefined;
const columnName = (offerType === OFFER_TYPE_TRIAL) ? FREE_TRIAL_PATH : BUY_NOW_PATH;
let url = checkoutLinkConfig[columnName];
Expand Down
43 changes: 24 additions & 19 deletions libs/features/personalization/personalization.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,21 +169,19 @@ const fetchData = async (url, type = DATA_TYPE.JSON) => {
return null;
};

const getBlockProps = (fVal) => {
const getBlockProps = (fVal, miloLibs, origin) => {
let val = fVal;
if (val?.includes('\\')) val = val?.split('\\').join('/');
if (!val?.startsWith('/')) val = `/${val}`;
const blockSelector = val?.split('/').pop();
const { origin } = PAGE_URL;
if (origin.includes('.hlx.') || origin.includes('localhost')) {
if (val.startsWith('/libs/')) {
/* c8 ignore next 2 */
const { miloLibs, codeRoot } = getConfig();
val = `${miloLibs || codeRoot}${val.replace('/libs', '')}`;
} else {
val = `${origin}${val}`;
}

if (val.startsWith('/libs/')) {
/* c8 ignore next 1 */
val = `${miloLibs}${val.replace('/libs', '')}`;
} else {
val = `${origin}${val}`;
}

return { blockSelector, blockTarget: val };
};

Expand Down Expand Up @@ -457,6 +455,7 @@ const getVariantInfo = (line, variantNames, variants, manifestPath, manifestOver
if (pageFilter && !matchGlob(pageFilter, new URL(window.location).pathname)) return;

if (!config.mep?.preview) manifestId = false;
const { origin } = PAGE_URL;
variantNames.forEach((vn) => {
const targetManifestId = vn.startsWith(TARGET_EXP_PREFIX) ? targetId : false;
if (!line[vn] || line[vn].toLowerCase() === 'false') return;
Expand All @@ -483,7 +482,7 @@ const getVariantInfo = (line, variantNames, variants, manifestPath, manifestOver
variants[vn][action] = variants[vn][action] || [];

if (action === 'useblockcode') {
const { blockSelector, blockTarget } = getBlockProps(line[vn]);
const { blockSelector, blockTarget } = getBlockProps(line[vn], config.miloLibs, origin);
variants[vn][action].push({
selector: blockSelector,
val: blockTarget,
Expand Down Expand Up @@ -578,20 +577,26 @@ const checkForParamMatch = (paramStr) => {
return false;
};

function trimNames(arr) {
return arr.map((v) => v.trim()).filter(Boolean);
}
export function buildVariantInfo(variantNames) {
return variantNames.reduce((acc, name) => {
let nameArr = [name];
if (!name.startsWith(TARGET_EXP_PREFIX)) nameArr = name.split(',');
acc[name] = trimNames(nameArr);
acc.allNames = [...acc.allNames, ...trimNames(name.split(/[,&]|\bnot\b/))];
return acc;
}, { allNames: [] });
}

async function getPersonalizationVariant(manifestPath, variantNames = [], variantLabel = null) {
const config = getConfig();
if (config.mep?.variantOverride?.[manifestPath]) {
return config.mep.variantOverride[manifestPath];
}

const variantInfo = variantNames.reduce((acc, name) => {
let nameArr = [name];
if (!name.startsWith(TARGET_EXP_PREFIX)) nameArr = name.split(',');
const vNames = nameArr.map((v) => v.trim()).filter(Boolean);
acc[name] = vNames;
acc.allNames = [...acc.allNames, ...vNames];
return acc;
}, { allNames: [] });
const variantInfo = buildVariantInfo(variantNames);

const entitlementKeys = Object.values(await getEntitlementMap());
const hasEntitlementTag = entitlementKeys.some((tag) => variantInfo.allNames.includes(tag));
Expand Down
Loading
Loading