Skip to content
This repository was archived by the owner on Jan 6, 2023. It is now read-only.

Commit 25b93f7

Browse files
sebastienbarbiervladikoff
authored andcommitted
Implement all GA events (#1033)
1 parent dcd0182 commit 25b93f7

File tree

10 files changed

+86
-12
lines changed

10 files changed

+86
-12
lines changed

docs/metrics.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Data will be collected with Google Analytics and follow [Test Pilot standards](h
3434
- `cd4` - whether the user has, anywhere in their active notepad, italicized text. One of `true` or `false`.
3535
- `cd5` - whether the user has, anywhere in their active notepad, strikethrough text. One of `true` or `false`.
3636
- `cd6` - whether the user has, anywhere in their active notepad, a list. One of `true` or `false`.
37-
- `cd7` - the UI element used to open or close the notepad. Possible values TBD, but may include `closeButton`, `sidebarButton`, and `sidebarSwitcher`.
37+
- `cd7` - the UI element used to open or close the notepad. Possible values TBD, but may include `closeButton`, `sidebarButton`, `sidebarSwitcher`, `appBackground`, `appInactive`.
3838
- `cd8` - the reason an editing session ended. One of `timeout` or `closed`.
3939
- `cd9` - whether the user was able to load the note panel or not. One of `true` or `false`.
4040
- `cd10` - provide current user state. Possible values are: 'error', 'isSyncing', 'synced', 'openLogin', 'verifyAccount', 'reconnectSync', and 'signIn'.
@@ -220,5 +220,3 @@ deleted on server side. Those were deleted before v4.0.0-beta.4 (during multi-no
220220

221221
- `ec` - `notes`
222222
- `ea` - `delete-deleted-notes`
223-
224-

native/app/actions.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,20 @@ import { SYNC_AUTHENTICATED,
2020

2121
import browser from './browser';
2222
import { v4 as uuid4 } from 'uuid';
23+
import { trackEvent } from './utils/metrics';
2324
import sync from './utils/sync';
2425

2526
export function pleaseLogin() {
2627
return { type: PLEASE_LOGIN };
2728
}
2829

29-
export function kintoLoad(from) {
30+
export function kintoLoad(origin) {
3031
// Return id to callback using promises
3132
return (dispatch, getState) => {
3233
return new Promise((resolve, reject) => {
33-
dispatch({ type: TEXT_SYNCING, from: from });
34+
35+
dispatch({ type: TEXT_SYNCING, from: origin });
36+
3437
sync.loadFromKinto(kintoClient, getState().sync.loginDetails).then(result => {
3538
if (result && result.data) {
3639
dispatch({ type: KINTO_LOADED, notes: result.data });
@@ -55,6 +58,10 @@ export function createNote(note = {}) {
5558
return (dispatch, getState) => {
5659
return new Promise((resolve, reject) => {
5760

61+
trackEvent('new-note', {
62+
el: 'list-view'
63+
});
64+
5865
note.id = uuid4();
5966
if (!note.lastModified) note.lastModified = new Date();
6067

@@ -83,6 +90,7 @@ export function createNote(note = {}) {
8390
}
8491

8592
export function updateNote(id, content, lastModified) {
93+
8694
browser.runtime.sendMessage({
8795
action: UPDATE_NOTE,
8896
id,
@@ -92,7 +100,11 @@ export function updateNote(id, content, lastModified) {
92100
return { type: UPDATE_NOTE, id, content, lastModified };
93101
}
94102

95-
export function deleteNote(id) {
103+
export function deleteNote(id, origin) {
104+
trackEvent('new-note', {
105+
el: origin
106+
});
107+
96108
browser.runtime.sendMessage({
97109
action: DELETE_NOTE,
98110
id

native/app/background.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import kintoClient from './vendor/kinto-client';
22
import fxaUtils from './vendor/fxa-utils';
3+
import { trackEvent } from './utils/metrics';
34

45
import { SYNC_AUTHENTICATED,
56
KINTO_LOADED,
@@ -52,7 +53,7 @@ browser.runtime.onMessage.addListener(eventData => {
5253
store.dispatch({ type: ERROR, message: eventData.message });
5354
break;
5455
case RECONNECT_SYNC:
55-
console.log('Implement me (background.js RECONNECT_SYNC message)');
56+
trackEvent('reconnect-sync');
5657
store.dispatch({ type: ERROR, message: 'Reconnect to Sync' });
5758
default:
5859
break;

native/app/components/DrawerItems.js

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class DrawerItems extends React.Component {
5858
{
5959
label : 'Feedback',
6060
action : () => {
61+
trackEvent('give-feedback');
6162
return Linking.openURL(SURVEY_PATH);
6263
}
6364
}
@@ -84,6 +85,8 @@ class DrawerItems extends React.Component {
8485
};
8586

8687
this._requestSync = () => {
88+
89+
trackEvent('webext-button-authenticate');
8790
props.dispatch(kintoLoad('drawer')).then(_ => {
8891
// If load succeed, we close drawer
8992
this.props.navigation.dispatch(DrawerActions.closeDrawer());

native/app/components/EditorPanel.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class RichTextExample extends Component {
4444
this.props.dispatch(setFocusedNote(note.id));
4545
});
4646
} else if (this.note && e === '') { // if we delete all caracters from a note
47-
this.props.dispatch(deleteNote(this.note.id));
47+
this.props.dispatch(deleteNote(this.note.id, 'blank-note'));
4848
this.note = null;
4949
this.props.dispatch(setFocusedNote());
5050
} else if (this.note && e !== '') { // default case, on modification we save

native/app/components/ListPanel.js

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { View, FlatList, StyleSheet, RefreshControl, AppState, Animated } from '
1111
import { COLOR_DARK_SYNC, COLOR_NOTES_BLUE, COLOR_NOTES_WHITE, KINTO_LOADED } from '../utils/constants';
1212
import { kintoLoad, createNote } from "../actions";
1313
import browser from '../browser';
14+
import { trackEvent } from '../utils/metrics';
15+
1416

1517
import ListPanelEmpty from './ListPanelEmpty';
1618
import ListPanelLoading from './ListPanelLoading';
@@ -40,6 +42,7 @@ class ListPanel extends React.Component {
4042
}
4143

4244
this._onRefresh = () => {
45+
trackEvent('webext-button-authenticate');
4346
this.setState({ refreshing: true });
4447
props.dispatch(kintoLoad()).then(() => {
4548
this.setState({ refreshing: false });
@@ -48,9 +51,12 @@ class ListPanel extends React.Component {
4851

4952
this._handleAppStateChange = (nextAppState) => {
5053
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
54+
trackEvent('open');
5155
props.dispatch(kintoLoad()).then(() => {
5256
this.setState({ refreshing: false });
5357
});
58+
} else {
59+
trackEvent('close', { state: nextAppState });
5460
}
5561
this.setState({ appState: nextAppState });
5662
}

native/app/components/MoreMenu.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class MoreMenu extends Component {
2828
return note.id === this.props.state.sync.focusedNoteId
2929
});
3030
if (deletedNote) {
31-
this.props.dispatch(deleteNote(deletedNote.id));
31+
this.props.dispatch(deleteNote(deletedNote.id, 'in-note'));
3232
}
3333
navigation.navigate('ListPanel', { deletedNote });
3434
break;

native/app/utils/metrics.js

+45-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,52 @@
11
import { GoogleAnalyticsTracker } from "react-native-google-analytics-bridge";
2+
import { store } from '../store';
23

34
// See https://github.com/mozilla/notes/blob/master/docs/metrics.md for details
45
const tracker = new GoogleAnalyticsTracker('UA-35433268-79');
56
const EVENT_CATEGORY = 'notes';
67

7-
export const trackEvent = (action) => {
8-
tracker.trackEvent(EVENT_CATEGORY, action);
8+
export const trackEvent = (action, optionalValues = {}) => {
9+
10+
const state = store.getState();
11+
12+
if (action === 'changed') {
13+
optionalValues.cd1 = state.profile.email !== null;
14+
}
15+
16+
if (action === 'close') {
17+
// See about appState : https://facebook.github.io/react-native/docs/appstate.html
18+
if (optionalValues.state === 'inactive') {
19+
optionalValues.cd7 = 'appInactive';
20+
} else if (optionalValues.state === 'background') {
21+
optionalValues.cd7 = 'appBackground';
22+
}
23+
}
24+
25+
optionalValues.cd9 = optionalValues.cd9 || 'true'; // if panel is loaded
26+
// Generate cd10 based on footer.js rules. Same in webext.
27+
if (state.sync && ['open', 'close', 'changed', 'drag-n-drop', 'new-note', 'export',
28+
'delete-note', 'give-feedback', 'limit-reached'].includes(action)) {
29+
if (state.sync.email) { // If user is authenticated
30+
if (state.sync.error) {
31+
optionalValues.cd10 = 'error';
32+
} else if (state.sync.isSyncing) {
33+
optionalValues.cd10 = 'isSyncing';
34+
} else {
35+
optionalValues.cd10 = 'synced';
36+
}
37+
} else {
38+
if (state.sync.isOpeningLogin) { // eslint-disable-line no-lonely-if
39+
optionalValues.cd10 = 'openLogin';
40+
} else if (state.sync.isPleaseLogin) {
41+
optionalValues.cd10 = 'verifyAccount';
42+
} else if (state.sync.isReconnectSync) {
43+
optionalValues.cd10 = 'reconnectSync';
44+
} else {
45+
optionalValues.cd10 = 'signIn';
46+
}
47+
}
48+
}
49+
50+
optionalValues.cd11 = state.notes.length;
51+
tracker.trackEvent(EVENT_CATEGORY, action, optionalValues);
952
};

native/app/utils/sync.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
} from '../actions';
44
import { store } from '../store';
55
import browser from '../browser';
6+
import { trackEvent } from './metrics';
7+
import striptags from 'striptags';
68

79
const fxaUtils = require('../vendor/fxa-utils');
810
const fxaCryptoRelier = require('../vendor/fxa-crypto-relier');
@@ -272,7 +274,7 @@ function syncKinto(client, loginDetails) {
272274
resolution.deleted = true;
273275
}
274276
client.conflict = true;
275-
// sendMetrics('handle-conflict'); // eslint-disable-line no-undef
277+
trackEvent('handle-conflict'); // eslint-disable-line no-undef
276278
}
277279
return collection.resolve(conflict, resolution);
278280
}))
@@ -390,6 +392,12 @@ function saveToKinto(client, loginDetails, note) { // eslint-disable-line no-unu
390392
action: TEXT_SYNCING
391393
});
392394

395+
trackEvent('changed', {
396+
cm1: striptags(note.content).length,
397+
cm2: (striptags(note.content.replace(/<\/p>|<\/li>/gi, '\n')).match(/\n/g) || []).length,
398+
cm3: null, // Size of change
399+
});
400+
393401
client.conflict = false;
394402
syncDebounce = null;
395403
return syncKinto(client, loginDetails)

native/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import { Toolbar, ToolbarContent, ToolbarAction, Provider as PaperProvider } fro
2727
import { COLOR_APP_BAR, COLOR_STATUS_BAR } from './app/utils/constants';
2828
import { store, persistor } from './app/store';
2929

30+
import { trackEvent } from './app/utils/metrics';
31+
3032
import DrawerItems from './app/components/DrawerItems';
3133
import EditorPanel from './app/components/EditorPanel';
3234
import EditorPanelHeader from './app/components/EditorPanelHeader';
@@ -137,6 +139,7 @@ class Notes extends React.Component {
137139
StatusBar.setBackgroundColor('rgba(249, 249, 250, 0.3)');
138140
StatusBar.setTranslucent(true);
139141
StatusBar.setBarStyle('dark-content');
142+
trackEvent('open');
140143
}
141144

142145
render () {

0 commit comments

Comments
 (0)