diff --git a/assets/src/components/GoogleAnalyticsTracking.js b/assets/src/components/GoogleAnalyticsTracking.js new file mode 100644 index 00000000..f00fd35a --- /dev/null +++ b/assets/src/components/GoogleAnalyticsTracking.js @@ -0,0 +1,30 @@ +import { useState, useEffect } from 'react' +import GoogleAnalytics from 'react-ga4' + +function GoogleAnalyticsTracking (props) { + const { gaId, cspNonce } = props + + const [initialized, setInitialized] = useState(false) + const [previousPage, setPreviousPage] = useState(null) + + if (gaId && !initialized) { + setInitialized(true) + GoogleAnalytics.initialize([{ + trackingId: gaId, + gaOptions: { nonce: cspNonce, cookieFlags: 'SameSite=None; Secure' } + }]) + } + + useEffect(() => { + const page = window.location.pathname + window.location.search + window.location.hash + if (gaId && page !== previousPage) { + setPreviousPage(page) + GoogleAnalytics.send({ hitType: 'pageview', page }) + } + }) + + return null +} + +export default GoogleAnalyticsTracking + \ No newline at end of file diff --git a/assets/src/containers/App.js b/assets/src/containers/App.js index b9226fb3..2a131928 100755 --- a/assets/src/containers/App.js +++ b/assets/src/containers/App.js @@ -1,15 +1,14 @@ import React from 'react' import { Route, Routes, useMatch } from 'react-router-dom' +import GoogleAnalyticsTracking from '../components/GoogleAnalyticsTracking' import CourseList from './CourseList' import Course from './Course' import WarningBanner from '../components/WarningBanner' import AlertBanner from '../components/AlertBanner' import { Helmet } from 'react-helmet' -import useGoogleAnalytics from 'react-ga-onetrust-consent' function App (props) { - const { user, gaId, cspNonce, oneTrustScriptDomain } = props - useGoogleAnalytics({ googleAnalyticsId: gaId, nonce: cspNonce, oneTrustScriptDomain}) + const { user, gaId, cspNonce } = props if (!user.isLoggedIn) { if (user.loginURL === '') { @@ -22,6 +21,7 @@ function App (props) { return ( <> + } /> } /> diff --git a/assets/src/globals.js b/assets/src/globals.js index fd9d219d..f6a56252 100644 --- a/assets/src/globals.js +++ b/assets/src/globals.js @@ -55,6 +55,5 @@ const siteTheme = createTheme({ props: componentSettings }) const gaId = mylaGlobals.google_analytics_id -const oneTrustScriptDomain = mylaGlobals.one_trust_script_domain -export { user, siteTheme, gaId, cspNonce,oneTrustScriptDomain, viewHelpURLs, surveyLink } +export { user, siteTheme, gaId, cspNonce, viewHelpURLs, surveyLink } diff --git a/assets/src/index.js b/assets/src/index.js index e0bcd366..a3fb8d67 100755 --- a/assets/src/index.js +++ b/assets/src/index.js @@ -6,7 +6,7 @@ import './index.css' import App from './containers/App' import client from './service/client' import { ApolloProvider } from '@apollo/client' -import { user, siteTheme, gaId, cspNonce, oneTrustScriptDomain } from './globals' +import { user, siteTheme, gaId, cspNonce } from './globals' // import * as serviceWorker from './serviceWorker' const container = document.getElementById('root') @@ -15,7 +15,7 @@ root.render( - + diff --git a/config/env_sample.hjson b/config/env_sample.hjson index 2ac31cf5..f367b8db 100644 --- a/config/env_sample.hjson +++ b/config/env_sample.hjson @@ -11,15 +11,12 @@ ], # The URL of a generic help or documentation site, to be used in the front end's drop-down menu "HELP_URL": "https://its.umich.edu/academics-research/teaching-learning/my-learning-analytics", - "PRIVACY_REDIRECT_URL": "https://umich.edu/about/privacy/" # Help for views. Specify URLs to overide defaults # URL_VIEW_RESOURCES_ACCESSED # URL_VIEW_ASSIGNMENT_PLANNING # URL_VIEW_GRADE_DISTRIBUTION # ID for your Google Analytics, defaults to nothing/disabled "GA_ID": "", - # ID of OneTrust script domain, used for google analytics integration - "OT_SCRIPT_DOMAIN": "" # The hex value to be used in the front end for the primary color of the palette and theme "PRIMARY_UI_COLOR": "#00274C", # Configuration of CSP see https://django-csp.readthedocs.io/en/latest/configuration.html diff --git a/dashboard/common/utils.py b/dashboard/common/utils.py index 9a32edb7..cb27c1b9 100644 --- a/dashboard/common/utils.py +++ b/dashboard/common/utils.py @@ -103,8 +103,6 @@ def get_myla_globals(request): if settings.GA_ID: google_analytics_id = settings.GA_ID - if settings.OT_SCRIPT_DOMAIN: - one_trust_script_domain = settings.OT_SCRIPT_DOMAIN primary_ui_color = settings.PRIMARY_UI_COLOR myla_globals = { @@ -117,7 +115,6 @@ def get_myla_globals(request): "logout": logout_url, "primary_ui_color": primary_ui_color, "google_analytics_id": google_analytics_id, - "one_trust_script_domain": one_trust_script_domain, "view_help_urls": { 'ra': settings.URL_VIEW_RESOURCES_ACCESSED, 'ap': settings.URL_VIEW_ASSIGNMENT_PLANNING, diff --git a/dashboard/settings.py b/dashboard/settings.py index 56aa013a..99acf547 100644 --- a/dashboard/settings.py +++ b/dashboard/settings.py @@ -70,7 +70,6 @@ def apply_env_overrides(env: Dict[str, Any], environ: os._Environ) -> Dict[str, LOGIN_URL = '/accounts/login/' LOGOUT_URL = '/accounts/logout/' HELP_URL = ENV.get("HELP_URL", "https://its.umich.edu/academics-research/teaching-learning/my-learning-analytics") -PRIVACY_REDIRECT_URL = ENV.get("PRIVACY_REDIRECT_URL","https://umich.edu/about/privacy/") URL_VIEW_RESOURCES_ACCESSED = ENV.get("URL_VIEW_RESOURCES_ACCESSED", "https://its.umich.edu/academics-research/teaching-learning/my-learning-analytics/support/resources-accessed") URL_VIEW_ASSIGNMENT_PLANNING = ENV.get("URL_VIEW_ASSIGNMENT_PLANNING", "https://its.umich.edu/academics-research/teaching-learning/my-learning-analytics/support/assignment-planning-goals") @@ -78,7 +77,6 @@ def apply_env_overrides(env: Dict[str, Any], environ: os._Environ) -> Dict[str, # Google Analytics ID GA_ID = ENV.get('GA_ID', '') -OT_SCRIPT_DOMAIN = ENV.get('OT_SCRIPT_DOMAIN', '') # Resource values from env RESOURCE_VALUES = ENV.get("RESOURCE_VALUES", {"files": {"types": ["canvas"], "icon": "fas fa-file fa-lg"}}) diff --git a/dashboard/urls.py b/dashboard/urls.py index de058777..542a2adf 100644 --- a/dashboard/urls.py +++ b/dashboard/urls.py @@ -42,8 +42,6 @@ path('status/bare_status/', watchman.views.bare_status), path('admin/', admin.site.urls), - # Use PRIVACY_REDIRECT_URL for the privacy policy - path('privacy/', views.privacy_policy_redirect, name='privacy_policy'), # Note the absence of a trailing slash; adding one breaks the GraphQL implementation. path('graphql', DashboardGraphQLView.as_view( middleware=[] if settings.DEBUG else [DisableIntrospectionMiddleware],graphiql=settings.DEBUG)), diff --git a/dashboard/views.py b/dashboard/views.py index f0c2eeb5..be0a0b68 100644 --- a/dashboard/views.py +++ b/dashboard/views.py @@ -678,8 +678,6 @@ def logout(request): auth.logout(request) return redirect(settings.LOGOUT_REDIRECT_URL) -def privacy_policy_redirect(request): - return redirect(settings.PRIVACY_REDIRECT_URL) def courses_enabled(request): """ Returns json for all courses we currently support and are enabled """ diff --git a/package-lock.json b/package-lock.json index 9802a18a..4ae2c4df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,11 +20,11 @@ "lodash.debounce": "4.0.8", "lodash.isequal": "4.5.0", "rc-slider": "10.5.0", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-ga-onetrust-consent": "github:tl-its-umich-edu/react-ga-onetrust-consent", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-ga4": "2.1.0", "react-helmet": "6.1.0", - "react-router-dom": "6.25.1" + "react-router-dom": "6.21.1" }, "devDependencies": { "@babel/cli": "7.23.4", @@ -2172,28 +2172,28 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz", - "integrity": "sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==", + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.5.tgz", + "integrity": "sha512-8GrTWmoFhm5BsMZOTHeGD2/0FLKLQQHvO/ZmQga4tKempYRLz8aqJGqXVuQgisnMObq2YZ2SgkwctN1LOOxcqA==", "dependencies": { - "@floating-ui/utils": "^0.1.3" + "@floating-ui/utils": "^0.2.5" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.8.tgz", + "integrity": "sha512-kx62rP19VZ767Q653wsP1XZCGIirkE09E0QUGNYTM/ttbbQHqcGPdSfWFxUyyNLc/W6aoJRBajOSXhP6GXjC0Q==", "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.5" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", - "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", "dependencies": { - "@floating-ui/dom": "^1.5.1" + "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": ">=16.8.0", @@ -2201,9 +2201,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", - "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.5.tgz", + "integrity": "sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==" }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", @@ -3368,9 +3368,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz", - "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.1.tgz", + "integrity": "sha512-Qg4DMQsfPNAs88rb2xkdk03N3bjK4jgX5fR24eHCTR9q6PrhZQZ4UJBPzCHJkIpTRN1UKxx2DzjZmnC+7Lj0Ow==", "engines": { "node": ">=14.0.0" } @@ -11461,9 +11461,9 @@ } }, "node_modules/rc-util": { - "version": "5.38.1", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.38.1.tgz", - "integrity": "sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng==", + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", + "integrity": "sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==", "dependencies": { "@babel/runtime": "^7.18.3", "react-is": "^18.2.0" @@ -11474,9 +11474,9 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "dependencies": { "loose-envify": "^1.1.0" }, @@ -11508,15 +11508,15 @@ "dev": true }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.23.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^18.2.0" } }, "node_modules/react-fast-compare": { @@ -11524,17 +11524,6 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, - "node_modules/react-ga-onetrust-consent": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/tl-its-umich-edu/react-ga-onetrust-consent.git#9f34eefa515d1c3d33ee071c6a935f23c85a4de4", - "license": "Apache-2.0", - "dependencies": { - "js-cookie": "^3.0.5", - "react": "^18.3.1", - "react-ga4": "^2.1.0", - "react-router-dom": "^6.25.1" - } - }, "node_modules/react-ga4": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-2.1.0.tgz", @@ -11560,11 +11549,11 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/react-router": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz", - "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==", + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.1.tgz", + "integrity": "sha512-W0l13YlMTm1YrpVIOpjCADJqEUpz1vm+CMo47RuFX4Ftegwm6KOYsL5G3eiE52jnJpKvzm6uB/vTKTPKM8dmkA==", "dependencies": { - "@remix-run/router": "1.18.0" + "@remix-run/router": "1.14.1" }, "engines": { "node": ">=14.0.0" @@ -11574,12 +11563,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.25.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz", - "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==", + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.1.tgz", + "integrity": "sha512-QCNrtjtDPwHDO+AO21MJd7yIcr41UetYt5jzaB9Y1UYaPTCnVuJq6S748g1dE11OQlCFIQg+RtAA1SEZIyiBeA==", "dependencies": { - "@remix-run/router": "1.18.0", - "react-router": "6.25.1" + "@remix-run/router": "1.14.1", + "react-router": "6.21.1" }, "engines": { "node": ">=14.0.0" diff --git a/package.json b/package.json index f192feb8..d7c95b38 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,11 @@ "lodash.debounce": "4.0.8", "lodash.isequal": "4.5.0", "rc-slider": "10.5.0", - "react": "18.3.1", - "react-dom": "18.3.1", - "react-ga-onetrust-consent": "github:tl-its-umich-edu/react-ga-onetrust-consent", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-ga4": "2.1.0", "react-helmet": "6.1.0", - "react-router-dom": "6.25.1" + "react-router-dom": "6.21.1" }, "babel": { "presets": [