function Analytics() { this.BASE_URL = null; // Session this.sessionId = null; this.sessionDuration = 0; this.sessionIntervalId = null; // Click this.globalClickHandler = null; this.clickTimeoutTime = 1000; this.clickTimeoutId = null; this.clicks = []; }; Analytics.prototype.trackClicks = function () { if (this.globalClickHandler !== null) return; let clickBucket = []; this.globalClickHandler = function clickhandler() { let mouseX, mouseY = null; if (event.clientX !== undefined && event.clientY !== undefined) { mouseX = event.clientX; mouseY = event.clientY; } else if (event.touches && event.touches[0]) { mouseX = event.touches[0].clientX; mouseY = event.touches[0].clientY; } if (mouseX === null || mouseY === null) return; clickBucket.push(); analytics.clicks.push({ x: mouseX, y: mouseY }); //clearTimeout(analytics.clickTimeoutId); // analytics.clickTimeoutId = setTimeout(() => { // console.log(clickBucket); // // if > 5, clicks are spam // if (clickBucket.length <= 5) analytics.clicks = [...analytics.clicks, ...clickBucket]; // clickBucket = []; // }, analytics.clickTimeoutTime); } document.addEventListener('click', this.globalClickHandler); } Analytics.prototype.startSessionTrack = function () { analytics.stopSessionTrack(); analytics.sessionIntervalId = setInterval(() => { if (document.visibilityState === 'visible') analytics.sessionDuration++; }, 1000); } Analytics.prototype.stopSessionTrack = function () { clearInterval(analytics.sessionIntervalId); analytics.sessionDuration = 0; } Analytics.prototype.trackUserRegistration = function (data) { let api = analytics.BASE_URL + '/api/analytics/track/user-registration' let affiliateHiveSlug = getCookie('affiliate-hive-slug'); data.affiliateHiveSlug = affiliateHiveSlug; fetch(api, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(data) }); } Analytics.prototype.initBeacon = function () { if (analytics.BASE_URL === null) { console.error("Analytics: BASE_URL is not set."); return; } document.addEventListener("visibilitychange", function logData() { if (document.visibilityState === "hidden") { let sendBeaconRequest = true; let analyticsData = { userSessionId: analytics.sessionId, sessionDuration: analytics.sessionDuration, affiliateHiveSlug: getCookie('affiliate-hive-slug'), pageURL: window.location.href, clicks: analytics.clicks, }; if (sendBeaconRequest === true) { navigator.sendBeacon(analytics.BASE_URL + '/api/analytics/track', JSON.stringify(analyticsData)); analytics.clicks = []; } analytics.stopSessionTrack(); } else if (document.visibilityState === 'visible') { analytics.startSessionTrack(); } }); } Analytics.prototype.initSession = function () { let s = null; let sessionStr = localStorage.getItem("analytics-session"); if (sessionStr === null) { s = generateSession(); localStorage.setItem("analytics-session", JSON.stringify(s)); } else { let sessionObj = JSON.parse(sessionStr); s = sessionObj; let now = new Date().getTime(); if (now > sessionObj.expiration) { s = generateSession(); localStorage.setItem("analytics-session", JSON.stringify(s)); } } analytics.sessionId = s.sessionId; function generateSession() { // expires at the end of the day 12:00am // (keep this time for front ends filters to work properly) return { sessionId: uid('analytics'), expiration: new Date().getTime() + (minutesUntilEndOfDay() * 60 * 1000) } } } Analytics.prototype.init = function (BASE_URL = null) { analytics.BASE_URL = BASE_URL; this.initSession(); this.trackClicks(); this.startSessionTrack(); this.initBeacon(); } var analytics = new Analytics(); function uid(prefix = '') { let timestamp = Date.now().toString(36); let randomString = ''; for (let i = 0; i < 8; i++) { randomString += Math.random().toString(36).substring(2, 10); } let randomNum = Math.floor(Math.random() * 1000); return prefix + timestamp + randomNum.toString() + randomString; } function getDateTime() { const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const hours = String(now.getHours()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0'); const seconds = String(now.getSeconds()).padStart(2, '0'); const amOrPm = hours >= 12 ? 'PM' : 'AM'; const formattedDateTime = `${year}/${month}/${day} ${hours % 12}:${minutes}:${seconds} ${amOrPm}`; return formattedDateTime; } function getTimezoneName() { const now = new Date(); const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; return timezone; } function minutesUntilEndOfDay() { const currentDate = new Date(); const endOfDay = new Date(currentDate); endOfDay.setDate(currentDate.getDate() + 1); endOfDay.setHours(0, 0, 0, 0); const timeDifferenceMs = endOfDay - currentDate; const minutesUntilEnd = Math.floor(timeDifferenceMs / (1000 * 60)); return minutesUntilEnd; } function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); }