From 7a26d46d7c98ff6df03716680f0cb80bd2b4c649 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Fri, 11 Oct 2024 09:35:08 +0100 Subject: [PATCH] Add Hotjar script to the home page (#20758) GitOrigin-RevId: b7fdb904702d84058c2e3519b17376083ee9cad7 --- .../Features/StaticPages/HomeController.js | 7 +++ .../app/src/infrastructure/ExpressLocals.js | 2 + .../js/features/cookie-banner/index.js | 2 + .../web/frontend/js/infrastructure/hotjar.ts | 45 +++++++++++++++++++ .../frontend/js/pages/marketing/homepage.js | 1 + services/web/types/exposed-settings.ts | 2 + 6 files changed, 59 insertions(+) create mode 100644 services/web/frontend/js/infrastructure/hotjar.ts diff --git a/services/web/app/src/Features/StaticPages/HomeController.js b/services/web/app/src/Features/StaticPages/HomeController.js index b7d914407e..60cba7fe79 100644 --- a/services/web/app/src/Features/StaticPages/HomeController.js +++ b/services/web/app/src/Features/StaticPages/HomeController.js @@ -9,6 +9,7 @@ const SessionManager = require('../Authentication/SessionManager') const { expressify } = require('@overleaf/promise-utils') const logger = require('@overleaf/logger') +const SplitTestHandler = require('../SplitTests/SplitTestHandler') const homepageExists = fs.existsSync( Path.join( @@ -35,6 +36,12 @@ async function home(req, res) { page: req.path, }) + try { + await SplitTestHandler.promises.getAssignment(req, res, 'hotjar') + } catch { + // do nothing + } + res.render('external/home/website-redesign/index') } else { res.redirect('/login') diff --git a/services/web/app/src/infrastructure/ExpressLocals.js b/services/web/app/src/infrastructure/ExpressLocals.js index 4b2042a29d..b81c3f5dc7 100644 --- a/services/web/app/src/infrastructure/ExpressLocals.js +++ b/services/web/app/src/infrastructure/ExpressLocals.js @@ -406,6 +406,8 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) { sentryDsn: Settings.sentry.publicDSN, sentryEnvironment: Settings.sentry.environment, sentryRelease: Settings.sentry.release, + hotjarId: Settings.hotjar?.id, + hotjarVersion: Settings.hotjar?.version, enableSubscriptions: Settings.enableSubscriptions, gaToken: Settings.analytics && diff --git a/services/web/frontend/js/features/cookie-banner/index.js b/services/web/frontend/js/features/cookie-banner/index.js index a22046a08d..20f62db8a5 100644 --- a/services/web/frontend/js/features/cookie-banner/index.js +++ b/services/web/frontend/js/features/cookie-banner/index.js @@ -20,8 +20,10 @@ function setConsent(value) { if (value === 'all') { document.cookie = 'oa=1' + cookieAttributes loadGA() + window.dispatchEvent(new CustomEvent('cookie-consent', { detail: true })) } else { document.cookie = 'oa=0' + cookieAttributes + window.dispatchEvent(new CustomEvent('cookie-consent', { detail: false })) } } diff --git a/services/web/frontend/js/infrastructure/hotjar.ts b/services/web/frontend/js/infrastructure/hotjar.ts new file mode 100644 index 0000000000..f024ce472f --- /dev/null +++ b/services/web/frontend/js/infrastructure/hotjar.ts @@ -0,0 +1,45 @@ +import getMeta from '@/utils/meta' +import { isSplitTestEnabled } from '@/utils/splitTestUtils' +import { debugConsole } from '@/utils/debugging' + +const { hotjarId, hotjarVersion } = getMeta('ol-ExposedSettings') + +if (hotjarId && hotjarVersion && isSplitTestEnabled('hotjar')) { + const loadHotjar = () => { + // consent needed + if (!document.cookie.split('; ').some(item => item === 'oa=1')) { + return + } + + // avoid inserting twice + if (document.getElementById('hotjar')) { + return + } + + debugConsole.log('Loading Hotjar') + + const url = new URL(`https://static.hotjar.com/c/hotjar-${hotjarId}.js`) + url.searchParams.set('sv', hotjarVersion) + + const script = document.createElement('script') + script.src = url.toString() + script.async = true + script.id = 'hotjar' + + document.head.append(script) + } + + // load when idle, if supported + if (typeof window.requestIdleCallback === 'function') { + window.requestIdleCallback(loadHotjar) + } else { + loadHotjar() + } + + // listen for consent + window.addEventListener('cookie-consent', event => { + if ((event as CustomEvent).detail) { + loadHotjar() + } + }) +} diff --git a/services/web/frontend/js/pages/marketing/homepage.js b/services/web/frontend/js/pages/marketing/homepage.js index 47b0e7e55e..47a368ec97 100644 --- a/services/web/frontend/js/pages/marketing/homepage.js +++ b/services/web/frontend/js/pages/marketing/homepage.js @@ -1,4 +1,5 @@ import '../../marketing' +import '../../infrastructure/hotjar' // set up Hotjar function homepageAnimation(homepageAnimationEl) { function createFrames(word, { buildTime, holdTime, breakTime }) { diff --git a/services/web/types/exposed-settings.ts b/services/web/types/exposed-settings.ts index 19584e685c..b4f52dcdfa 100644 --- a/services/web/types/exposed-settings.ts +++ b/services/web/types/exposed-settings.ts @@ -19,6 +19,8 @@ export type ExposedSettings = { hasLinkedProjectOutputFileFeature: boolean hasSamlBeta?: boolean hasSamlFeature: boolean + hotjarId?: string + hotjarVersion?: string ieeeBrandId: number isOverleaf: boolean maxEntitiesPerProject: number