diff --git a/gatsby-browser.js b/gatsby-browser.js index 27905acc9..d36514e2b 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -6,4 +6,24 @@ import wrapPageElement from './gatsby/wrap-page-element'; -export { wrapPageElement }; +const onRouteUpdate = ({ location }) => { + if (process.env.NODE_ENV !== `production` || typeof ga !== `function`) { + return null; + } + + // wrap inside a timeout to make sure react-helmet is done with it's changes (https://github.com/gatsbyjs/gatsby/issues/9139) + // reactHelmet is using requestAnimationFrame: https://github.com/nfl/react-helmet/blob/5.2.0/src/HelmetUtils.js#L296-L299 + const sendPageView = () => { + const pagePath = location + ? location.pathname + location.search + location.hash + : undefined; + window.ga(`set`, `page`, pagePath); + window.ga(`send`, `pageview`); + }; + + // Minimum delay for reactHelmet's requestAnimationFrame + setTimeout(sendPageView, 32); + + return null; +}; +export { onRouteUpdate, wrapPageElement }; diff --git a/gatsby-config.js b/gatsby-config.js index 44432a41a..e02dbe7d4 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -7,13 +7,6 @@ module.exports = { siteUrl: 'https://developer.newrelic.com', }, plugins: [ - { - resolve: `gatsby-plugin-google-analytics`, - options: { - trackingId: 'UA-3047412-33', - head: true, - }, - }, 'gatsby-plugin-react-helmet', { resolve: 'gatsby-source-filesystem', diff --git a/gatsby-ssr.js b/gatsby-ssr.js index 4a759a0f7..d62a28bb8 100644 --- a/gatsby-ssr.js +++ b/gatsby-ssr.js @@ -50,4 +50,23 @@ const onPreRenderHTML = ({ ]); }; -export { onPreRenderHTML, wrapPageElement }; +const onRenderBody = ({ setHeadComponents }) => { + if (process.env.NODE_ENV !== `production`) { + return null; + } + // Pre-connect to google analytics + return setHeadComponents([ + , + , + ]); +}; + +export { onPreRenderHTML, onRenderBody, wrapPageElement }; diff --git a/package-lock.json b/package-lock.json index f7356a5ec..b48ec7ac8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12897,43 +12897,6 @@ } } }, - "gatsby-plugin-google-analytics": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/gatsby-plugin-google-analytics/-/gatsby-plugin-google-analytics-2.3.10.tgz", - "integrity": "sha512-PnGIluGbz2xLEe9+dz5ozMiw9HPBNwCR8VeJMoznRNcl+/JW2dZ5NEhtbrGIDx3JOuGjwOXbZZqbLL4UKZXDYQ==", - "requires": { - "@babel/runtime": "^7.10.3", - "minimatch": "3.0.4" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz", - "integrity": "sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - } - } - }, - "gatsby-plugin-google-tagmanager": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/gatsby-plugin-google-tagmanager/-/gatsby-plugin-google-tagmanager-2.3.5.tgz", - "integrity": "sha512-HuJLf+y/dV8diSQdUpQgsr5pfMGUYj/NTMo5EnUa4s66L6Ypj3rbuAkedin0m0wXy7hZVvag2wEKnykGdSwuWA==", - "requires": { - "@babel/runtime": "^7.10.2" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz", - "integrity": "sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - } - } - }, "gatsby-plugin-manifest": { "version": "2.4.12", "resolved": "https://registry.npmjs.org/gatsby-plugin-manifest/-/gatsby-plugin-manifest-2.4.12.tgz", diff --git a/package.json b/package.json index 792babe2b..b2d17951d 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,6 @@ "gatsby": "^2.24.2", "gatsby-image": "^2.4.9", "gatsby-plugin-emotion": "^4.3.9", - "gatsby-plugin-google-analytics": "^2.3.10", - "gatsby-plugin-google-tagmanager": "^2.3.5", "gatsby-plugin-manifest": "^2.4.12", "gatsby-plugin-mdx": "^1.2.14", "gatsby-plugin-meta-redirect": "^1.1.1", @@ -30,6 +28,7 @@ "gatsby-source-filesystem": "^2.3.12", "gatsby-transformer-remark": "^2.8.17", "gatsby-transformer-sharp": "^2.5.7", + "js-cookie": "^2.2.1", "node-sass": "^4.14.1", "normalize.css": "^8.0.1", "prism-react-renderer": "^1.1.1", diff --git a/src/components/CookieApprovalDialog.js b/src/components/CookieApprovalDialog.js new file mode 100644 index 000000000..d9bbf0922 --- /dev/null +++ b/src/components/CookieApprovalDialog.js @@ -0,0 +1,81 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import Cookies from 'js-cookie'; +import Button from './Button'; +import cx from 'classnames'; +import styles from './CookieApprovalDialog.module.scss'; +import ExternalLink from './ExternalLink'; + +const gdprConsentCookieName = 'newrelic-gdpr-consent'; + +const CookieApprovalDialog = ({ className, setCookieConsent }) => { + const [isCookieSet, setIsCookieSet] = useState(true); + + useEffect(() => { + setIsCookieSet(Cookies.get(gdprConsentCookieName) !== undefined); + }, []); + + function writeCookie(answer) { + const currentEnvironment = + process.env.ENV || process.env.NODE_ENV || 'development'; + const options = { expires: 365 /* days */ }; + if (currentEnvironment !== 'development') { + options.domain = 'newrelic.com'; + } + + Cookies.set(gdprConsentCookieName, String(!!answer), options); + setIsCookieSet(true); + answer && setCookieConsent(true); + } + + if (isCookieSet) { + return null; + } + return ( +
+
+
+

+ This site uses cookies{' '} + + 🍪 + +

+

+ We use cookies and other similar technologies ("Cookies") on our + websites and services to enhance your experience and to provide you + with relevant content. By using our websites and services you are + agreeing to the use of cookies. You can read more{' '} + + here + + . If you consent to our cookies, please click Yes. +

+
+
+ + +
+
+
+ ); +}; + +CookieApprovalDialog.propTypes = { + className: PropTypes.string, + setCookieConsent: PropTypes.func, +}; + +export default CookieApprovalDialog; diff --git a/src/components/CookieApprovalDialog.module.scss b/src/components/CookieApprovalDialog.module.scss new file mode 100644 index 000000000..38243b8ff --- /dev/null +++ b/src/components/CookieApprovalDialog.module.scss @@ -0,0 +1,105 @@ +.container { + width: 100%; + position: fixed; + bottom: 0; + z-index: 10000; + background-color: rgba(28, 42, 47, 0.92); + box-shadow: 0px -0.249053px 4.26158px rgba(12, 48, 57, 0.0421718), + 0px -0.598509px 10.2412px rgba(12, 48, 57, 0.0605839), + 0px -1.12694px 19.2832px rgba(12, 48, 57, 0.075), + 0px -2.01027px 34.3979px rgba(12, 48, 57, 0.0894161), + 0px -3.75998px 64.3375px rgba(12, 48, 57, 0.107828), + 0px -9px 154px rgba(12, 48, 57, 0.15); + backdrop-filter: blur(5px); +} + +.content { + display: flex; + justify-content: space-between; + align-items: center; + width: 1180px; + margin: 0 auto; + box-sizing: border-box; + padding: 1.125rem 0; +} + +.heading { + color: #fff; + margin-top: 0; + margin-bottom: 2px; + line-height: 21px; +} + +.description { + margin: 0 0 0px; + font-size: 13px; + line-height: 21px; + color: var(--accent-text-color); +} + +.buttonsContainer { + margin-left: 1rem; + flex-shrink: 0; +} + +.approveButton { + margin-right: 10px; + padding: 0.625rem 1.75rem; +} + +.rejectButton { + padding: 0.625rem 1rem; +} + +// ============================================================== +// Responsive styles +// ============================================================== +@media screen and (max-width: 1200px) { + .content { + width: 100%; + padding: 1.125rem 1.75rem; + } + + .heading { + margin-bottom: 0.375rem; + } + + .description { + line-height: 19px; + } +} + +@media screen and (max-width: 480px) { + .content { + flex-direction: column; + align-items: flex-start; + } + + .description { + margin-bottom: 1rem; + } + + .cta-container { + margin: 0; + } + + .approveButton { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + } + + .rejectButton { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + } +} + +// ============================================================== +// Dark mode +// ============================================================== +:global(.dark-mode) { + .container { + background-color: rgba(15, 25, 28, 0.92); + box-shadow: 0 -1px 0 rgba(55, 72, 78, 0.4); + } +} diff --git a/src/components/Layout.js b/src/components/Layout.js index af75b4793..959314f7d 100644 --- a/src/components/Layout.js +++ b/src/components/Layout.js @@ -1,21 +1,47 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import { Helmet } from 'react-helmet'; +import Cookies from 'js-cookie'; import Footer from './Footer'; import GlobalHeader from './GlobalHeader'; import MobileHeader from './MobileHeader'; import Sidebar from './Sidebar'; +import CookieApprovalDialog from './CookieApprovalDialog'; import styles from './Layout.module.scss'; import 'normalize.css'; import './styles.scss'; import '../theme.scss'; +const gaTrackingId = 'UA-3047412-33'; +const gdprConsentCookieName = 'newrelic-gdpr-consent'; + const Layout = ({ children }) => { + const [cookieConsent, setCookieConsent] = useState(false); const [isMobileNavOpen, setIsMobileNavOpen] = useState(false); + useEffect(() => { + const consentValue = Cookies.get(gdprConsentCookieName); + consentValue && setCookieConsent(true); + }, []); + return (
+ + {cookieConsent ? ( + + ) : null} + {
+ ); };