From c85efe0067a741c013ad413c9f3c2746ca3ee855 Mon Sep 17 00:00:00 2001 From: Prince Date: Thu, 26 Sep 2024 15:13:10 +0400 Subject: [PATCH] chore: added analytics caching script --- public/scripts/analytics.js | 173 ++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 public/scripts/analytics.js diff --git a/public/scripts/analytics.js b/public/scripts/analytics.js new file mode 100644 index 0000000000000..2c94f46ac528f --- /dev/null +++ b/public/scripts/analytics.js @@ -0,0 +1,173 @@ +const cacheTrackEvents = { + interval: null, + responses: [], + isTrackingResponses: false, + trackPageUnload: () => { + window.addEventListener("beforeunload", (event) => { + if (!cacheTrackEvents.isPageViewSent()) { + cacheTrackEvents.push("cached_analytics_page_views", { + name: window.location.href, + properties: { + url: window.location.href, + }, + }); + } + }); + }, + trackResponses: () => { + const originalXhrOpen = XMLHttpRequest.prototype.open; + const originalXhrSend = XMLHttpRequest.prototype.send; + + XMLHttpRequest.prototype.open = function (method, url) { + this._url = url; + this._method = method; + return originalXhrOpen.apply(this, arguments); + }; + + XMLHttpRequest.prototype.send = function (body) { + this.addEventListener("load", function () { + let parsedPayload = null; + + if (typeof body === "string") { + try { + parsedPayload = JSON.parse(body); + } catch (e) { + parsedPayload = body; + } + } + + const responseData = { + url: this._url, + method: this._method, + status: this.status, + headers: this.getAllResponseHeaders(), + data: this.responseText, + payload: parsedPayload, + }; + cacheTrackEvents.responses.push(responseData); + }); + + return originalXhrSend.apply(this, arguments); + }; + }, + isReady: () => { + if (typeof Analytics === "undefined" || Analytics === null) { + return false; + } + + const instances = Analytics.Analytics.getInstances(); + return !!(instances?.tracking && instances?.ab); + }, + parseCookies: (cookieName) => { + const cookies = document.cookie.split("; ").reduce((acc, cookie) => { + const [key, value] = cookie.split("="); + acc[decodeURIComponent(key)] = decodeURIComponent(value); + return acc; + }, {}); + + return JSON.parse(cookies[cookieName] || null); + }, + isPageViewSent: () => + !!cacheTrackEvents.responses.find( + (e) => e.payload?.type === "page" && e.payload?.anonymousId + ), + set: (event) => { + cacheTrackEvents.push("cached_analytics_events", event); + }, + push: (cookieName, data) => { + let storedCookies = []; + const cacheCookie = cacheTrackEvents.parseCookies(cookieName); + if (cacheCookie) storedCookies = cacheCookie; + storedCookies.push(data); + + document.cookie = `${cookieName}=${JSON.stringify( + storedCookies + )}; path=/; Domain=.deriv.com`; + }, + track: (event) => { + if (cacheTrackEvents.isReady()) { + Analytics.Analytics.trackEvent(event.name, event.properties); + } else { + cacheTrackEvents.set(event); + } + }, + pageView: () => { + if (!cacheTrackEvents.isTrackingResponses) { + cacheTrackEvents.trackResponses(); + cacheTrackEvents.trackPageUnload(); + } + + let pageViewInterval = null; + + pageViewInterval = setInterval(() => { + if ( + typeof Analytics.Analytics?.pageView === "function" && + cacheTrackEvents.isReady() + ) { + Analytics?.Analytics?.pageView(window.location.href); + } + + if (cacheTrackEvents.isPageViewSent()) { + clearInterval(pageViewInterval); + } + }, 1000); + }, + listen: (element, { name, properties }) => { + const addClickListener = (el) => { + if (!el.dataset.clickEventTracking) { + el.addEventListener("click", function () { + cacheTrackEvents.track({ + name, + properties, + }); + }); + el.dataset.clickEventTracking = "true"; + } + }; + + const elements = + element instanceof NodeList ? Array.from(element) : [element]; + + elements.forEach(addClickListener); + }, + + addEventhandler: (items) => { + cacheTrackEvents.interval = setInterval(() => { + let allListenersApplied = true; + + items.forEach(({ element, event }) => { + const elem = document.querySelectorAll(element); + const elements = elem instanceof NodeList ? Array.from(elem) : [elem]; + + if (!elements.length) { + allListenersApplied = false; + } + + elements.forEach((el) => { + if (!el.dataset.clickEventTracking) { + cacheTrackEvents.listen(el, event); + allListenersApplied = false; + } + }); + }); + + if (allListenersApplied) { + clearInterval(cacheTrackEvents.interval); + } + }, 1); + + return cacheTrackEvents; + }, + loadEvent: (items) => { + items.forEach(({ event }) => { + const { name, properties } = event; + cacheTrackEvents.track({ + name, + properties, + }); + }); + + return cacheTrackEvents; + }, + }; +