UNPKG

@ampush/centaurus

Version:

Centaurus, is an Ampush repository designed to house common UI components, JS classes, templates and API methods in a central place that can be imported and reused across other Ampush partner repositories as needed.

161 lines (151 loc) 6.39 kB
const getCookie = (utmKey) => { const cookieString = decodeURIComponent(document.cookie).split('; '); for (let val = 0; val < cookieString.length; val++) { const item = cookieString[val]; const queryVal = item.split(`${utmKey}=`)[1]; const queryKey = item.split('=')[0]; if (utmKey === queryKey) { return queryVal; } } return ''; }; const { hostname } = window.location; const [subDomain, domainName, top] = hostname.split('.'); const host = hostname; const isLocalhost = hostname.indexOf('localhost') !== -1 || hostname.indexOf('0.0.0.0') !== -1; const parsedDomain = isLocalhost ? host : domainName ? `${domainName}.${top || 'com'}` : ''; const parsedSubDomain = isLocalhost ? '' : subDomain; const hostName = isLocalhost ? `http://${host}:${window.location.port}` : `https://${parsedSubDomain}.${parsedDomain}`; const removeDuplicates = (str, splitChar) => { const splitArr = str.split(splitChar); const obj = {}; splitArr.forEach((v) => { const [key, value] = v.split('='); obj[key] = value; }); const keys = Object.keys(obj); return keys.map((k) => `${k}=${obj[k]}`).join(splitChar); }; const color = 'color:#008b8b'; const background = 'background-color:#fff8dc'; const whiteSpace = 'white-space:break-spaces'; const display = 'display:flow'; const padding = 'padding: 0 30px'; const textAlign = 'text-align: center'; const styles = [color, background, whiteSpace, display, padding, textAlign]; const logCss = styles.join(';'); const redirect = (variant, utmExp, additionalUtms) => { const { url, name } = variant; const qsToPass = window.location.search.substr(1) !== '' ? `${removeDuplicates(window.location.search.substr(1), '&')}` : ''; const baseUrl = url.indexOf('.') !== -1 ? `https://${url}` : `${hostName}/${url}`; let fullUrl = qsToPass ? `${baseUrl}?${qsToPass}` : baseUrl; if (name) { const urlPart = [utmExp, name].filter((param) => param).join(''); const cleanParams = [qsToPass, urlPart].filter((param) => param).join('&'); const params = removeDuplicates(cleanParams, '&'); fullUrl = `${baseUrl}?${params}`; } console.info('%c __ Redirecting to __ ', logCss); console.info(JSON.stringify({ fullUrl, variant }, null, 2)); const operand = fullUrl.indexOf('?') !== -1 ? '&' : '?'; document.location.replace(fullUrl.concat(additionalUtms ? `${operand}${additionalUtms}` : '')); }; const setCookie = (cookieStr, doExpires) => { if (doExpires) { const date = new Date(); date.setTime(date.getTime() + 365 * 24 * 60 * 60 * 1000); const expires = `expires=${date.toUTCString()}`; document.cookie = `${cookieStr};${expires};domain=${parsedDomain};path=/`; } else { document.cookie = `${cookieStr};domain=${parsedDomain};path=/`; } }; const compare = (a = 0, b = 0) => { let comparison = 0; if (a < b) { comparison = 1; } else if (a > b) { comparison = -1; } return comparison; }; function Split(experience, experimentName) { const { cookies = [], homeExpCookie = 'utm_home_exp', variants = [], additionalUtms = '' } = experience; if (!variants.length) { throw Error('No variants supplied, please re-visit split config!'); } if (!experimentName) { throw Error('No experimentName passed for naming the experiment name!'); } variants.forEach(({ name, url }, index) => { if (!url || !name) { throw Error(`Missing url for variant at index ${index} | name: ${name} | url: ${url}`); } }); const splitArray = []; const variantsWithoutPercentages = variants.filter(({ percentage }) => !percentage); const variantsWithPercentages = variants.filter(({ percentage }) => percentage); const reducePercentages = variantsWithPercentages.reduce((sum, { percentage }) => sum + percentage, 0); const splitPercentage = (100 - (reducePercentages || 0)) / (variantsWithoutPercentages.length || 1); variants.sort((a, b) => compare(a.percentage, b.percentage)); variants.forEach(({ name, percentage }) => { const loop = percentage || splitPercentage; for (let index = 0; index < loop; index++) { splitArray.push(name); } }); const splitResult = Math.floor(Math.random() * 100); const answerName = splitArray[splitResult]; const answerObj = variants.filter(({ name }) => name === answerName)[0] || {}; setCookie(`${homeExpCookie}=${experimentName}${answerObj['name']}`, false); setCookie(`${homeExpCookie}_url=${answerObj['url']}`, false); cookies.forEach(({ key, val }) => { setCookie(`${key}=${val}`); }); console.info('%c ·· Split result /Y\\ ·· ', logCss); console.info(JSON.stringify({ splitArray, answerObj, splitResult, additionalUtms, }, null, 2)); return { answerObj, splitResult, additionalUtms, }; } const Plover = (utmExpName, experiences) => { const { tests, revisitingUser, testName } = experiences; if (revisitingUser) { const numRegex = /\d+/; const [utmTestName] = utmExpName.split('='); const revisitingCookie = getCookie(utmTestName); const [revisitingExp, variantName] = revisitingCookie.split('_'); const revisitingTestNumber = (revisitingExp.match(numRegex) || ['1'])[0]; const revisitingTestName = revisitingExp.split(revisitingTestNumber)[0]; const returingExpName = `${utmTestName}=${revisitingTestName}${revisitingTestNumber}_`; const variantUrl = getCookie(`${utmTestName}_url`); const revisitExperience = { name: variantName, url: variantUrl, }; console.info('%c Revisiting User', logCss); console.info(JSON.stringify(revisitExperience, null, 2)); return redirect(revisitExperience, returingExpName); } const experience = (tests && tests.filter(({ rule }) => rule)[0]) || experiences.default; if (experience) { const { answerObj, additionalUtms } = Split(experience, testName); redirect(answerObj, utmExpName, additionalUtms); } else { console.error('ERROR! No experience matched on rules. Set one to "true"'); } }; export default Plover;