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

feat: integrate target using json offers #474

Merged
merged 34 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
06dc6b8
inital setup for audiences from target
Feb 5, 2024
8f68deb
feat: resolve audiences
vtsaplin Feb 6, 2024
a3b54fd
feat: resolve audiences
vtsaplin Feb 6, 2024
1c1ccb3
added cloudflare worker
Feb 6, 2024
473e9a9
read target location
Feb 6, 2024
75dd80d
fix: target location name
Feb 6, 2024
c604972
fix: target location name
Feb 6, 2024
a68dc46
refactor: cleanup
vtsaplin Feb 7, 2024
33c641b
feat: add hero2 block
vtsaplin Feb 7, 2024
b990e8a
feat: add hero2 block
vtsaplin Feb 7, 2024
ad6369f
feat: add hero2 block
vtsaplin Feb 7, 2024
2ad4338
feat: add hero2 block
vtsaplin Feb 7, 2024
a87ca27
feat: add hero2 block
vtsaplin Feb 7, 2024
54873af
Revert "feat: add hero2 block"
vtsaplin Feb 8, 2024
7b38410
Revert "feat: add hero2 block"
vtsaplin Feb 8, 2024
5cc97b3
Revert "feat: add hero2 block"
vtsaplin Feb 8, 2024
bccb999
Revert "feat: add hero2 block"
vtsaplin Feb 8, 2024
94138d1
Revert "feat: add hero2 block"
vtsaplin Feb 8, 2024
6ac41db
added css to highlight challenger change
Feb 8, 2024
15bc716
Merge branch 'main' into target
vtsaplin Apr 17, 2024
18de45b
Merge branch 'refs/heads/main' into target
vtsaplin Apr 20, 2024
f584314
feat: create audiences dynamically
vtsaplin Apr 21, 2024
7992a12
Merge branch 'refs/heads/main' into target-json
vtsaplin May 13, 2024
66c393b
feat: cleanup and refactoring
vtsaplin May 24, 2024
b96e5c3
chore: log experiment details
vtsaplin May 24, 2024
0d247f9
feat: expose target tenant param
vtsaplin May 24, 2024
9c63997
feat: resolve configured audiences
vtsaplin May 24, 2024
759466e
chore: remove temp files
vtsaplin May 24, 2024
fed24dc
chore: undo accidental change
vtsaplin May 24, 2024
70488a9
feat: decouple from aem experimentation
vtsaplin May 28, 2024
ffdad8c
chore: linting
vtsaplin May 28, 2024
da49496
Merge branch 'refs/heads/main' into target-json
vtsaplin May 29, 2024
84eb9d5
feat: apply review feedback
vtsaplin May 29, 2024
19066e8
chore: change target tenant
vtsaplin May 29, 2024
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
3 changes: 2 additions & 1 deletion head.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<script src="/solutions/scripts/lib-franklin.js" type="module"></script>
<script src="/solutions/scripts/utils.js" type="module"></script>
<script src="/solutions/scripts/target.js" type="module"></script>
<script src="/solutions/scripts/scripts.js" type="module"></script>
<link rel="stylesheet" href="/solutions/styles/styles.css"/>
<link rel="stylesheet" href="/solutions/styles/styles.css"/>
13 changes: 10 additions & 3 deletions solutions/scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from './utils.js';

import { loadAnalytics } from './analytics.js';
import runTargetExperiment from './target.js';
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved

const LCP_BLOCKS = ['hero']; // add your LCP blocks to the list
const TRACKED_PRODUCTS = [];
Expand All @@ -32,6 +33,8 @@ export const DEFAULT_COUNTRY = 'au';

export const METADATA_ANALYTICS_TAGS = 'analytics-tags';

const TARGET_TENANT = 'sitesinternal';
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved

const HREFLANG_MAP = [
['en-ro', { baseUrl: 'https://www.bitdefender.ro', pageType: '.html' }],
['de', { baseUrl: 'https://www.bitdefender.de', pageType: '.html' }],
Expand Down Expand Up @@ -459,7 +462,7 @@ function getExperimentDetails() {
return { experimentId, experimentVariant };
}

function pushPageLoadToDataLayer() {
function pushPageLoadToDataLayer(targetExperimentDetails) {
const { hostname } = window.location;
if (!hostname) {
return;
Expand All @@ -469,7 +472,9 @@ function pushPageLoadToDataLayer() {
const environment = getEnvironment(hostname, languageCountry.country);
const tags = getTags(getMetadata(METADATA_ANALYTICS_TAGS));

const experimentDetails = getExperimentDetails();
const experimentDetails = targetExperimentDetails ?? getExperimentDetails();
// eslint-disable-next-line no-console
console.debug(`Experiment details: ${JSON.stringify(experimentDetails)}`);

pushToDataLayer('page load started', {
pageInstanceID: environment,
Expand Down Expand Up @@ -511,7 +516,9 @@ async function loadEager(doc) {

await window.hlx.plugins.run('loadEager');

pushPageLoadToDataLayer();
const targetExperimentDetails = await runTargetExperiment(TARGET_TENANT);

pushPageLoadToDataLayer(targetExperimentDetails);
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved

if (getMetadata('template') !== '') {
loadCSS(`${window.hlx.codeBasePath}/styles/${getMetadata('template')}.css`);
Expand Down
145 changes: 145 additions & 0 deletions solutions/scripts/target.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { getMetadata, sampleRUM } from './lib-franklin.js';

const ADOBE_TARGET_SESSION_ID_PARAM = 'adobeTargetSessionId';

/**
* Convert a URL to a relative URL.
* @param url
* @returns {*|string}
*/
function toRelativeUrl(url) {
try {
const parsedUrl = new URL(url);
return parsedUrl.pathname + parsedUrl.search + parsedUrl.hash;
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved
} catch (e) {
return url;
}
}

/**
* Generate a random session id.
* @param length
* @returns {string}
*/
function generateSessionID(length = 16) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved
let sessionID = '';
for (let i = 0; i < length; i += 1) {
const randomIndex = Math.floor(Math.random() * characters.length);
sessionID += characters.charAt(randomIndex);
}
return sessionID;
}

/**
* Get or create a session id for the current user.
* @returns {string}
*/
function getOrCreateSessionId() {
let sessionId = sessionStorage.getItem(ADOBE_TARGET_SESSION_ID_PARAM);
// eslint-disable-next-line no-console
console.debug(`Session id: ${sessionId}`);
if (!sessionId) {
sessionId = generateSessionID();
// eslint-disable-next-line no-console
console.debug(`Generated new session id: ${sessionId}`);
sessionStorage.setItem(ADOBE_TARGET_SESSION_ID_PARAM, sessionId);
}
return sessionId;
}

/**
* Fetch the target offers for the current location.
* @returns {Promise<boolean>}
*/
async function fetchChallengerPageUrl(tenant, targetLocation) {
// eslint-disable-next-line no-console
console.debug(`Fetching target offers for location: ${targetLocation}`);
const res = await fetch(`https://${tenant}.tt.omtrdc.net/rest/v1/delivery?client=${tenant}&sessionId=${getOrCreateSessionId()}`, {
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved
context: {
channel: 'web',
},
execute: {
pageLoad: {},
mboxes: [
{
name: targetLocation,
index: 0,
},
],
},
}),
});

const payload = await res.json();
const mbox = payload.execute.mboxes.find((m) => m.name === targetLocation);
const { url } = mbox?.options[0].content ?? { url: null };
if (!url) {
// eslint-disable-next-line no-console
console.error('No challenger url found');
throw new Error('No challenger url found');
}

// eslint-disable-next-line no-console
console.debug(`Resolved challenger url: ${url}`);
return url;
}

/**
* Replace the current page with the challenger page.
* @param url The challenger page url.
* @returns {Promise<boolean>}
*/
async function switchToChallengerPage(url) {
const relativePath = toRelativeUrl(url);
const plainPath = relativePath.endsWith('/') ? `${relativePath}index.plain.html` : `${relativePath}.plain.html`;
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved
const resp = await fetch(plainPath);
if (!resp.ok) {
throw new Error(`Failed to fetch challenger page: ${resp.status}`);
}
const mainElement = document.querySelector('main');
if (!mainElement) {
throw new Error('Main element not found');
}
mainElement.innerHTML = await resp.text();
}

export default async function runTargetExperiment(clientId) {
try {
const experimentId = getMetadata('target-experiment');
const targetLocation = getMetadata('target-experiment-location');
if (!experimentId || !targetLocation) {
// eslint-disable-next-line no-console
console.log('Experiment id or target location not found');
return null;
}

// eslint-disable-next-line no-console
console.debug(`Running Target experiment ${experimentId} at location ${targetLocation}`);

const pageUrl = await fetchChallengerPageUrl(clientId, targetLocation);
// eslint-disable-next-line no-console
console.debug(`Challenger page url: ${pageUrl}`);

await switchToChallengerPage(pageUrl);

sampleRUM('target-experiment', {
vtsaplin marked this conversation as resolved.
Show resolved Hide resolved
source: `target:${experimentId}`,
target: pageUrl,
});

return {
experimentId,
experimentVariant: pageUrl,
};
} catch (e) {
// eslint-disable-next-line no-console
console.error('Error running target experiment:', e);
return null;
}
}
Loading