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"