Skip to content

Commit 7b89dc7

Browse files
Add link tracking
1 parent 5a6c239 commit 7b89dc7

File tree

5 files changed

+73
-5
lines changed

5 files changed

+73
-5
lines changed

src/core/utils.js

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import { fetchAddon } from 'core/api';
66
import log from 'core/logger';
77
import purify from 'core/purify';
88

9+
import {
10+
EXTENSION_TYPE,
11+
THEME_TYPE,
12+
} from 'core/constants';
13+
914
export function gettext(str) {
1015
return str;
1116
}
@@ -102,3 +107,10 @@ export function loadAddonIfNeeded(
102107
return fetchAddon({ slug, api: state.api })
103108
.then(({ entities }) => dispatch(loadEntities(entities)));
104109
}
110+
111+
export function getAction(type) {
112+
return {
113+
[EXTENSION_TYPE]: 'addon',
114+
[THEME_TYPE]: 'theme',
115+
}[type] || 'invalid';
116+
}

src/disco/components/Addon.js

+19-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
55
import { connect } from 'react-redux';
66
import translate from 'core/i18n/translate';
77

8-
import { sanitizeHTML } from 'core/utils';
8+
import { getAction, sanitizeHTML } from 'core/utils';
99
import config from 'config';
1010
import themeAction, { getThemeData } from 'disco/themePreview';
1111
import tracking from 'core/tracking';
@@ -37,6 +37,7 @@ import {
3737
validInstallStates,
3838
} from 'core/constants';
3939
import {
40+
CLICK_CATEGORY,
4041
CLOSE_INFO,
4142
INSTALL_CATEGORY,
4243
SET_ENABLE_NOT_AVAILABLE,
@@ -69,12 +70,14 @@ export class Addon extends React.Component {
6970
textcolor: PropTypes.string,
7071
themeAction: PropTypes.func,
7172
type: PropTypes.oneOf(validAddonTypes).isRequired,
73+
_tracking: PropTypes.object,
7274
}
7375

7476
static defaultProps = {
7577
// Defaults themeAction to the imported func.
7678
themeAction,
7779
needsRestart: false,
80+
_tracking: tracking,
7881
}
7982

8083
componentDidMount() {
@@ -90,6 +93,7 @@ export class Addon extends React.Component {
9093
return JSON.stringify(getThemeData(this.props));
9194
}
9295

96+
9397
getError() {
9498
const { error, i18n, status } = this.props;
9599
return status === ERROR ? (<div className="notification error" key="error-overlay">
@@ -177,6 +181,18 @@ export class Addon extends React.Component {
177181
this.setCurrentStatus();
178182
}
179183

184+
clickHeadingLink = (e) => {
185+
const { type, name, _tracking } = this.props;
186+
187+
if (e.target.nodeName.toLowerCase() === 'a') {
188+
_tracking.sendEvent({
189+
action: getAction(type),
190+
category: CLICK_CATEGORY,
191+
label: name,
192+
});
193+
}
194+
}
195+
180196
clickInstallTheme = (e) => {
181197
const { guid, installTheme, name, status, type } = this.props;
182198
e.preventDefault();
@@ -220,6 +236,7 @@ export class Addon extends React.Component {
220236
</ReactCSSTransitionGroup>
221237
<div className="copy">
222238
<h2
239+
onClick={this.clickHeadingLink}
223240
ref="heading"
224241
className="heading"
225242
dangerouslySetInnerHTML={sanitizeHTML(heading, ['a', 'span'])} />
@@ -376,11 +393,8 @@ export function mapDispatchToProps(dispatch, { _tracking = tracking,
376393
},
377394

378395
uninstall({ guid, name, type }) {
379-
const action = {
380-
[EXTENSION_TYPE]: 'addon',
381-
[THEME_TYPE]: 'theme',
382-
}[type] || 'invalid';
383396
dispatch({ type: INSTALL_STATE, payload: { guid, status: UNINSTALLING } });
397+
const action = getAction(type);
384398
return _addonManager.uninstall(guid)
385399
.then(() => {
386400
_tracking.sendEvent({

src/disco/constants.js

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111

1212
export const INSTALL_CATEGORY = 'AMO Addon / Theme Installs';
1313
export const UNINSTALL_CATEGORY = 'AMO Addon / Theme Uninstalls';
14+
export const CLICK_CATEGORY = 'AMO Addon / Theme Clicks';
1415
export const VIDEO_CATEGORY = 'Discovery Video';
1516
export const NAVIGATION_CATEGORY = 'Discovery Navigation';
1617

tests/client/core/test_utils.js

+17
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import {
44
camelCaseProps,
55
convertBoolean,
66
findAddon,
7+
getAction,
78
getClientApp,
89
getClientConfig,
910
isValidClientApp,
1011
loadAddonIfNeeded,
1112
nl2br,
1213
} from 'core/utils';
1314

15+
import { EXTENSION_TYPE, THEME_TYPE } from 'core/constants';
16+
1417
import { unexpectedSuccess } from 'tests/client/helpers';
1518

1619
describe('camelCaseProps', () => {
@@ -331,3 +334,17 @@ describe('nl2br', () => {
331334
assert.equal(nl2br('\r\n\r\n'), '<br /><br />');
332335
});
333336
});
337+
338+
describe('getAction', () => {
339+
it('returns addon for EXTENSION_TYPE', () => {
340+
assert.equal(getAction(EXTENSION_TYPE), 'addon');
341+
});
342+
343+
it('returns theme for THEME_TYPE', () => {
344+
assert.equal(getAction(THEME_TYPE), 'theme');
345+
});
346+
347+
it('returns invalid for unknown type', () => {
348+
assert.equal(getAction('whatever'), 'invalid');
349+
});
350+
});

tests/client/disco/components/TestAddon.js

+24
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
UNINSTALLING,
3535
} from 'core/constants';
3636
import {
37+
CLICK_CATEGORY,
3738
CLOSE_INFO,
3839
INSTALL_CATEGORY,
3940
SET_ENABLE_NOT_AVAILABLE,
@@ -246,6 +247,29 @@ describe('<Addon />', () => {
246247
renderAddon(data);
247248
}, Error, 'Invalid addon type');
248249
});
250+
251+
it('tracks an add-on link click', () => {
252+
const fakeTracking = {
253+
sendEvent: sinon.stub(),
254+
};
255+
const data = {
256+
...result,
257+
_tracking: fakeTracking,
258+
name: 'foo',
259+
heading: 'This is <span>an <a href="https://addons.mozilla.org">add-on</a>/span>',
260+
type: EXTENSION_TYPE,
261+
};
262+
root = renderAddon(data);
263+
const heading = findDOMNode(root).querySelector('.heading');
264+
// We click the heading providing the link nodeName to emulate
265+
// bubbling.
266+
Simulate.click(heading, { target: { nodeName: 'A' } });
267+
assert.ok(fakeTracking.sendEvent.calledWith({
268+
action: 'addon',
269+
category: CLICK_CATEGORY,
270+
label: 'foo',
271+
}), sinon.format(fakeTracking.sendEvent.firstCall.args));
272+
});
249273
});
250274

251275

0 commit comments

Comments
 (0)