diff --git a/package.json b/package.json index 1f977d84f..a62b70f93 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "react": "^16.0.0", "react-dom": "^16.0.0", "react-helmet": "^5.2.0", - "react-piwik": "^1.0.7", "react-redux": "^5.0.6", "react-router": "^4.2.0", "react-router-dom": "^4.2.2", diff --git a/source/components/Satisfaction.js b/source/components/Satisfaction.js index 4334c0071..cc2e64525 100644 --- a/source/components/Satisfaction.js +++ b/source/components/Satisfaction.js @@ -5,7 +5,7 @@ import {connect} from 'react-redux' import './Satisfaction.css' import classNames from 'classnames' -import ReactPiwik from 'react-piwik'; +import ReactPiwik from './Tracker'; @connect( state => ({ diff --git a/source/components/Simulateur.js b/source/components/Simulateur.js index 2f44462fd..325ce3af6 100644 --- a/source/components/Simulateur.js +++ b/source/components/Simulateur.js @@ -14,7 +14,7 @@ import './Simulateur.css' import {capitalise0} from '../utils' import Conversation from './conversation/Conversation' -import ReactPiwik from 'react-piwik'; +import ReactPiwik from './Tracker'; let situationSelector = formValueSelector('conversation') diff --git a/source/components/Tracker.js b/source/components/Tracker.js new file mode 100644 index 000000000..0e6924163 --- /dev/null +++ b/source/components/Tracker.js @@ -0,0 +1,92 @@ +export default class Piwik { + constructor(opts) { + const options = opts; + + options.enableLinkTracking = (options.enableLinkTracking !== undefined) ? + options.enableLinkTracking : true; + options.trackDocumentTitle = (options.trackDocumentTitle !== undefined) ? + options.trackDocumentTitle : true; + + this.options = options; + + if (this.options.url === undefined || this.options.siteId === undefined) { + throw new Error('PiwikTracker cannot be initialized! SiteId and url are mandatory.'); + } + + this.initPiwik(); + } + + initPiwik() { + let url = this.options.url; + + if (url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1) { + url = `${url}/`; + } else { + url = ((document.location.protocol === 'https:') ? `https://${url}/` : `http://${url}/`); + } + + window._paq = window._paq || []; // eslint-disable-line no-underscore-dangle + + Piwik.push(['setSiteId', this.options.siteId]); + Piwik.push(['setTrackerUrl', `${url}piwik.php`]); + + if (this.options.enableLinkTracking) { + Piwik.push(['enableLinkTracking']); + } + + const scriptElement = document.createElement('script'); + const refElement = document.getElementsByTagName('script')[0]; + + scriptElement.type = 'text/javascript'; + scriptElement.defer = true; + scriptElement.async = true; + scriptElement.src = `${url}piwik.js`; + refElement.parentNode.insertBefore(scriptElement, refElement); + + return { + push: this.push, + track: this.track, + connectToHistory: this.connectToHistory, + disconnectFromHistory: this.disconnectFromHistory, + }; + } + + static push(args) { + window._paq.push(args); // eslint-disable-line no-underscore-dangle + } + + connectToHistory(history) { + this.unlistenFromHistory = history.listen((loc) => { + this.track(loc); + }); + + return history; + } + + disconnectFromHistory() { + if (this.unlistenFromHistory) { + this.unlistenFromHistory(); + + return true; + } + + return false; + } + + track(loc) { + const currentPath = loc.path || (loc.pathname + loc.search)/*.replace(/^\//, '')*/; + + if (this.previousPath === currentPath) { + return; + } + + if (this.options.trackDocumentTitle) { + Piwik.push(['setDocumentTitle', document.title]); + } + + Piwik.push(['setCustomUrl', currentPath]); + Piwik.push(['trackPageView']); + + this.previousPath = currentPath; + } +} diff --git a/source/components/conversation/Explicable.js b/source/components/conversation/Explicable.js index 06ae59005..1ee7deb59 100644 --- a/source/components/conversation/Explicable.js +++ b/source/components/conversation/Explicable.js @@ -6,7 +6,7 @@ import {connect} from 'react-redux' import {EXPLAIN_VARIABLE} from '../../actions' import {rules, findRuleByDottedName} from 'Engine/rules' -import ReactPiwik from 'react-piwik'; +import ReactPiwik from '../Tracker'; @connect(state => ({explained: state.explainedVariable}), dispatch => ({ explain: variableName => dispatch({type: EXPLAIN_VARIABLE, variableName}) diff --git a/source/containers/Layout.js b/source/containers/Layout.js index c41711aa5..c09eeddf8 100644 --- a/source/containers/Layout.js +++ b/source/containers/Layout.js @@ -4,8 +4,6 @@ import './reset.css' import './ribbon.css' import {Link, Route, Router, Switch} from 'react-router-dom' -import ReactPiwik from 'react-piwik' -import createHistory from 'history/createBrowserHistory' import HomeEmbauche from 'Components/HomeEmbauche' import HomeSyso from 'Components/HomeSyso' @@ -16,6 +14,9 @@ import Simulateur from 'Components/Simulateur' import Results from 'Components/Results' import RulesList from "Components/RulesList" +import ReactPiwik from 'Components/Tracker'; +import createHistory from 'history/createBrowserHistory' + const piwik = new ReactPiwik({ url: 'stats.data.gouv.fr', siteId: 39, diff --git a/source/reducers.js b/source/reducers.js index ffdaa8e02..abb6fd44f 100644 --- a/source/reducers.js +++ b/source/reducers.js @@ -11,7 +11,7 @@ import { STEP_ACTION, START_CONVERSATION, EXPLAIN_VARIABLE, CHANGE_THEME_COLOUR} import {analyseTopDown} from 'Engine/traverse' -import ReactPiwik from 'react-piwik'; +import ReactPiwik from 'Components/Tracker'; // Our situationGate retrieves data from the "conversation" form let fromConversation = state => name => formValueSelector('conversation')(state, name)