From 571ec394f8b0a11eb8d93c9b6ae3dab6250bab6e Mon Sep 17 00:00:00 2001 From: jacob-moore-cb <144269024+jacob-moore-cb@users.noreply.github.com> Date: Tue, 3 Oct 2023 11:53:54 -0700 Subject: [PATCH] Add Client Analytics Pageview Tracking (#29) * Add Client Analytics pageview tracking to Base Docs app. * Add Client Analytics pageview tracking to Base Web app. * Add import plugin to fix dotenv linting in docusaurus.config.js * Switch to .ts files and disable type-checking and linting. * Update initCCA file extension in docs config. * Add execution environment check before using window variable. * Replace process.env with publicRuntimeConfig. * Remove Amplitude env vars. Remove device id from analytics init files. * Remove duplicate dotenv call. --- .eslintrc.js | 11 +++---- apps/base-docs/docusaurus.config.js | 25 +++++++++++---- apps/base-docs/package.json | 1 + apps/base-docs/src/utils/initCCA.ts | 48 +++++++++++++++++++++++++++++ apps/web/global.d.ts | 1 + apps/web/next.config.js | 5 +++ apps/web/pages/_app.tsx | 10 ++++++ apps/web/src/utils/initCCA.ts | 35 +++++++++++++++++++++ yarn.lock | 3 +- 9 files changed, 126 insertions(+), 13 deletions(-) create mode 100644 apps/base-docs/src/utils/initCCA.ts create mode 100644 apps/web/src/utils/initCCA.ts diff --git a/.eslintrc.js b/.eslintrc.js index d9cc0f86f0..55b991a02d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -16,10 +16,10 @@ module.exports = { }, ], parserOptions: { - parser: "@typescript-eslint/parser", - project: "./tsconfig.json", + parser: '@typescript-eslint/parser', + project: './tsconfig.json', }, - plugins: ['react-perf', 'relay', '@typescript-eslint'], + plugins: ['react-perf', 'relay', '@typescript-eslint', 'import'], extends: [ 'airbnb-typescript/base', 'airbnb/rules/react', @@ -136,6 +136,5 @@ module.exports = { // Hard to migrate // Errors for all try/catch blocks and any types from third-parties '@typescript-eslint/no-unsafe-member-access': 'off', - - } -} + }, +}; diff --git a/apps/base-docs/docusaurus.config.js b/apps/base-docs/docusaurus.config.js index 75539adc27..5654acdb88 100644 --- a/apps/base-docs/docusaurus.config.js +++ b/apps/base-docs/docusaurus.config.js @@ -1,3 +1,6 @@ +const dotenv = require('dotenv'); +dotenv.config(); + const baseConfig = { baseUrl: '/', favicon: 'img/favicon.ico', @@ -11,14 +14,14 @@ const baseConfig = { autoCollapseCategories: true, hideable: true, }, - } + }, }, -};; +}; const lightCodeTheme = require('prism-react-renderer/themes/github'); const darkCodeTheme = require('prism-react-renderer/themes/oceanicNext'); -const APP_TITLE = `Base`; +const APP_TITLE = 'Base'; const PRODUCT_NAME = 'Base'; const config = { @@ -26,6 +29,9 @@ const config = { title: APP_TITLE, tagline: '', url: 'https://docs.base.org', + customFields: { + nodeEnv: process.env.NODE_ENV, + }, presets: [ [ @@ -57,6 +63,13 @@ const config = { 'docusaurus-node-polyfills', './src/plugins/docusaurus-plugin-kbar/index.js', ], + scripts: [ + { + src: 'https://static-assets.coinbase.com/js/cca/v0.0.1.js', + async: true, + }, + ], + clientModules: [require.resolve('./src/utils/initCCA.ts')], themeConfig: { ...baseConfig.themeConfig, @@ -73,12 +86,12 @@ const config = { type: 'doc', docId: 'overview', position: 'left', - label: `Documentation`, + label: 'Documentation', }, { to: '/base-camp/docs/welcome', position: 'left', - label: `Base Camp`, + label: 'Base Camp', items: [ { label: 'Learn', @@ -94,7 +107,7 @@ const config = { type: 'doc', docId: 'security', position: 'left', - label: `Security`, + label: 'Security', }, { type: 'dropdown', diff --git a/apps/base-docs/package.json b/apps/base-docs/package.json index 59794bc22b..ac4dc17c55 100644 --- a/apps/base-docs/package.json +++ b/apps/base-docs/package.json @@ -21,6 +21,7 @@ "@mdx-js/react": "^1.6.22", "@rainbow-me/rainbowkit": "^1.0.4", "docusaurus-node-polyfills": "^1.0.0", + "dotenv": "^16.3.1", "express": "^4.18.2", "express-basic-auth": "^1.2.1", "kbar": "^0.1.0-beta.41", diff --git a/apps/base-docs/src/utils/initCCA.ts b/apps/base-docs/src/utils/initCCA.ts new file mode 100644 index 0000000000..f7ab649ca5 --- /dev/null +++ b/apps/base-docs/src/utils/initCCA.ts @@ -0,0 +1,48 @@ +// The CCA team said this lite version of the library is temporary and not officially supported. +// They recommended disabling linting and type-checking for now, since this version is not typed. +/* eslint-disable */ +// @ts-nocheck +const docusaurusConfig = require('@generated/docusaurus.config'); +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; + +const { customFields } = docusaurusConfig.default; +const isDevelopment = customFields.nodeEnv === 'development'; + +// Initialize Client Analytics +const initCCA = () => { + if (ExecutionEnvironment.canUseDOM && window.ClientAnalytics) { + const { init, identify, PlatformName } = window.ClientAnalytics; + + init({ + isProd: !isDevelopment, + amplitudeApiKey: isDevelopment + ? 'ca92bbcb548f7ec4b8ebe9194b8eda81' + : '2b38c7ac93c0dccc83ebf9acc5107413', + platform: PlatformName.web, + projectName: 'base_docs', + showDebugLogging: isDevelopment, + version: '1.0.0', + apiEndpoint: 'https://cca-lite.coinbase.com', + }); + + identify({ deviceId: 'base_docs_device_id' }); + } +}; + +export default initCCA(); + +// Track Pageviews +export function onRouteDidUpdate({ location, previousLocation }) { + if (location.pathname !== previousLocation?.pathname && window.ClientAnalytics) { + const { logEvent } = window.ClientAnalytics; + + const referrerURL = + previousLocation?.pathname === null && document.referrer ? document.referrer : null; + + logEvent('pageview', { + page_path: location.pathname, + prev_page_path: previousLocation?.pathname, + referrer_url: referrerURL, + }); + } +} diff --git a/apps/web/global.d.ts b/apps/web/global.d.ts index 0f68bb2177..3fb1d1a430 100644 --- a/apps/web/global.d.ts +++ b/apps/web/global.d.ts @@ -5,6 +5,7 @@ declare module 'next/config' { alchemyApiUrl: string; }; publicRuntimeConfig: { + nodeEnv: string; docsUrl: string; bridgeUrl: string; greenhouseApiUrl: string; diff --git a/apps/web/next.config.js b/apps/web/next.config.js index ba19e8217b..a62084e1fe 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -54,6 +54,8 @@ function extendBaseConfig(customConfig = {}, plugins = []) { const isLocalDevelopment = process.env.NODE_ENV === 'development'; const baseXYZDomains = 'https://base.mirror.xyz'; const greenhouseDomains = 'https://boards.greenhouse.io'; +const ccaDomain = 'https://static-assets.coinbase.com/js/cca/v0.0.1.js'; +const analyticsDomains = 'https://analytics-service-dev.cbhq.net'; const contentSecurityPolicy = { 'default-src': [ @@ -62,6 +64,8 @@ const contentSecurityPolicy = { isLocalDevelopment ? "'unsafe-eval'" : '', baseXYZDomains, greenhouseDomains, + ccaDomain, + analyticsDomains, ], 'frame-ancestors': ["'self'", baseXYZDomains], 'form-action': ["'self'", baseXYZDomains], @@ -108,6 +112,7 @@ const securityHeaders = [ module.exports = extendBaseConfig({ publicRuntimeConfig: { + nodeEnv: process.env.NODE_ENV, docsUrl: process.env.DOCS_URL ?? 'https://docs.base.org', bridgeUrl: process.env.BRIDGE_URL ?? 'https://bridge.base.org', greenhouseApiUrl: process.env.GREENHOUSE_HTTPS ?? 'https://boards-api.greenhouse.io/v1', diff --git a/apps/web/pages/_app.tsx b/apps/web/pages/_app.tsx index b7b44710e5..9e2b5012f3 100644 --- a/apps/web/pages/_app.tsx +++ b/apps/web/pages/_app.tsx @@ -1,5 +1,9 @@ import './global.css'; +import Script from 'next/script'; +import { useRouter } from 'next/router'; +import { useCallback } from 'react'; +import initCCA from '../src/utils/initCCA'; import { MotionConfig } from 'framer-motion'; import App, { AppContext, AppProps } from 'next/app'; @@ -13,8 +17,14 @@ export async function getInitialProps(context: AppContext) { } export default function StaticApp({ Component, pageProps }: AppProps) { + const router = useRouter(); + return ( +