From d96fd4bd867ab72ff88f2feafab081141a3d8104 Mon Sep 17 00:00:00 2001 From: Teppo Jalava Date: Thu, 14 Feb 2019 23:14:37 +0200 Subject: [PATCH] Check existence of sizeme_options in all places where it is accessed Fixes #115 --- nosizeme.html | 9 +++ src/api/ga.js | 120 ++++++++++++++++++++------------------ src/api/sizeme-api.js | 90 ++++++++++++++++------------- src/api/uiOptions.js | 12 ++-- src/i18n.js | 6 +- src/index.js | 131 ++++++++++++++++++++++-------------------- webpack.config.js | 3 +- 7 files changed, 207 insertions(+), 164 deletions(-) create mode 100644 nosizeme.html diff --git a/nosizeme.html b/nosizeme.html new file mode 100644 index 0000000..ce8fe07 --- /dev/null +++ b/nosizeme.html @@ -0,0 +1,9 @@ + + + + No Sizeme + + +

Nothing to see here, move along

+ + \ No newline at end of file diff --git a/src/api/ga.js b/src/api/ga.js index f7bbb88..40484d4 100644 --- a/src/api/ga.js +++ b/src/api/ga.js @@ -1,4 +1,4 @@ -/* global ga, sizeme_options */ +/* global ga */ import cookie from "react-cookie"; const PENDING = -1; @@ -17,65 +17,75 @@ const optanonConsent = () => { } }; -((i, s, o, g, r) => { - if (!i[r]) { - i["GoogleAnalyticsObject"] = r; - i[r] = i[r] || - function () { - (i[r].q = i[r].q || []).push(arguments); - }; - i[r].l = 1 * new Date(); - let a = s.createElement(o); - let m = s.getElementsByTagName(o)[0]; - a.async = 1; - a.src = g; - m.parentNode.insertBefore(a, m); - } -})(window, document, "script", "https://www.google-analytics.com/analytics.js", "ga"); - -const gaTrackingId = !sizeme_options.debugState ? prodTrackingId : devTrackingId; -let trackEvent; -let gaConsent = () => ENABLED; -const trackingConsentMethod = sizeme_options.trackingConsentMethod; -const gaQueue = [() => { - ga("create", gaTrackingId, "auto", { name: "sizemeTracker" }); -}]; - -if (trackingConsentMethod) { - switch (trackingConsentMethod.toLowerCase()) { - case "optanon": - gaConsent = optanonConsent; - break; - - default: +let trackEvent = () => {}; + +(sizemeOptions => { + if (!sizemeOptions) { + return; } -} - -const _trackEvent = (action, label) => { - ga("sizemeTracker.send", { - hitType: "event", - eventCategory: window.location.hostname, - eventAction: action, - eventLabel: label + " (v3)" - }); -}; + ((i, s, o, g, r) => { + if (!i[r]) { + i["GoogleAnalyticsObject"] = r; + i[r] = i[r] || + function () { + (i[r].q = i[r].q || []).push(arguments); + }; + i[r].l = 1 * new Date(); + let a = s.createElement(o); + let m = s.getElementsByTagName(o)[0]; + a.async = 1; + a.src = g; + m.parentNode.insertBefore(a, m); + } + })(window, document, "script", "https://www.google-analytics.com/analytics.js", "ga"); -trackEvent = (action, label) => { - switch (gaConsent()) { - case PENDING: - gaQueue.push(() => _trackEvent(action, label)); - break; + const gaTrackingId = !sizemeOptions.debugState ? prodTrackingId : devTrackingId; + let gaConsent = () => ENABLED; + const trackingConsentMethod = sizemeOptions.trackingConsentMethod; + const gaQueue = [() => { + ga("create", gaTrackingId, "auto", {name: "sizemeTracker"}); + }]; - case ENABLED: - gaQueue.forEach(fn => fn()); - _trackEvent(action, label); - trackEvent = _trackEvent; - break; + if (trackingConsentMethod) { + switch (trackingConsentMethod.toLowerCase()) { + case "optanon": + gaConsent = optanonConsent; + break; - case DISABLED: - trackEvent = () => {}; + default: + } } -}; + + const _trackEvent = (action, label) => { + ga("sizemeTracker.send", { + hitType: "event", + eventCategory: window.location.hostname, + eventAction: action, + eventLabel: label + " (v3)" + }); + }; + + + trackEvent = (action, label) => { + switch (gaConsent()) { + case PENDING: + gaQueue.push(() => _trackEvent(action, label)); + break; + + case ENABLED: + gaQueue.forEach(fn => fn()); + _trackEvent(action, label); + trackEvent = _trackEvent; + break; + + case DISABLED: + trackEvent = () => { + }; + } + }; +// eslint-disable-next-line +})(window.sizeme_options); + export { trackEvent }; diff --git a/src/api/sizeme-api.js b/src/api/sizeme-api.js index 23b5b7e..f2c2e55 100644 --- a/src/api/sizeme-api.js +++ b/src/api/sizeme-api.js @@ -1,4 +1,4 @@ -/* global sizeme_options, sizeme_product */ +/* global sizeme_product */ import "isomorphic-fetch"; import { trackEvent } from "./ga.js"; @@ -14,52 +14,62 @@ import uiOptions from "./uiOptions"; import equals from "shallow-equals"; import cookie from "react-cookie"; -const contextAddress = sizeme_options.contextAddress || "https://www.sizeme.com"; -const pluginVersion = sizeme_options.pluginVersion || "UNKNOWN"; +const sizemeOptions = () => window.sizeme_options || {}; + +const contextAddress = sizemeOptions().contextAddress || "https://www.sizeme.com"; +const pluginVersion = sizemeOptions().pluginVersion || "UNKNOWN"; const cdnLocation = "https://cdn.sizeme.com"; const storeMeasurementsKey = "sizemeMeasurements"; -const sizemeStore = createStore(rootReducer, applyMiddleware( - thunkMiddleware, - createLogger({ - predicate: () => sizeme_options.debugState, - duration: true - }) -)); - -function observeStore (select, onChange) { - let currentState; - - function handleChange () { - let nextState = select(sizemeStore.getState()); - if (!equals(nextState, currentState)) { - currentState = nextState; - onChange(currentState); - } +const sizemeStore = (sizemeOpts => { + if (!sizemeOpts) { + return {}; } - let unsubscribe = sizemeStore.subscribe(handleChange); - handleChange(); - return unsubscribe; -} - -observeStore( - ({ productInfo, selectedProfile, abStatus }) => ({ product: productInfo.product, selectedProfile, abStatus }), - ({ product, selectedProfile, abStatus }) => { - let smAction; - const statusPostFix = abStatus ? "-" + abStatus : ""; - if (!product) { - smAction = "noProduct" + statusPostFix; - } else if (!Object.values(selectedProfile.measurements).some(item => item)) { - smAction = "noHuman"; - } else if (!selectedProfile.id) { - smAction = "hasUnsaved"; - } else { - smAction = "hasProfile"; + const store = createStore(rootReducer, applyMiddleware( + thunkMiddleware, + createLogger({ + predicate: () => sizemeOpts.debugState, + duration: true + }) + )); + + function observeStore (select, onChange) { + let currentState; + + function handleChange () { + let nextState = select(store.getState()); + if (!equals(nextState, currentState)) { + currentState = nextState; + onChange(currentState); + } } - cookie.save("sm_action", smAction, { path: "/" }); + + let unsubscribe = store.subscribe(handleChange); + handleChange(); + return unsubscribe; } -); + + observeStore( + ({productInfo, selectedProfile, abStatus}) => ({product: productInfo.product, selectedProfile, abStatus}), + ({product, selectedProfile, abStatus}) => { + let smAction; + const statusPostFix = abStatus ? "-" + abStatus : ""; + if (!product) { + smAction = "noProduct" + statusPostFix; + } else if (!Object.values(selectedProfile.measurements).some(item => item)) { + smAction = "noHuman"; + } else if (!selectedProfile.id) { + smAction = "hasUnsaved"; + } else { + smAction = "hasProfile"; + } + cookie.save("sm_action", smAction, {path: "/"}); + } + ); + + return store; +})(window.sizeme_options); class FitRequest { constructor (subject, item) { diff --git a/src/api/uiOptions.js b/src/api/uiOptions.js index 80f0ff0..5962172 100644 --- a/src/api/uiOptions.js +++ b/src/api/uiOptions.js @@ -1,5 +1,3 @@ -/* global sizeme_options */ - const general = { disableSizeGuide: false, toggler: false @@ -26,5 +24,11 @@ const shops = { } }; -export default Object.assign({ shopType: sizeme_options.shopType }, general, - shops[sizeme_options.shopType], sizeme_options.uiOptions); +export default (sizemeOptions => { + if (sizemeOptions) { + return Object.assign({ shopType: sizemeOptions.shopType }, general, + shops[sizemeOptions.shopType], sizemeOptions.uiOptions); + } else { + return {}; + } +})(window.sizeme_options); \ No newline at end of file diff --git a/src/i18n.js b/src/i18n.js index 6db60e0..53ae1fe 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -41,8 +41,10 @@ i18n.init({ } }); -if (sizeme_options.additionalTranslations) { - const addtr = sizeme_options.additionalTranslations; +const additionalTranslations = window.sizeme_options ? sizeme_options.additionalTranslations : null; + +if (additionalTranslations) { + const addtr = additionalTranslations; ["en", "fi", "sv", "ar"].forEach(lng => { if (addtr[lng]) { i18n.addResourceBundle(lng, "translation", addtr[lng], true, true); diff --git a/src/index.js b/src/index.js index e99ba2b..bd4fdaa 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -/* global VERSION, BUILD_DATE, sizeme_options */ +/* global VERSION, BUILD_DATE */ import "babel-polyfill"; import React from "react"; @@ -14,76 +14,83 @@ import { trackEvent } from "./api/ga"; import i18n from "./i18n"; import "./scss/index.scss"; -console.log("Initializing SizeMe, version " + VERSION + ", built on " + BUILD_DATE); +(sizemeOptions => { + if (!sizemeOptions) { + return; + } -let sizemeDisabled = false; + console.log("Initializing SizeMe, version " + VERSION + ", built on " + BUILD_DATE); -if (sizeme_options.serviceStatus === "ab") { - const storageABValue = localStorage.getItem("sizemeABDisabled"); + let sizemeDisabled = false; - if (!storageABValue) { - sizemeDisabled = Math.floor(Math.random() * 100) % 2 === 0; - localStorage.setItem("sizemeABDisabled", JSON.stringify(sizemeDisabled)); - } else { - sizemeDisabled = JSON.parse(storageABValue); - } - const abStatus = sizemeDisabled ? "B" : "A"; - console.log("SizeMe A/B testing, status: " + abStatus); - sizemeStore.dispatch(setAbStatus(abStatus)); + if (sizemeOptions.serviceStatus === "ab") { + const storageABValue = localStorage.getItem("sizemeABDisabled"); - if (sizemeDisabled) { - trackEvent("productPageLoggedOutABDenied", "Store: Product page load, logged out, AB SM denied"); - } else { - trackEvent("productPageLoggedOutABEnabled", "Store: Product page load, logged out, AB SM enabled"); - } -} + if (!storageABValue) { + sizemeDisabled = Math.floor(Math.random() * 100) % 2 === 0; + localStorage.setItem("sizemeABDisabled", JSON.stringify(sizemeDisabled)); + } else { + sizemeDisabled = JSON.parse(storageABValue); + } + + const abStatus = sizemeDisabled ? "B" : "A"; + console.log("SizeMe A/B testing, status: " + abStatus); + sizemeStore.dispatch(setAbStatus(abStatus)); -const { addToCartElement, addToCartEvent } = uiOptions; -if (addToCartElement && addToCartEvent) { - const elements = document.querySelectorAll(addToCartElement); - const fn = () => { - const { authToken, productInfo } = sizemeStore.getState(); - const loggedIn = authToken.loggedIn; - const sizemeProductPage = productInfo.product !== null; - if (loggedIn && sizemeProductPage) { - trackEvent("addToCartSM", "Store: Product added to cart by SizeMe user"); - } else if (loggedIn && !sizemeProductPage) { - trackEvent("addNonSMToCartSM", "Store: Non-SizeMe product added to cart by SizeMe user"); - } else if (!loggedIn && sizemeProductPage) { - trackEvent("addToCart", "Store: Product added to cart"); + if (sizemeDisabled) { + trackEvent("productPageLoggedOutABDenied", "Store: Product page load, logged out, AB SM denied"); } else { - trackEvent("addNonSMToCart", "Store: Non-SizeMe product added to cart"); + trackEvent("productPageLoggedOutABEnabled", "Store: Product page load, logged out, AB SM enabled"); } - }; - for (let i = 0; i < elements.length; i++) { - elements.item(i).addEventListener(addToCartEvent, fn); } -} -if (uiOptions.toggler) { - const sizemeHidden = !JSON.parse(localStorage.getItem("sizemeToggledVisible")); - setSizemeHidden(sizemeHidden)(sizemeStore.dispatch); -} + const {addToCartElement, addToCartEvent} = uiOptions; + if (addToCartElement && addToCartEvent) { + const elements = document.querySelectorAll(addToCartElement); + const fn = () => { + const {authToken, productInfo} = sizemeStore.getState(); + const loggedIn = authToken.loggedIn; + const sizemeProductPage = productInfo.product !== null; + if (loggedIn && sizemeProductPage) { + trackEvent("addToCartSM", "Store: Product added to cart by SizeMe user"); + } else if (loggedIn && !sizemeProductPage) { + trackEvent("addNonSMToCartSM", "Store: Non-SizeMe product added to cart by SizeMe user"); + } else if (!loggedIn && sizemeProductPage) { + trackEvent("addToCart", "Store: Product added to cart"); + } else { + trackEvent("addNonSMToCart", "Store: Non-SizeMe product added to cart"); + } + }; + for (let i = 0; i < elements.length; i++) { + elements.item(i).addEventListener(addToCartEvent, fn); + } + } + + if (uiOptions.toggler) { + const sizemeHidden = !JSON.parse(localStorage.getItem("sizemeToggledVisible")); + setSizemeHidden(sizemeHidden)(sizemeStore.dispatch); + } -if (!sizemeDisabled) { - // postpone execution of this block to wait for the shop UI to finish rendering. At least - // with KooKenka accordion component this was needed - setTimeout(() => { - const el = findVisibleElement(uiOptions.appendContentTo); + if (!sizemeDisabled) { + // postpone execution of this block to wait for the shop UI to finish rendering. At least + // with KooKenka accordion component this was needed + setTimeout(() => { + const el = findVisibleElement(uiOptions.appendContentTo); - if (el) { - const section = el.appendChild(document.createElement("div")); - //noinspection RequiredAttributes - render( - - - - - , - section, - () => SizeSelector.initSizeSelector(size => sizemeStore.dispatch(selectSize(size, false))) - ); - } - }); -} + if (el) { + const section = el.appendChild(document.createElement("div")); + //noinspection RequiredAttributes + render( + + + + + , + section, + () => SizeSelector.initSizeSelector(size => sizemeStore.dispatch(selectSize(size, false))) + ); + } + }); + } +})(window.sizeme_options); diff --git a/webpack.config.js b/webpack.config.js index 9c7301e..87fce9f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -71,7 +71,8 @@ const developmentConfig = merge([ parts.page({ template: "selectric.html", filename: "selectric.html" }), parts.page({ template: "makia1.html", filename: "makia1.html" }), parts.page({ template: "harrysoflondon.html", filename: "harrysoflondon.html" }), - parts.page({ template: "levelshoes.html", filename: "levelshoes.html" }) + parts.page({ template: "levelshoes.html", filename: "levelshoes.html" }), + parts.page({ template: "nosizeme.html", filename: "nosizeme.html" }) ]); const productionConfig = merge([