diff --git a/.env b/.env
index 315c33e1c..cce0b78ef 100644
--- a/.env
+++ b/.env
@@ -28,3 +28,6 @@ ENABLE_PROGRESS_GRAPH_SETTINGS=false
ENABLE_TEAM_TYPE_SETTING=false
ENABLE_NEW_EDITOR_PAGES=true
BBB_LEARN_MORE_URL=''
+HOTJAR_APP_ID=''
+HOTJAR_VERSION=6
+HOTJAR_DEBUG=false
diff --git a/.env.development b/.env.development
index ace285e48..82a140c35 100644
--- a/.env.development
+++ b/.env.development
@@ -30,3 +30,6 @@ ENABLE_PROGRESS_GRAPH_SETTINGS=false
ENABLE_TEAM_TYPE_SETTING=false
ENABLE_NEW_EDITOR_PAGES=true
BBB_LEARN_MORE_URL=''
+HOTJAR_APP_ID=''
+HOTJAR_VERSION=6
+HOTJAR_DEBUG=true
diff --git a/package-lock.json b/package-lock.json
index 98864297b..84712642e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "11.1.1",
+ "@edx/frontend-enterprise-hotjar": "^1.2.1",
"@edx/frontend-lib-content-components": "^1.135.1",
"@edx/frontend-platform": "2.5.1",
"@edx/paragon": "^20.28.0",
@@ -32,8 +33,8 @@
"react-helmet": "^6.1.0",
"react-redux": "7.1.3",
"react-responsive": "8.1.0",
- "react-router": "5.1.2",
- "react-router-dom": "5.1.2",
+ "react-router": "5.2.0",
+ "react-router-dom": "5.2.0",
"react-transition-group": "4.4.1",
"redux": "4.0.5",
"regenerator-runtime": "0.13.7",
@@ -2228,6 +2229,16 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/@edx/frontend-enterprise-hotjar": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@edx/frontend-enterprise-hotjar/-/frontend-enterprise-hotjar-1.2.1.tgz",
+ "integrity": "sha512-0UyvVdyY3d+OpKG4P88mTmaoDtaT869VRxSIHX46wPDC18J+A1yE5XVrX2yDdeXF/HgawI5h2t0Y1Lkf2JDKQA==",
+ "peerDependencies": {
+ "react": "^16.12.0",
+ "react-dom": "^16.12.0",
+ "react-router-dom": "^5.2.0"
+ }
+ },
"node_modules/@edx/frontend-lib-content-components": {
"version": "1.135.1",
"resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-1.135.1.tgz",
@@ -17415,20 +17426,6 @@
"node": ">=4"
}
},
- "node_modules/mini-create-react-context": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.3.tgz",
- "integrity": "sha512-TtF6hZE59SGmS4U8529qB+jJFeW6asTLDIpPgvPLSCsooAwJS7QprHIFTqv9/Qh3NdLwQxFYgiHX5lqb6jqzPA==",
- "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
- "dependencies": {
- "@babel/runtime": "^7.12.1",
- "tiny-warning": "^1.0.3"
- },
- "peerDependencies": {
- "prop-types": "^15.0.0",
- "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
- }
- },
"node_modules/mini-css-extract-plugin": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz",
@@ -20633,15 +20630,15 @@
}
},
"node_modules/react-router": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz",
- "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
+ "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
"dependencies": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"hoist-non-react-statics": "^3.1.0",
"loose-envify": "^1.3.1",
- "mini-create-react-context": "^0.3.0",
+ "mini-create-react-context": "^0.4.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
@@ -20653,15 +20650,15 @@
}
},
"node_modules/react-router-dom": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.1.2.tgz",
- "integrity": "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz",
+ "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==",
"dependencies": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
- "react-router": "5.1.2",
+ "react-router": "5.2.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
},
@@ -20669,6 +20666,20 @@
"react": ">=15"
}
},
+ "node_modules/react-router/node_modules/mini-create-react-context": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
+ "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
+ "dependencies": {
+ "@babel/runtime": "^7.12.1",
+ "tiny-warning": "^1.0.3"
+ },
+ "peerDependencies": {
+ "prop-types": "^15.0.0",
+ "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
+ }
+ },
"node_modules/react-side-effect": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
@@ -26925,6 +26936,12 @@
}
}
},
+ "@edx/frontend-enterprise-hotjar": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@edx/frontend-enterprise-hotjar/-/frontend-enterprise-hotjar-1.2.1.tgz",
+ "integrity": "sha512-0UyvVdyY3d+OpKG4P88mTmaoDtaT869VRxSIHX46wPDC18J+A1yE5XVrX2yDdeXF/HgawI5h2t0Y1Lkf2JDKQA==",
+ "requires": {}
+ },
"@edx/frontend-lib-content-components": {
"version": "1.135.1",
"resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-1.135.1.tgz",
@@ -38620,15 +38637,6 @@
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true
},
- "mini-create-react-context": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.3.tgz",
- "integrity": "sha512-TtF6hZE59SGmS4U8529qB+jJFeW6asTLDIpPgvPLSCsooAwJS7QprHIFTqv9/Qh3NdLwQxFYgiHX5lqb6jqzPA==",
- "requires": {
- "@babel/runtime": "^7.12.1",
- "tiny-warning": "^1.0.3"
- }
- },
"mini-css-extract-plugin": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz",
@@ -40956,32 +40964,43 @@
}
},
"react-router": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.1.2.tgz",
- "integrity": "sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
+ "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==",
"requires": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"hoist-non-react-statics": "^3.1.0",
"loose-envify": "^1.3.1",
- "mini-create-react-context": "^0.3.0",
+ "mini-create-react-context": "^0.4.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
+ },
+ "dependencies": {
+ "mini-create-react-context": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
+ "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
+ "requires": {
+ "@babel/runtime": "^7.12.1",
+ "tiny-warning": "^1.0.3"
+ }
+ }
}
},
"react-router-dom": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.1.2.tgz",
- "integrity": "sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz",
+ "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==",
"requires": {
"@babel/runtime": "^7.1.2",
"history": "^4.9.0",
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
- "react-router": "5.1.2",
+ "react-router": "5.2.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
}
diff --git a/package.json b/package.json
index ec8f7c11f..81a154c7d 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-footer": "11.1.1",
+ "@edx/frontend-enterprise-hotjar": "^1.2.1",
"@edx/frontend-lib-content-components": "^1.135.1",
"@edx/frontend-platform": "2.5.1",
"@edx/paragon": "^20.28.0",
@@ -56,8 +57,8 @@
"react-helmet": "^6.1.0",
"react-redux": "7.1.3",
"react-responsive": "8.1.0",
- "react-router": "5.1.2",
- "react-router-dom": "5.1.2",
+ "react-router": "5.2.0",
+ "react-router-dom": "5.2.0",
"react-transition-group": "4.4.1",
"redux": "4.0.5",
"regenerator-runtime": "0.13.7",
diff --git a/src/index.jsx b/src/index.jsx
index 594f8d0ab..337d1f631 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -5,12 +5,14 @@ import {
APP_INIT_ERROR, APP_READY, subscribe, initialize, mergeConfig,
} from '@edx/frontend-platform';
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
-import React from 'react';
+import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
import { Route, Switch } from 'react-router-dom';
import { messages as footerMessages } from '@edx/frontend-component-footer';
+import { initializeHotjar } from '@edx/frontend-enterprise-hotjar';
+import { logError } from '@edx/frontend-platform/logging';
import appMessages from './i18n';
import initializeStore from './store';
@@ -18,8 +20,22 @@ import './index.scss';
import CourseAuthoringRoutes from './CourseAuthoringRoutes';
import Head from './head/Head';
-subscribe(APP_READY, () => {
- ReactDOM.render(
+const App = () => {
+ useEffect(() => {
+ if (process.env.HOTJAR_APP_ID) {
+ try {
+ initializeHotjar({
+ hotjarId: process.env.HOTJAR_APP_ID,
+ hotjarVersion: process.env.HOTJAR_VERSION,
+ hotjarDebug: !!process.env.HOTJAR_DEBUG,
+ });
+ } catch (error) {
+ logError(error);
+ }
+ }
+ }, []);
+
+ return (
@@ -33,7 +49,13 @@ subscribe(APP_READY, () => {
}}
/>
- ,
+
+ );
+};
+
+subscribe(APP_READY, () => {
+ ReactDOM.render(
+ (),
document.getElementById('root'),
);
});