├── .gitignore ├── README.md ├── demo.png ├── demo └── src │ └── index.js ├── nwb.config.js ├── package-lock.json ├── package.json └── src └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | es 3 | lib 4 | demo/dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-analytics-widget 2 | 3 | [![npm package][npm-badge]][npm] 4 | 5 | Embed Google Analytics widgets in your React applications. 6 | 7 | - The `GoogleProvider` container ensure user is logged on analytics 8 | - The `GoogleDataChart` component display any [DataChart configuraton](https://developers.google.com/analytics/devguides/reporting/embed/v1/component-reference#datachart) 9 | 10 | ![](./demo.png) 11 | 12 | Demo : [https://revolunet.github.io/react-analytics-widget](https://revolunet.github.io/react-analytics-widget) 13 | 14 | ## Requirements 15 | 16 | You need to create a OAUTH client id in the [google developer console](https://console.developers.google.com/apis/credentials/oauthclient/960315238073-dv345fcj3tkikn506k9lrch73hk9259u.apps.googleusercontent.com?project=eastern-store-174123) and provide an [analytic view ID](https://ga-dev-tools.appspot.com/query-explorer/). 17 | Alternatively you can use server-side authentication tokens. You can find more info in this [example](https://ga-dev-tools.appspot.com/embed-api/server-side-authorization/). 18 | 19 | ### Note: 20 | If you provide values for both the `accessToken` and the `clientId` props, the latter will be ignored. 21 | 22 | Also, add the Google SDK at the top of your page 23 | 24 | ```js 25 | ;(function(w, d, s, g, js, fjs) { 26 | g = w.gapi || (w.gapi = {}) 27 | g.analytics = { 28 | q: [], 29 | ready: function(cb) { 30 | this.q.push(cb) 31 | } 32 | } 33 | js = d.createElement(s) 34 | fjs = d.getElementsByTagName(s)[0] 35 | js.src = "https://apis.google.com/js/platform.js" 36 | fjs.parentNode.insertBefore(js, fjs) 37 | js.onload = function() { 38 | g.load("analytics") 39 | } 40 | })(window, document, "script") 41 | ``` 42 | 43 | ## Usage 44 | ### OAUTH authentication 45 | 46 | ```js 47 | 48 | import { GoogleProvider, GoogleDataChart } from 'react-analytics-widget' 49 | 50 | const CLIENT_ID = 'x-x--x---x---x-xx--x-apps.googleusercontent.com'; 51 | 52 | // graph 1 config 53 | const last30days = { 54 | reportType: "ga", 55 | query: { 56 | dimensions: "ga:date", 57 | metrics: "ga:pageviews", 58 | "start-date": "30daysAgo", 59 | "end-date": "yesterday" 60 | }, 61 | chart: { 62 | type: "LINE", 63 | options: { 64 | // options for google charts 65 | // https://google-developers.appspot.com/chart/interactive/docs/gallery 66 | title: "Last 30 days pageviews" 67 | } 68 | } 69 | } 70 | 71 | // graph 2 config 72 | const last7days = { 73 | reportType: "ga", 74 | query: { 75 | dimensions: "ga:date", 76 | metrics: "ga:pageviews", 77 | "start-date": "7daysAgo", 78 | "end-date": "yesterday" 79 | }, 80 | chart: { 81 | type: "LINE" 82 | } 83 | } 84 | 85 | // analytics views ID 86 | const views = { 87 | query: { 88 | ids: "ga:87986986" 89 | } 90 | } 91 | 92 | const Example = () => ( 93 | 94 | 95 | 96 | 97 | ) 98 | ``` 99 | 100 | ### Server-side token authentication 101 | 102 | ```js 103 | 104 | import React, { Component } from 'react'; 105 | import { GoogleProvider, GoogleDataChart } from 'react-analytics-widget' 106 | 107 | // graph 1 config 108 | const last30days = { 109 | reportType: "ga", 110 | query: { 111 | dimensions: "ga:date", 112 | metrics: "ga:pageviews", 113 | "start-date": "30daysAgo", 114 | "end-date": "yesterday" 115 | }, 116 | chart: { 117 | type: "LINE", 118 | options: { 119 | // options for google charts 120 | // https://google-developers.appspot.com/chart/interactive/docs/gallery 121 | title: "Last 30 days pageviews" 122 | } 123 | } 124 | } 125 | 126 | // graph 2 config 127 | const last7days = { 128 | reportType: "ga", 129 | query: { 130 | dimensions: "ga:date", 131 | metrics: "ga:pageviews", 132 | "start-date": "7daysAgo", 133 | "end-date": "yesterday" 134 | }, 135 | chart: { 136 | type: "LINE" 137 | } 138 | } 139 | 140 | // analytics views ID 141 | const views = { 142 | query: { 143 | ids: "ga:87986986" 144 | } 145 | } 146 | 147 | class Example extends Component { 148 | componentDidMount = () => { 149 | const request = new Request('https://yourserver.example/auth/ganalytics/getToken', { 150 | method: 'GET' 151 | }); 152 | fetch(request) 153 | .then(response => response.json()) 154 | .then(({ token }) => { 155 | this.setState({ token }); // TODO: handle errors 156 | }); 157 | } 158 | 159 | render = () => ( 160 | 161 | 162 | 163 | 164 | ) 165 | } 166 | ``` 167 | 168 | [npm-badge]: https://img.shields.io/npm/v/react-analytics-widget.png?style=flat-square 169 | [npm]: https://www.npmjs.org/package/react-analytics-widget 170 | -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/revolunet/react-analytics-widget/c0f529f71db4136abb34ab4c5d2777dc55d1dd29/demo.png -------------------------------------------------------------------------------- /demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react" 2 | import { render } from "react-dom" 3 | import GithubCorner from 'react-github-corner'; 4 | 5 | import { GoogleProvider, GoogleDataChart } from "../../src" 6 | 7 | ;(function(w, d, s, g, js, fjs) { 8 | g = w.gapi || (w.gapi = {}) 9 | g.analytics = { 10 | q: [], 11 | ready: function(cb) { 12 | this.q.push(cb) 13 | } 14 | } 15 | js = d.createElement(s) 16 | fjs = d.getElementsByTagName(s)[0] 17 | js.src = "https://apis.google.com/js/platform.js" 18 | fjs.parentNode.insertBefore(js, fjs) 19 | js.onload = function() { 20 | g.load("analytics") 21 | } 22 | })(window, document, "script") 23 | 24 | const CHARTS = [ 25 | { 26 | reportType: "ga", 27 | query: { 28 | dimensions: "ga:date", 29 | metrics: "ga:sessions", 30 | "start-date": "10daysAgo", 31 | "end-date": "yesterday" 32 | }, 33 | chart: { 34 | type: "LINE", 35 | options: { 36 | title: "Last 10 days sessions", 37 | width: '100%' 38 | } 39 | } 40 | }, 41 | { 42 | reportType: "ga", 43 | query: { 44 | dimensions: "ga:date", 45 | metrics: "ga:sessions", 46 | "start-date": "30daysAgo", 47 | "end-date": "yesterday" 48 | }, 49 | chart: { 50 | type: "LINE", 51 | options: { 52 | title: "Last 30 days sessions", 53 | width: '100%' 54 | } 55 | } 56 | }, 57 | { 58 | reportType: "ga", 59 | query: { 60 | dimensions: "ga:date", 61 | metrics: "ga:pageviews", 62 | "start-date": "30daysAgo", 63 | "end-date": "yesterday" 64 | }, 65 | chart: { 66 | type: "LINE", 67 | options: { 68 | title: "Last 30 days pageviews", 69 | width: '100%' 70 | } 71 | } 72 | }, 73 | { 74 | reportType: "ga", 75 | query: { 76 | dimensions: "ga:date", 77 | metrics: "ga:goalCompletionsAll", 78 | "start-date": "30daysAgo", 79 | "end-date": "yesterday" 80 | }, 81 | chart: { 82 | type: "LINE", 83 | options: { 84 | title: "Last 30 days conversions", 85 | width: '100%' 86 | } 87 | } 88 | } 89 | ] 90 | 91 | // App credential in the google developer console 92 | var CLIENT_ID = "960315238073-dv345fcj3tkikn506k9lrch73hk9259u.apps.googleusercontent.com" 93 | 94 | class Example extends React.Component { 95 | state = { 96 | ids: "ga:150278027" 97 | } 98 | render() { 99 | const views = { 100 | query: { 101 | ids: this.state.ids 102 | } 103 | } 104 | return ( 105 |
106 | 107 | 108 |
109 | Define your view ID : 110 | this.setState({ ids: e.target.value })} value={this.state.ids} /> 111 | 112 |
113 |
114 | {CHARTS.map((c, i) => )} 115 |
116 |
117 | ) 118 | } 119 | } 120 | 121 | render(, document.getElementById("demo")) 122 | -------------------------------------------------------------------------------- /nwb.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | type: 'react-component', 3 | npm: { 4 | esModules: true, 5 | umd: false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-analytics-widget", 3 | "version": "1.2.0", 4 | "description": "Embed Google Analytics widgets in your React applications", 5 | "main": "lib/index.js", 6 | "module": "es/index.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/revolunet/react-analytics-widget.git" 10 | }, 11 | "homepage": "https://revolunet.github.io/react-analytics-widget/", 12 | "bugs": { 13 | "url": "https://github.com/revolunet/react-analytics-widget/issues" 14 | }, 15 | "files": [ 16 | "css", 17 | "es", 18 | "lib", 19 | "umd" 20 | ], 21 | "scripts": { 22 | "build": "nwb build-react-component", 23 | "clean": "nwb clean-module && nwb clean-demo", 24 | "start": "nwb serve-react-demo", 25 | "test": "nwb test-react", 26 | "publish": "gh-pages -d demo/dist && git push", 27 | "test:coverage": "nwb test-react --coverage", 28 | "test:watch": "nwb test-react --server" 29 | }, 30 | "peerDependencies": { 31 | "react": "15.x" 32 | }, 33 | "devDependencies": { 34 | "gh-pages": "^1.0.0", 35 | "nwb": "0.18.x", 36 | "react": "^15.6.1", 37 | "react-dom": "^15.6.1", 38 | "react-github-corner": "^0.3.0" 39 | }, 40 | "author": "Julien Bouquillon ", 41 | "license": "MIT", 42 | "keywords": [ 43 | "react-component", 44 | "analytics", 45 | "widget" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import PropTypes from 'prop-types'; 4 | 5 | // dont wait for auth twice, even after unmounts 6 | let isLoaded = false; 7 | 8 | // wait for auth to display children 9 | export class GoogleProvider extends React.Component { 10 | state = { 11 | ready: false 12 | }; 13 | componentDidMount() { 14 | this.init(); 15 | } 16 | init = () => { 17 | const doAuth = () => { 18 | const authObj = this.props.accessToken ? 19 | {serverAuth: {access_token: this.props.accessToken}} : 20 | {clientid: this.props.clientId}; 21 | gapi.analytics.auth && 22 | gapi.analytics.auth.authorize({ 23 | ...authObj, 24 | container: this.authButtonNode 25 | }); 26 | }; 27 | gapi.analytics.ready(a => { 28 | if (isLoaded) { 29 | this.setState({ 30 | ready: true 31 | }); 32 | return; 33 | } 34 | const authResponse = gapi.analytics.auth.getAuthResponse(); 35 | if (!authResponse) { 36 | gapi.analytics.auth.on("success", response => { 37 | this.setState({ 38 | ready: true 39 | }); 40 | }); 41 | } else { 42 | this.setState({ 43 | ready: true 44 | }); 45 | } 46 | doAuth(); 47 | }); 48 | }; 49 | render() { 50 | return ( 51 |
52 | {this.props.clientId &&
(this.authButtonNode = node)} />} 53 | {this.state.ready && this.props.children} 54 |
55 | ); 56 | } 57 | } 58 | GoogleProvider.propTypes = { 59 | clientId: PropTypes.string, 60 | accessToken: PropTypes.string, 61 | } 62 | 63 | // single chart 64 | export class GoogleDataChart extends React.Component { 65 | componentDidMount() { 66 | this.loadChart(); 67 | } 68 | componentWillUpdate() { 69 | this.loadChart(); 70 | } 71 | componentWillUnmount() { 72 | // TODO: cleanup 73 | } 74 | loadChart = () => { 75 | const config = { 76 | ...this.props.config, 77 | chart: { 78 | ...this.props.config.chart, 79 | container: this.chartNode 80 | } 81 | }; 82 | this.chart = new gapi.analytics.googleCharts.DataChart(config); 83 | this.chart.set(this.props.views).execute(); 84 | }; 85 | render() { 86 | return ( 87 |
(this.chartNode = node)} 91 | /> 92 | ); 93 | } 94 | } 95 | --------------------------------------------------------------------------------