diff --git a/config/default.js b/config/default.js index a09b6ed..4bc4cff 100644 --- a/config/default.js +++ b/config/default.js @@ -1,5 +1,5 @@ // default config -export default { +module.exports = { apiEntry: "http://localhost:4060", GitHubRepo: "https://github.com/UTD-CRSS/app.exploreapollo.org", TravisBaseURL: "https://travis-ci.org/UTD-CRSS/app.exploreapollo.org" diff --git a/config/development.js b/config/development.js index dfd3b80..8cd5107 100644 --- a/config/development.js +++ b/config/development.js @@ -1,2 +1,2 @@ // development config -export default {}; +module.exports = {}; diff --git a/config/index.js b/config/index.js index 9a9746f..8bf1ba2 100644 --- a/config/index.js +++ b/config/index.js @@ -1,9 +1,9 @@ -import defaultConfig from "./default"; +var defaultConfig = require("./default"); // TODO: more robust config management -const specificConfig = require(`./${process.env.APP_ENV}.js`).default; +const specificConfig = require(`./${process.env.APP_ENV || "development"}.js`); -export default Object.assign( +module.exports = Object.assign( {}, defaultConfig, specificConfig diff --git a/config/production.js b/config/production.js index 975ecc2..43ce426 100644 --- a/config/production.js +++ b/config/production.js @@ -1,4 +1,5 @@ // production config -export default { - apiEntry: "https://explore-apollo-api.herokuapp.com" +module.exports = { + apiEntry: "https://explore-apollo-api.herokuapp.com", + GoogleAnalyticsCode: "UA-83921870-1" }; diff --git a/config/staging.js b/config/staging.js index 4ac3e27..d60bd06 100644 --- a/config/staging.js +++ b/config/staging.js @@ -1,4 +1,5 @@ // staging config -export default { - apiEntry: "https://exploreapollo-api-staging.herokuapp.com" +module.exports = { + apiEntry: "https://exploreapollo-api-staging.herokuapp.com", + GoogleAnalyticsCode: "UA-83921870-1" }; diff --git a/src/index.html b/src/index.html index 70d7592..40423fb 100644 --- a/src/index.html +++ b/src/index.html @@ -4,6 +4,21 @@ <%= htmlWebpackPlugin.options.title %> + + <% if (htmlWebpackPlugin.options.GoogleAnalyticsCode) { %> + + <% } else { %> + + <% } %>
diff --git a/src/middleware.js b/src/middleware.js new file mode 100644 index 0000000..ab1f71e --- /dev/null +++ b/src/middleware.js @@ -0,0 +1,47 @@ +import { RECEIVE_AUDIO } from "./actions"; +import {throttle, isFunction} from "lodash"; +import ga from "ga"; + +// Tracks page-views and audio play times. +export function googleAnalytics(store) { + // This constant isn't exported from redux-router so I'm having to redefine it. + // It's a bit of a hack and makes the Google Analytics code dependent on redux-router's internal implementation. + // The better way to do this is to subscribe to the react router using browserHistory, + // but redux and redux-router make it difficult to access browswerHistory in a middleware function.. + const ROUTER_DID_CHANGE = "@@reduxReactRouter/routerDidChange"; + + const gaMomentEventCategory = "Moment"; + const gaPlayTimeEventAction = "playTime"; + const gaPlayTimeEventIntervalInMilliseconds = 5000; + + // Some helper functions. + const sendPlayTimeEvent = throttle(function(playTimeInMilliseconds) { + if (isFunction(ga)) { + ga("send", "event", gaMomentEventCategory, gaPlayTimeEventAction, store.getState().audio.momentId, playTimeInMilliseconds); + } + }, gaPlayTimeEventIntervalInMilliseconds); + + // Return a function handling actions. + return next => action => { + switch (action.type) { + case ROUTER_DID_CHANGE: + // Send a page-view. + if (isFunction(ga)) { + ga("set", "page", action.payload.location.pathname + action.payload.location.search); + ga("send", "pageview"); + } + + break; + case RECEIVE_AUDIO: + const isPlaying = !!store.getState().audio.playing || !!action.playing; + if (isPlaying && action.time) { + // Audio has started playing, so start sending play time events. + sendPlayTimeEvent(action.time); + } + + break; + } + + return next(action); + }; +} diff --git a/src/store/configureStore.js b/src/store/configureStore.js index 3cf19af..03ed16d 100644 --- a/src/store/configureStore.js +++ b/src/store/configureStore.js @@ -2,6 +2,7 @@ import { createStore, applyMiddleware, compose } from "redux"; import { reduxReactRouter } from "redux-router"; import routes from "../routes"; import thunk from "redux-thunk"; +import { googleAnalytics } from "../middleware"; import createLogger from "redux-logger"; import rootReducer from "../reducers"; import createHistory from "history/lib/createBrowserHistory"; @@ -12,6 +13,7 @@ const isProduction = process.env.NODE_ENV === "production"; const middleware = compact([ applyMiddleware(thunk), reduxReactRouter({ routes, createHistory }), + applyMiddleware(googleAnalytics), !isProduction && applyMiddleware(createLogger()) ]); diff --git a/webpack.config.js b/webpack.config.js index 3758718..85c762d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,6 +2,7 @@ var path = require("path"); var HtmlWebpackPlugin = require("html-webpack-plugin"); var webpack = require("webpack"); +var config = require("./config"); var isProduction = process.env.NODE_ENV === "production"; @@ -39,7 +40,8 @@ module.exports = { title: "Explore Apollo", template: "index.html", // Load a custom template inject: "body", //scripts are injected to here - favicon: "./favicon.ico" + favicon: "./favicon.ico", + GoogleAnalyticsCode: config.GoogleAnalyticsCode }), new webpack.ProvidePlugin({ fetch: "imports?this=>global!exports?global.fetch!whatwg-fetch" @@ -85,5 +87,9 @@ module.exports = { { test: /\.eot$/, loader: "file-loader" }, { test: /\.svg$/, loader: "file-loader" } ] + }, + + externals: { + "ga": "ga" } };