Skip to content

Commit

Permalink
analytics revisions
Browse files Browse the repository at this point in the history
  • Loading branch information
crookm committed Feb 22, 2019
1 parent dd27d99 commit b9af928
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 100 deletions.
9 changes: 0 additions & 9 deletions public/index.html
Expand Up @@ -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 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"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<title>Mass Effect Checklist</title> <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> </head>


<body> <body>
Expand Down
132 changes: 63 additions & 69 deletions src/App.js
@@ -1,6 +1,8 @@
import React, { Component } from "react"; import React, { Component } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom"; import { BrowserRouter, Route, Switch } from "react-router-dom";


import ReactGA from "react-ga";

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


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


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

this.pageViewTimerStart = new Date(); this.pageViewTimerStart = new Date();


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


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


// functions for downstream pages // functions for downstream pages
handleTrackOutboundLink(e, aiProperties, aiMetrics) { handleTrackOutboundLink(e, category, action, label) {
window.appInsights.trackEvent( ReactGA.event({
"linkedOutbound", category: category,
{ action: action,
dev: this.isLocal, label: label
href: e.target.href, });
target: e.target.target, }
...aiProperties
}, handleTrackRemoteSync(game, count, interacted) {
{ ReactGA.event({
secsToClickFromPageReady: category: "Checklist",
new Date(new Date() - this.pageViewTimerStart).getTime() / 1000, action: "Synced to cloud",
...aiMetrics label: `G${game}`,
} value: count,
); nonInteraction: !interacted
});
} }


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


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


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


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


if (out[current].completion.done) { if (out[current].completion.done) completed++;
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;
}

return out; return out;
}, {}); }, {});


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


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


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


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


window.appInsights.trackEvent("toggleUISetting", { let uiTrackIgnore = ["syncLink", "syncLast"];
setting: key, if (!uiTrackIgnore.includes(key)) {
value: value, // ignore sensitive UI settings like the sync passphrase
dev: this.isLocal 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"
});
}
}
} }
} }


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


e.stopPropagation(); e.stopPropagation();
Expand Down Expand Up @@ -276,9 +272,7 @@ class Checklist extends Component {
/> />
</div> </div>
<div className="columns title"> <div className="columns title">
<p style={{ color: "#f0f0f0" }}> <p style={{ color: "#f0f0f0" }}>{entry.title}</p>
{entry.title}
</p>
</div> </div>
<div className="columns shrink"> <div className="columns shrink">
<div className="carat down up" /> <div className="carat down up" />
Expand Down
9 changes: 5 additions & 4 deletions src/_components/SyncPanel.js
Expand Up @@ -48,7 +48,7 @@ class SyncPanel extends Component {
} }


this.timerBGSync = setInterval(() => { 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); }, 1000 * 60 * 1);


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


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


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


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


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


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

0 comments on commit b9af928

Please sign in to comment.