From 1d1ce874b20c97b15ee6f4187a03cfae26c61f94 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 29 Nov 2020 18:07:05 +1100 Subject: [PATCH] issue-124 add google analytics using react-ga which only passively maintained atm, and doesn't support GA-4, so might have to revisit this at some point. --- web/package.json | 1 + .../LandingSection/LandingSection.js | 20 ++++++--- web/src/components/OutBound/OutBound.js | 21 ++++++++++ .../components/OutBound/OutBound.stories.js | 7 ++++ web/src/components/OutBound/OutBound.test.js | 11 +++++ web/src/index.js | 3 ++ web/src/layouts/MainLayout/MainLayout.js | 41 ++++++++++++++++++- yarn.lock | 5 +++ 8 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 web/src/components/OutBound/OutBound.js create mode 100644 web/src/components/OutBound/OutBound.stories.js create mode 100644 web/src/components/OutBound/OutBound.test.js diff --git a/web/package.json b/web/package.json index ea43467..b047ab0 100644 --- a/web/package.json +++ b/web/package.json @@ -31,6 +31,7 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-dropzone": "^11.2.1", + "react-ga": "^3.3.0", "react-helmet": "^6.1.0", "react-image-crop": "^8.6.6", "rich-markdown-editor": "^11.0.2", diff --git a/web/src/components/LandingSection/LandingSection.js b/web/src/components/LandingSection/LandingSection.js index 66621d7..0d488cd 100644 --- a/web/src/components/LandingSection/LandingSection.js +++ b/web/src/components/LandingSection/LandingSection.js @@ -6,11 +6,19 @@ import { involuteDonut, } from './mockEditorParts' import Svg from 'src/components/Svg' -import { Link } from '@redwoodjs/router' +import OutBound from 'src/components/OutBound' import { useAuth } from '@redwoodjs/auth' +import ReactGA from 'react-ga' const LandingSection = () => { const { logIn } = useAuth() + const recordedLogin = () => { + ReactGA.event({ + category: 'login', + action: 'landing section CTA', + }) + logIn() + } return (
@@ -146,17 +154,17 @@ const LandingSection = () => {

Projects use the excellent{' '} - CascadeStudio - {' '} + {' '} with more integrations coming soon.

@@ -193,8 +201,8 @@ function MarketingPoint({ leadingPoint, title, children }) { function QuickLink({ to, children }) { return ( - + {children} - + ) } diff --git a/web/src/components/OutBound/OutBound.js b/web/src/components/OutBound/OutBound.js new file mode 100644 index 0000000..398ae57 --- /dev/null +++ b/web/src/components/OutBound/OutBound.js @@ -0,0 +1,21 @@ +import ReactGA from 'react-ga' + +const OutBound = ({ className, children, to }) => { + return ( + { + ReactGA.event({ + category: 'outbound', + action: to, + }) + return true + }} + > + {children} + + ) +} + +export default OutBound diff --git a/web/src/components/OutBound/OutBound.stories.js b/web/src/components/OutBound/OutBound.stories.js new file mode 100644 index 0000000..62885ec --- /dev/null +++ b/web/src/components/OutBound/OutBound.stories.js @@ -0,0 +1,7 @@ +import OutBound from './OutBound' + +export const generated = () => { + return +} + +export default { title: 'Components/OutBound' } diff --git a/web/src/components/OutBound/OutBound.test.js b/web/src/components/OutBound/OutBound.test.js new file mode 100644 index 0000000..ae1a365 --- /dev/null +++ b/web/src/components/OutBound/OutBound.test.js @@ -0,0 +1,11 @@ +import { render } from '@redwoodjs/testing' + +import OutBound from './OutBound' + +describe('OutBound', () => { + it('renders successfully', () => { + expect(() => { + render() + }).not.toThrow() + }) +}) diff --git a/web/src/index.js b/web/src/index.js index 652024f..20431b5 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -3,6 +3,9 @@ import netlifyIdentity from 'netlify-identity-widget' import ReactDOM from 'react-dom' import { RedwoodProvider, FatalErrorBoundary } from '@redwoodjs/web' import FatalErrorPage from 'src/pages/FatalErrorPage' +import ReactGA from 'react-ga' + +ReactGA.initialize(process.env.GOOGLE_ANALYTICS_ID) import Routes from 'src/Routes' diff --git a/web/src/layouts/MainLayout/MainLayout.js b/web/src/layouts/MainLayout/MainLayout.js index 7bdb0dd..b3da63c 100644 --- a/web/src/layouts/MainLayout/MainLayout.js +++ b/web/src/layouts/MainLayout/MainLayout.js @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useState, useEffect } from 'react' import { Link, routes } from '@redwoodjs/router' import { useAuth } from '@redwoodjs/auth' import { Flash } from '@redwoodjs/web' @@ -6,6 +6,8 @@ import Tooltip from '@material-ui/core/Tooltip' import { useQuery } from '@redwoodjs/web' import Popover from '@material-ui/core/Popover' import { getActiveClasses } from 'get-active-classes' +import { useLocation } from '@redwoodjs/router' +import ReactGA from 'react-ga' export const QUERY = gql` query FIND_USER_BY_ID($id: String!) { @@ -20,6 +22,9 @@ export const QUERY = gql` import Svg from 'src/components/Svg' import ImageUploader from 'src/components/ImageUploader' +let previousSubmission = '' +let previousUserID = '' + const MainLayout = ({ children }) => { const { logIn, logOut, isAuthenticated, currentUser } = useAuth() const { data, loading } = useQuery(QUERY, { @@ -48,6 +53,38 @@ const MainLayout = ({ children }) => { openPopover(currentTarget) } + + const recordedLogin = () => { + ReactGA.event({ + category: 'login', + action: 'navbar login', + }) + logIn() + } + + const { pathname, params } = useLocation() + + useEffect(() => { + const newSubmission = `${pathname || ''}${params || ''}` + // not the "React" way of doing think, but otherwise it will submit twice + // it's because the old page submits it and when the new page loads it happens again + if (previousSubmission !== newSubmission) { + ReactGA.pageview(newSubmission) + previousSubmission = newSubmission + } + }, [pathname, params]) + useEffect(() => { + // not the "React" way of doing think, but otherwise it will submit twice + // it's because the old page submits it and when the new page loads it happens again + if ( + isAuthenticated && + previousUserID !== currentUser && + data?.user?.userName + ) { + ReactGA.set({ userName: data.user.userName, userId: currentUser }) + previousUserID = currentUser + } + }, [data, currentUser, isAuthenticated]) return ( <>
@@ -120,7 +157,7 @@ const MainLayout = ({ children }) => { Sign in/up diff --git a/yarn.lock b/yarn.lock index 6336f44..36dde25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13356,6 +13356,11 @@ react-focus-lock@^2.1.0: use-callback-ref "^1.2.1" use-sidecar "^1.0.1" +react-ga@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.0.tgz#c91f407198adcb3b49e2bc5c12b3fe460039b3ca" + integrity sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ== + react-helmet-async@^1.0.2: version "1.0.6" resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.0.6.tgz#11c15c74e79b3f66670c73779bef3e0e352b1d4e"