|
1 | 1 | import Vue from 'vue'; |
2 | | -import isFunction from 'lodash/isFunction'; |
3 | | - |
4 | | -/** |
5 | | - * Analytics class for handling anything analytics related, exposed in Vue as $analytics |
6 | | - */ |
7 | | -class Analytics { |
8 | | - /** |
9 | | - * GTM uses an array-like structure called the `dataLayer` |
10 | | - * |
11 | | - * @param {Array} dataLayer |
12 | | - */ |
13 | | - constructor(dataLayer) { |
14 | | - this.counter = 0; |
15 | | - this.dataLayer = dataLayer; |
16 | | - this.lastLength = 0; |
17 | | - |
18 | | - // add interval to trigger resets every 5 minutes |
19 | | - this.resetInterval = setInterval( |
20 | | - () => { |
21 | | - this.reset(); |
22 | | - }, |
23 | | - 5 * 60 * 1000, |
24 | | - ); |
25 | | - } |
26 | | - |
27 | | - /** |
28 | | - * Resets the datalayer and cleans up elements |
29 | | - */ |
30 | | - reset() { |
31 | | - // If the dataLayer hasn't changed since our last reset, skip |
32 | | - if (this.dataLayer.length === this.lastLength) { |
33 | | - if (process.env.NODE_ENV !== 'production') { |
34 | | - // eslint-disable-next-line no-console |
35 | | - console.info('Skipping Analytics.reset()'); |
36 | | - } |
37 | | - return; |
38 | | - } |
39 | | - |
40 | | - if (process.env.NODE_ENV !== 'production') { |
41 | | - // eslint-disable-next-line no-console |
42 | | - console.info('Analytics.reset()'); |
43 | | - } |
44 | | - |
45 | | - // Add local variable so the pushed reset function can access the datalayer |
46 | | - const dataLayer = this.dataLayer; |
47 | | - const resetCounter = this.counter; |
48 | | - this.counter++; |
49 | | - |
50 | | - // This can't use an arrow function, it will be called with a different |
51 | | - // context to access `this.reset()` |
52 | | - const dataLayerReset = function () { |
53 | | - // See https://developers.google.com/tag-platform/devguides/datalayer#reset |
54 | | - this.reset(); |
55 | | - |
56 | | - for (const item of dataLayer) { |
57 | | - // Do our own reset of the `gtm.element` variable |
58 | | - if (item['gtm.element']) { |
59 | | - item['gtm.element'] = null; |
60 | | - } |
61 | | - // Be sure we stop when we reach this function's position in the dataLayer. The dataLayer |
62 | | - // is like a FIFO queue, so by queuing this function and having the GTM execute it, we're |
63 | | - // ensuring that everything prior to this function was processed. For this reason, we stop |
64 | | - // once we reach the position of this function to avoid manipulating events that have been |
65 | | - // added afterwards |
66 | | - if (isFunction(item) && item['counter'] === resetCounter) { |
67 | | - break; |
68 | | - } |
69 | | - } |
70 | | - }; |
71 | | - dataLayerReset.counter = resetCounter; |
72 | | - |
73 | | - this.dataLayer.push(dataLayerReset); |
74 | | - this.lastLength = this.dataLayer.length; |
75 | | - } |
76 | | - |
77 | | - /** |
78 | | - * Push data onto the datalayer |
79 | | - * @param {object|function} args |
80 | | - */ |
81 | | - push(...args) { |
82 | | - this.dataLayer.push(...args); |
83 | | - } |
84 | | - |
85 | | - /** |
86 | | - * Push an event into the dataLayer |
87 | | - * |
88 | | - * These events could be standard GA events, or custom events that trigger tags within GTM |
89 | | - * |
90 | | - * @param {String} event |
91 | | - * @param {{:*}} data |
92 | | - */ |
93 | | - trackEvent(event, data = {}) { |
94 | | - this.push({ |
95 | | - ...data, |
96 | | - event, |
97 | | - }); |
98 | | - |
99 | | - if (process.env.NODE_ENV !== 'production') { |
100 | | - // eslint-disable-next-line no-console |
101 | | - console.info(`Analytics.trackEvent("${event}", ${JSON.stringify(data)})`); |
102 | | - } |
103 | | - } |
104 | | - |
105 | | - /** |
106 | | - * Tracks event with specific action |
107 | | - * |
108 | | - * @param {String} event |
109 | | - * @param {String} eventAction |
110 | | - * @param {{:*}} data |
111 | | - */ |
112 | | - trackAction(event, eventAction, data = {}) { |
113 | | - this.trackEvent(event, { ...data, eventAction }); |
114 | | - } |
115 | | - |
116 | | - /** |
117 | | - * Tracks event with click action |
118 | | - * |
119 | | - * @param {String} event |
120 | | - * @param {String} eventLabel |
121 | | - * @param {{:*}} data |
122 | | - */ |
123 | | - trackClick(event, eventLabel, data = {}) { |
124 | | - this.trackAction(event, 'Click', { ...data, eventLabel }); |
125 | | - } |
126 | | - |
127 | | - /** |
128 | | - * Pushes current channel data into the data layer for GTM to associate with events |
129 | | - * |
130 | | - * @param {Object} channel |
131 | | - * @param {Boolean} staging |
132 | | - */ |
133 | | - trackCurrentChannel(channel, staging = false) { |
134 | | - // We only want to track once, since a page reload is required to open a new channel |
135 | | - const hasCurrentChannel = this.dataLayer.find(data => Boolean(data['currentChannel'])); |
136 | | - if (hasCurrentChannel) { |
137 | | - return; |
138 | | - } |
139 | | - |
140 | | - this.push({ |
141 | | - currentChannel: { |
142 | | - id: channel.id, |
143 | | - name: channel.name, |
144 | | - lastPublished: channel.last_published, |
145 | | - isPublic: channel.public, |
146 | | - allowEdit: channel.edit, |
147 | | - staging, |
148 | | - // Skipping this field for now as we don't have this info on the frontend by default |
149 | | - // hasEditors: |
150 | | - }, |
151 | | - }); |
152 | | - } |
153 | | - |
154 | | - /** |
155 | | - * Cleans up the datalayer and removes the interval to call dataLayer.reset() |
156 | | - */ |
157 | | - destroy() { |
158 | | - clearInterval(this.resetInterval); |
159 | | - this.dataLayer = null; |
160 | | - } |
161 | | -} |
| 2 | +// the new home for analytics |
| 3 | +import { Analytics } from 'shared/composables/useAnalytics'; |
162 | 4 |
|
163 | 5 | /** |
164 | 6 | * @param Vue |
|
0 commit comments