From 0ef33e09886870f436720be5bd357e4de5ebaba2 Mon Sep 17 00:00:00 2001 From: Koen van Gilst Date: Mon, 11 Mar 2019 11:24:44 +0100 Subject: [PATCH] fix(analytics) - no tracking when on development --- public/index.html | 21 ------- src/index.tsx | 18 +++--- src/shared/utils/analytics.js | 110 ++++++++++++++++++++++++++++++++++ src/shared/utils/bugsnag.ts | 7 +++ 4 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 src/shared/utils/analytics.js create mode 100644 src/shared/utils/bugsnag.ts diff --git a/public/index.html b/public/index.html index ac9e5a6..5dce507 100644 --- a/public/index.html +++ b/public/index.html @@ -159,25 +159,4 @@ To create a production bundle, use `npm run build` or `yarn build`. --> - - diff --git a/src/index.tsx b/src/index.tsx index 4004f08..3d13f16 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,12 +1,9 @@ -import bugsnag from '@bugsnag/js' -import bugsnagReact from '@bugsnag/plugin-react' import { Router } from '@reach/router' import preventDoubleTapZoom from 'prevent-double-tap-zoom' import * as React from 'react' import * as ReactDOM from 'react-dom' import { Provider } from 'react-redux' import { applyMiddleware, compose, createStore } from 'redux' - import FindingColors from 'src/finding-colors' import FindingWords from 'src/finding-words' import { audioMiddleware } from 'src/finding-words/redux/audio-middleware' @@ -14,8 +11,8 @@ import { IStoreState } from 'src/finding-words/types' import rootReducer from 'src/shared/redux/root-reducer' import './index.css' import registerServiceWorker from './registerServiceWorker' - -preventDoubleTapZoom({ delay: 500 }) +import { initializeAnalytics } from './shared/utils/analytics' +import { BugsnagErrorBoundary } from './shared/utils/bugsnag' const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose @@ -25,19 +22,18 @@ const store = createStore( composeEnhancers(applyMiddleware(audioMiddleware)) ) -const bugsnagClient = bugsnag('eb9c66e47f7f95c5801a21ffe1308619') -bugsnagClient.use(bugsnagReact, React) -const ErrorBoundary = bugsnagClient.getPlugin('react') - ReactDOM.render( - + - , + , document.getElementById('root') as HTMLElement ) + +preventDoubleTapZoom({ delay: 500 }) registerServiceWorker() +initializeAnalytics() diff --git a/src/shared/utils/analytics.js b/src/shared/utils/analytics.js new file mode 100644 index 0000000..a069588 --- /dev/null +++ b/src/shared/utils/analytics.js @@ -0,0 +1,110 @@ +function initialize(context, trackingId, options) { + const history = context.history + const doc = document + const nav = navigator || {} + const storage = localStorage + const encode = encodeURIComponent + const pushState = history.pushState + const typeException = 'exception' + const generateId = () => Math.random().toString(36) + const getId = () => { + if (!storage.cid) { + storage.cid = generateId() + } + return storage.cid + } + const serialize = obj => { + var str = [] + for (var p in obj) { + if (obj.hasOwnProperty(p)) { + if (obj[p] !== undefined) { + str.push(encode(p) + '=' + encode(obj[p])) + } + } + } + return str.join('&') + } + const track = ( + type, + eventCategory, + eventAction, + eventLabel, + eventValue, + exceptionDescription, + exceptionFatal + ) => { + const url = 'https://www.google-analytics.com/collect' + const data = serialize({ + v: '1', + ds: 'web', + aip: options.anonymizeIp ? 1 : undefined, + tid: trackingId, + cid: getId(), + t: type || 'pageview', + sd: + options.colorDepth && context.screen.colorDepth + ? `${context.screen.colorDepth}-bits` + : undefined, + dr: doc.referrer || undefined, + dt: doc.title, + dl: doc.location.origin + doc.location.pathname + doc.location.search, + ul: options.language ? (nav.language || '').toLowerCase() : undefined, + de: options.characterSet ? doc.characterSet : undefined, + sr: options.screenSize + ? `${(context.screen || {}).width}x${(context.screen || {}).height}` + : undefined, + vp: + options.screenSize && context.visualViewport + ? `${(context.visualViewport || {}).width}x${ + (context.visualViewport || {}).height + }` + : undefined, + ec: eventCategory || undefined, + ea: eventAction || undefined, + el: eventLabel || undefined, + ev: eventValue || undefined, + exd: exceptionDescription || undefined, + exf: + typeof exceptionFatal !== 'undefined' && !!exceptionFatal === false + ? 0 + : undefined + }) + + if (nav.sendBeacon) { + nav.sendBeacon(url, data) + } else { + var xhr = new XMLHttpRequest() + xhr.open('POST', url, true) + xhr.send(data) + } + } + const trackEvent = (category, action, label, value) => + track('event', category, action, label, value) + const trackException = (description, fatal) => + track(typeException, null, null, null, null, description, fatal) + history.pushState = function(state) { + if (typeof history.onpushstate == 'function') { + history.onpushstate({ state: state }) + } + setTimeout(track, options.delay || 10) + return pushState.apply(history, arguments) + } + track() + context.ma = { + trackEvent, + trackException + } +} + +export function initializeAnalytics() { + // only track on production + if (process.env.NODE_ENV !== 'production') return + + initialize(window, 'UA-135954444-1', { + anonymizeIp: true, + colorDepth: true, + characterSet: true, + screenSize: true, + language: true + }) +} diff --git a/src/shared/utils/bugsnag.ts b/src/shared/utils/bugsnag.ts new file mode 100644 index 0000000..6597c3d --- /dev/null +++ b/src/shared/utils/bugsnag.ts @@ -0,0 +1,7 @@ +import bugsnag from '@bugsnag/js' +import bugsnagReact from '@bugsnag/plugin-react' +import * as React from 'react' + +export const bugsnagClient = bugsnag('eb9c66e47f7f95c5801a21ffe1308619') +bugsnagClient.use(bugsnagReact, React) +export const BugsnagErrorBoundary = bugsnagClient.getPlugin('react')