Skip to content
Permalink
Browse files

analytics revisions

  • Loading branch information...
crookm committed Feb 22, 2019
1 parent dd27d99 commit b9af928cfea0e107f19098dc67c8b4161477f13a
Showing with 83 additions and 100 deletions.
  1. +0 −9 public/index.html
  2. +63 −69 src/App.js
  3. +7 −13 src/_components/Checklist.js
  4. +5 −4 src/_components/SyncPanel.js
  5. +3 −3 src/_pages/About.js
  6. +5 −2 src/_pages/Game.js
@@ -11,15 +11,6 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.3.1/dist/css/foundation-flex.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<title>Mass Effect Checklist</title>
<script type="text/javascript">
var appInsights = window.appInsights || function (a) {
function b(a) { c[a] = function () { var b = arguments; c.queue.push(function () { c[a].apply(c, b) }) } } var c = { config: a }, d = document, e = window; setTimeout(function () { var b = d.createElement("script"); b.src = a.url || "https://az416426.vo.msecnd.net/scripts/a/ai.0.js", d.getElementsByTagName("script")[0].parentNode.appendChild(b) }); try { c.cookie = d.cookie } catch (a) { } c.queue = []; for (var f = ["Event", "Exception", "Metric", "PageView", "Trace", "Dependency"]; f.length;)b("track" + f.pop()); if (b("setAuthenticatedUserContext"), b("clearAuthenticatedUserContext"), b("startTrackEvent"), b("stopTrackEvent"), b("startTrackPage"), b("stopTrackPage"), b("flush"), !a.disableExceptionTracking) { f = "onerror", b("_" + f); var g = e[f]; e[f] = function (a, b, d, e, h) { var i = g && g(a, b, d, e, h); return !0 !== i && c["_" + f](a, b, d, e, h), i } } return c
}({
instrumentationKey: "d4d3e329-6b62-43b2-9541-39c63aa1f896"
});
window.appInsights = appInsights, appInsights.queue && 0 === appInsights.queue.length && appInsights.trackPageView();
</script>
</head>

<body>
@@ -1,6 +1,8 @@
import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";

import ReactGA from "react-ga";

// error pages
import NotFound from "./_pages/_errors/NotFound";

@@ -23,9 +25,12 @@ class App extends Component {
)
);

ReactGA.initialize("UA-135056719-1");

this.pageViewTimerStart = new Date();

this.handleTrackOutboundLink = this.handleTrackOutboundLink.bind(this);
this.handleTrackRemoteSync = this.handleTrackRemoteSync.bind(this);
this.handleTrackPageView = this.handleTrackPageView.bind(this);
this.handleSetPageTitle = this.handleSetPageTitle.bind(this);
this.handleLoadUserData = this.handleLoadUserData.bind(this);
@@ -35,6 +40,7 @@ class App extends Component {

this.downstreamHandlers = {
handleTrackOutboundLink: this.handleTrackOutboundLink,
handleTrackRemoteSync: this.handleTrackRemoteSync,
handleTrackPageView: this.handleTrackPageView,
handleSetPageTitle: this.handleSetPageTitle,
handleLoadUserData: this.handleLoadUserData,
@@ -55,28 +61,27 @@ class App extends Component {
}

// functions for downstream pages
handleTrackOutboundLink(e, aiProperties, aiMetrics) {
window.appInsights.trackEvent(
"linkedOutbound",
{
dev: this.isLocal,
href: e.target.href,
target: e.target.target,
...aiProperties
},
{
secsToClickFromPageReady:
new Date(new Date() - this.pageViewTimerStart).getTime() / 1000,
...aiMetrics
}
);
handleTrackOutboundLink(e, category, action, label) {
ReactGA.event({
category: category,
action: action,
label: label
});
}

handleTrackRemoteSync(game, count, interacted) {
ReactGA.event({
category: "Checklist",
action: "Synced to cloud",
label: `G${game}`,
value: count,
nonInteraction: !interacted
});
}

handleTrackPageView() {
this.pageViewTimerStart = new Date();
window.appInsights.trackPageView(undefined, undefined, {
dev: this.props.isLocal
});
ReactGA.pageview(window.location.pathname + window.location.search)
}

handleSetPageTitle(name) {
@@ -88,11 +93,7 @@ class App extends Component {
if (typeof window.localStorage[game] === "string") {
let data = JSON.parse(window.localStorage[game]);

let analyticsData = {
completedMissionsAtLoad: 0,
firstCompletedMissionAtLoad: null,
lastCompletedMissionAtLoad: null
};
let completed = 0;

let hydrated = Object.keys(def).reduce((out, current) => {
out[current] = def[current];
@@ -102,44 +103,17 @@ class App extends Component {
datetime: data[current] ? new Date(data[current].datetime) : null
};

if (out[current].completion.done) {
analyticsData.completedMissionsAtLoad++;

if (
out[current].completion.datetime <
analyticsData.firstCompletedMissionAtLoad ||
!analyticsData.firstCompletedMissionAtLoad
)
// this item is earlier than the earliest item, or the earliest item hasn't been set yet
analyticsData.firstCompletedMissionAtLoad =
out[current].completion.datetime;
if (
out[current].completion.datetime >
analyticsData.lastCompletedMissionAtLoad ||
!analyticsData.lastCompletedMissionAtLoad
)
// this item is later than the latest item, or the latest item hasn't been set yet
analyticsData.lastCompletedMissionAtLoad =
out[current].completion.datetime;
}

if (out[current].completion.done) completed++;
return out;
}, {});

window.appInsights.trackEvent(
"loadUserData",
{
game: game,
firstCompletedMissionAtLoad:
analyticsData.firstCompletedMissionAtLoad,
lastCompletedMissionAtLoad:
analyticsData.lastCompletedMissionAtLoad,
dev: this.props.isLocal
},
{
completedMissionsAtLoad: analyticsData.completedMissionsAtLoad
}
);
ReactGA.event({
category: "Checklist",
action: "Loaded local completed missions data",
label: `G${game}`,
value: completed,
nonInteraction: true
});

set(hydrated);
}
@@ -163,12 +137,11 @@ class App extends Component {
);
}

window.appInsights.trackEvent("toggleCompleteMission", {
game: game,
itemKey: key,
itemTitle: items[key].title.replace(/<\/?[^>]+(>|$)/g, ""),
itemStatus: toggled.done,
dev: this.props.isLocal
ReactGA.event({
category: "Checklist",
action: "Toggle mission completion status",
label: `G${game}#${key}`,
value: toggled.done ? 1 : 0
});

set(items); // return the new items so caller can update state
@@ -195,11 +168,32 @@ class App extends Component {
ui_settings[key] = value;
window.localStorage["ui_settings"] = JSON.stringify(ui_settings);

window.appInsights.trackEvent("toggleUISetting", {
setting: key,
value: value,
dev: this.isLocal
});
let uiTrackIgnore = ["syncLink", "syncLast"];
if (!uiTrackIgnore.includes(key)) {
// ignore sensitive UI settings like the sync passphrase
ReactGA.event({
category: "UI",
action: "Toggled UI setting",
label: key,
value: value ? 1 : 0
});
}

if (key === "syncLink") {
if (value) {
// linked to account
ReactGA.event({
category: "UI",
action: "Connected cloud sync account"
});
} else {
// unlinked
ReactGA.event({
category: "UI",
action: "Disconnected cloud sync account"
});
}
}
}
}

@@ -211,7 +211,9 @@ class Checklist extends Component {
<div className="columns titlerow">
<div className="row">
<div className="columns title">
<p dangerouslySetInnerHTML={{ __html: entry.title }} />
<p
dangerouslySetInnerHTML={{ __html: entry.title }}
/>
</div>
{this.state.showWikiLinks && (
<div className="columns shrink">
@@ -231,15 +233,9 @@ class Checklist extends Component {
onClick={e => {
this.props.downstreamHandlers.handleTrackOutboundLink(
e,
{
game: this.props.game,
linkSpecPurpose: "out to wikia",
linkVisualReferrer: `checklist item: ${entry.title.replace(
/<\/?[^>]+(>|$)/g,
""
)}`,
linkVisualOrder: key
}
"Checklist",
"Navigated to Wiki",
`G${this.props.game}#${key}`
);

e.stopPropagation();
@@ -276,9 +272,7 @@ class Checklist extends Component {
/>
</div>
<div className="columns title">
<p style={{ color: "#f0f0f0" }}>
{entry.title}
</p>
<p style={{ color: "#f0f0f0" }}>{entry.title}</p>
</div>
<div className="columns shrink">
<div className="carat down up" />
@@ -48,7 +48,7 @@ class SyncPanel extends Component {
}

this.timerBGSync = setInterval(() => {
if (this.state.syncAuto && this.state.syncLink) this.doSync();
if (this.state.syncAuto && this.state.syncLink) this.doSync(false, false);
}, 1000 * 60 * 1);

this.timerLastSync = setInterval(
@@ -115,14 +115,14 @@ class SyncPanel extends Component {
this.refs["sync-passphrase_input-error"].innerHTML =
"Passphrases must be > 10 characters. We recommend a short sentence of a few random words.";
} else {
this.setState({ syncLink: input }, () => this.doSync(true));
this.setState({ syncLink: input }, () => this.doSync(true, true));
this.props.downstreamHandlers.handleSetUI("syncLink", input);
this.refs["sync-passphrase_input-error"].innerHTML = "";
}
}
}

doSync(bypassDebounce) {
doSync(bypassDebounce, interacted) {
if (typeof Storage !== "undefined") {
this.setState({ syncActive: true });

@@ -138,7 +138,8 @@ class SyncPanel extends Component {
// success from http
this.props.downstreamHandlers.handleSyncResponse(
data,
this.props.items
this.props.items,
interacted
);

this.setState({ syncActive: false, syncLast: new Date() });
@@ -47,23 +47,23 @@ class About extends Component {
<a
href="https://github.com/crookm/me-checklist"
onClick={e =>
this.props.downstreamHandlers.handleTrackOutboundLink(e)
this.props.downstreamHandlers.handleTrackOutboundLink(e, "Navigation", "Link click on About page", "Repository")
}
>
repository
</a>. If you'd like to visit me on{" "}
<a
href="https://www.crookm.com/"
onClick={e =>
this.props.downstreamHandlers.handleTrackOutboundLink(e)
this.props.downstreamHandlers.handleTrackOutboundLink(e, "Navigation", "Link click on About page", "Blog")
}
>
my blog
</a>, or follow me on{" "}
<a
href="https://twitter.com/mattlc_3"
onClick={e =>
this.props.downstreamHandlers.handleTrackOutboundLink(e)
this.props.downstreamHandlers.handleTrackOutboundLink(e, "Navigation", "Link click on About page", "Twitter")
}
>
Twitter
@@ -122,7 +122,8 @@ class Game extends Component {
// success from http
this.props.downstreamHandlers.handleSyncResponse(
data,
this.state.items
this.state.items,
true
);

this.setState({ syncActive: false, syncLast: new Date() });
@@ -141,10 +142,12 @@ class Game extends Component {
);
}

handleSyncResponse(data, items) {
handleSyncResponse(data, items, interacted) {
let hydrated = items;
let stored = JSON.parse(window.localStorage[this.props.game]);
if (Object.keys(data).length > 0) {
this.props.downstreamHandlers.handleTrackRemoteSync(
this.props.game, Object.keys(data).lengt, interacted);
Object.entries(data).forEach(([key, entry]) => {
stored[key] = hydrated[key]["completion"] = entry;
});

0 comments on commit b9af928

Please sign in to comment.
You can’t perform that action at this time.