@shopgate/tracking-core 7.30.0-alpha.7 → 7.30.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/AppHandler.js +121 -19
- package/core/Core.js +337 -82
- package/helpers/events.js +46 -7
- package/helpers/formatHelpers.js +324 -49
- package/helpers/helper.js +247 -36
- package/helpers/optOut.js +114 -13
- package/helpers/urlMapping.js +110 -14
- package/package.json +3 -3
- package/plugins/Base.js +94 -17
- package/plugins/trackers/FbPixel.js +186 -17
- package/plugins/trackers/GaBase.js +250 -31
- package/plugins/trackers/GaClassic.js +93 -13
- package/plugins/trackers/GaUniversal.js +162 -16
- package/plugins/trackers/Unified.js +67 -11
- package/typedef.js +51 -17
|
@@ -1,10 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import BasePlugin from "../Base";
|
|
2
|
+
import SgGAUniversalTracking from "./GaUniversal";
|
|
3
|
+
import SgGAClassicTracking from "./GaClassic";
|
|
4
|
+
import { SGLink } from "../../helpers/helper";
|
|
5
|
+
const TRACK_PAGE_VIEW = 'pageView';
|
|
6
|
+
const TRACK_EVENT = 'event';
|
|
7
|
+
const TRACK_SET = 'set';
|
|
8
|
+
const TRACK_REQUIRE = 'require';
|
|
9
|
+
const TRACK_CONVERSION = {
|
|
10
|
+
ADDITEM: 'addItem',
|
|
11
|
+
CURRENCY: 'currencyCode',
|
|
12
|
+
END: 'trackTrans',
|
|
13
|
+
START: 'addTrans',
|
|
14
|
+
PAGE: 'page'
|
|
15
|
+
};
|
|
16
|
+
const ACCOUNT_CLASSIC = 'classic';
|
|
17
|
+
const ACCOUNT_UNIVERSAL = 'universal';
|
|
18
|
+
const shopgateOnly = {
|
|
19
|
+
merchant: false,
|
|
20
|
+
shopgate: true
|
|
21
|
+
};
|
|
22
|
+
const merchantOnly = {
|
|
23
|
+
merchant: true,
|
|
24
|
+
shopgate: false
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// Command mapping tuple, [classic, universal]
|
|
28
|
+
const commandMapping = {};
|
|
29
|
+
commandMapping[TRACK_PAGE_VIEW] = ['trackPageview', 'pageview'];
|
|
30
|
+
commandMapping[TRACK_EVENT] = ['trackEvent', 'event'];
|
|
31
|
+
commandMapping[TRACK_SET] = [undefined, 'set'];
|
|
32
|
+
commandMapping[TRACK_CONVERSION.ADDITEM] = ['addItem', 'ecommerce:addItem'];
|
|
33
|
+
commandMapping[TRACK_CONVERSION.CURRENCY] = ['currencyCode'];
|
|
34
|
+
commandMapping[TRACK_CONVERSION.END] = ['trackTrans', 'ecommerce:send'];
|
|
35
|
+
commandMapping[TRACK_CONVERSION.START] = ['addTrans', 'ecommerce:addTransaction'];
|
|
36
|
+
commandMapping[TRACK_REQUIRE] = [undefined, 'require'];
|
|
37
|
+
|
|
38
|
+
/**
|
|
3
39
|
* Parent Tracking plugin for Google Analytics
|
|
4
|
-
*/
|
|
40
|
+
*/
|
|
41
|
+
class GaBase extends BasePlugin {
|
|
42
|
+
/**
|
|
5
43
|
* Constructor
|
|
6
|
-
*/
|
|
7
|
-
|
|
44
|
+
*/
|
|
45
|
+
constructor() {
|
|
46
|
+
super('GAcore', {});
|
|
47
|
+
|
|
48
|
+
// Universal and classic merchant and shopgate accounts
|
|
49
|
+
this.accounts = [];
|
|
50
|
+
this.isRegistered = false;
|
|
51
|
+
this.universalPlugin = null;
|
|
52
|
+
this.classicPlugin = null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
8
56
|
* Returns common data for a custom event
|
|
9
57
|
* @param {string} name Event category
|
|
10
58
|
* @param {Object} data Input
|
|
@@ -16,7 +64,18 @@ _this2.accounts=[];_this2.isRegistered=false;_this2.universalPlugin=null;_this2.
|
|
|
16
64
|
* nonInteraction: (boolean)
|
|
17
65
|
* }}
|
|
18
66
|
* @private
|
|
19
|
-
*/
|
|
67
|
+
*/
|
|
68
|
+
static getEventData(name, data) {
|
|
69
|
+
return {
|
|
70
|
+
eventCategory: name,
|
|
71
|
+
eventAction: data.eventAction,
|
|
72
|
+
eventLabel: data.eventLabel,
|
|
73
|
+
eventValue: data.eventValue,
|
|
74
|
+
nonInteraction: data.nonInteraction
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
20
79
|
* Send command to both universal and classic sdk
|
|
21
80
|
*
|
|
22
81
|
* @param {string} command Name of the command
|
|
@@ -25,36 +84,196 @@ _this2.accounts=[];_this2.isRegistered=false;_this2.universalPlugin=null;_this2.
|
|
|
25
84
|
* @param {Object} [scope] Scope (merchant or shopgate account)
|
|
26
85
|
* @param {string} [account] Which account to use, classic or universal
|
|
27
86
|
* @private
|
|
28
|
-
*/
|
|
29
|
-
|
|
87
|
+
*/
|
|
88
|
+
sendCommand(command, payload, scope, account) {
|
|
89
|
+
if (typeof commandMapping[command] === 'undefined') {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Evaluate which accounts to send to.
|
|
94
|
+
const isClassic = typeof account === 'undefined' || account === ACCOUNT_CLASSIC;
|
|
95
|
+
const isUniversal = typeof account === 'undefined' || account === ACCOUNT_UNIVERSAL;
|
|
96
|
+
if (isUniversal && this.universalPlugin !== null) {
|
|
97
|
+
this.universalPlugin.send(commandMapping[command][1], payload, scope);
|
|
98
|
+
}
|
|
99
|
+
if (isClassic && this.classicPlugin !== null) {
|
|
100
|
+
this.classicPlugin.send(commandMapping[command][0], payload, scope);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
30
105
|
* Helper to register for some events
|
|
31
106
|
* @private
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
this.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.register.
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.register.
|
|
46
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.register.
|
|
51
|
-
this.
|
|
107
|
+
*/
|
|
108
|
+
registerEvents() {
|
|
109
|
+
if (this.isRegistered) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.isRegistered = true;
|
|
113
|
+
|
|
114
|
+
// Handle pageview event for shopgate accounts
|
|
115
|
+
this.register.pageview(data => {
|
|
116
|
+
this.sendCommand(TRACK_PAGE_VIEW, data.page.shopgateUrl, shopgateOnly);
|
|
117
|
+
}, shopgateOnly);
|
|
118
|
+
|
|
119
|
+
// Handle pageview event for merchant account
|
|
120
|
+
this.register.pageview(data => {
|
|
121
|
+
this.sendCommand(TRACK_PAGE_VIEW, data.page.merchantUrl, merchantOnly);
|
|
122
|
+
}, merchantOnly);
|
|
123
|
+
|
|
124
|
+
// Handle add_to_cart event as a pageview
|
|
125
|
+
this.register.addToCart(() => {
|
|
126
|
+
this.sendCommand(TRACK_PAGE_VIEW, 'add_to_cart');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Smart app banner
|
|
130
|
+
this.register.smartbanner(data => {
|
|
131
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('Smartbanner', data));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Scroll to top button event
|
|
135
|
+
this.register.scrollTop(data => {
|
|
136
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('ScrollTop', data), shopgateOnly);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Qr scanner events
|
|
140
|
+
this.register.qrScanner(data => {
|
|
141
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('QRScanner', data));
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Ad scanner events
|
|
145
|
+
this.register.adScanner((data, originalData, scope) => {
|
|
146
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('AdScanner', data), scope);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Credit card scanner events
|
|
150
|
+
this.register.ccScanner(data => {
|
|
151
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('CcScanner', data));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Filter in live suggest events
|
|
155
|
+
this.register.filterLiveSuggest(data => {
|
|
156
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('FilterLiveSuggest', data), shopgateOnly);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Deeplink
|
|
160
|
+
this.register.openDeepLink(data => {
|
|
161
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('DeepLinkOpen', data), shopgateOnly);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Universal link
|
|
165
|
+
this.register.openUniversalLink(data => {
|
|
166
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('UniversalLinkOpen', data), shopgateOnly);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Deferred deep link
|
|
170
|
+
this.register.openDeferredDeepLink(data => {
|
|
171
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('DeferredDeepLinkOpen', data), shopgateOnly);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Smart app download link
|
|
175
|
+
this.register.openSmartAppDownloadLink(data => {
|
|
176
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('SmartAppDownloadLink', data), shopgateOnly);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Push notification
|
|
180
|
+
this.register.openPushNotification(data => {
|
|
181
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('PushNotification', data), shopgateOnly);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Push notification
|
|
185
|
+
this.register.setCampaignWithUrl((data, raw) => {
|
|
186
|
+
const shopgateUrl = new SGLink(data.url);
|
|
187
|
+
shopgateUrl.setUtmParams(data, raw);
|
|
188
|
+
this.sendCommand(TRACK_SET, ['campaignName', shopgateUrl.getParam('utm_campaign')], undefined, ACCOUNT_UNIVERSAL);
|
|
189
|
+
this.sendCommand(TRACK_SET, ['campaignSource', shopgateUrl.getParam('utm_source')], undefined, ACCOUNT_UNIVERSAL);
|
|
190
|
+
this.sendCommand(TRACK_SET, ['campaignMedium', shopgateUrl.getParam('utm_medium')], undefined, ACCOUNT_UNIVERSAL);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// App review prompt
|
|
194
|
+
this.register.appReviewPrompt(data => {
|
|
195
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('AppReviewPrompt', data), shopgateOnly);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Purchase events
|
|
199
|
+
this.register.purchase((data, rawData) => {
|
|
200
|
+
this.sendCommand('require', ['ecommerce', 'ecommerce.js'], null, ACCOUNT_UNIVERSAL);
|
|
201
|
+
this.sendCommand(TRACK_CONVERSION.START, account => ({
|
|
202
|
+
amountCompleteFloat: account.useNetPrices ? data.revenueNet : data.revenueGross,
|
|
203
|
+
amountTaxCompleteFloat: data.tax,
|
|
204
|
+
amountShippingFloat: account.useNetPrices ? data.shippingNet : data.shippingGross,
|
|
205
|
+
city: rawData.order.shippingAddress.city,
|
|
206
|
+
countryId: rawData.order.shippingAddress.country,
|
|
207
|
+
currency: data.currency,
|
|
208
|
+
orderNumber: data.id,
|
|
209
|
+
shopName: data.affiliation,
|
|
210
|
+
state: rawData.order.shippingAddress.stateId || ''
|
|
211
|
+
}));
|
|
212
|
+
data.items.forEach(item => {
|
|
213
|
+
this.sendCommand(TRACK_CONVERSION.ADDITEM, account => ({
|
|
214
|
+
orderNumber: rawData.order.number,
|
|
215
|
+
productNumber: item.id,
|
|
216
|
+
name: item.name,
|
|
217
|
+
quantity: item.quantity,
|
|
218
|
+
unitAmount: account.useNetPrices ? item.priceNet : item.priceGross
|
|
219
|
+
}));
|
|
220
|
+
});
|
|
221
|
+
this.sendCommand(TRACK_SET, [TRACK_CONVERSION.CURRENCY, data.currency], null, ACCOUNT_CLASSIC);
|
|
222
|
+
this.sendCommand(TRACK_CONVERSION.END);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Opt-out
|
|
226
|
+
this.register.removeTracker(() => {
|
|
227
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('analyticsOptOut', {
|
|
228
|
+
eventAction: 'optOut',
|
|
229
|
+
eventLabel: 'all_accounts'
|
|
230
|
+
}));
|
|
231
|
+
this.accounts.forEach(account => {
|
|
232
|
+
const disableStr = `ga-disable-${account.id}`;
|
|
233
|
+
document.cookie = `${disableStr}=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/`;
|
|
234
|
+
window[disableStr] = true;
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Revert opt-out
|
|
239
|
+
this.register.addTracker(() => {
|
|
240
|
+
this.accounts.forEach(account => {
|
|
241
|
+
const disableStr = `ga-disable-${account.id}`;
|
|
242
|
+
document.cookie = `${disableStr}=false; expires=Thu, 01 Jan 1970 00:00:01 UTC; path=/`;
|
|
243
|
+
window[disableStr] = false;
|
|
244
|
+
});
|
|
245
|
+
this.sendCommand(TRACK_EVENT, GaBase.getEventData('revertOptOut', {
|
|
246
|
+
eventAction: 'optOut',
|
|
247
|
+
eventLabel: 'all_accounts'
|
|
248
|
+
}));
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
52
253
|
* Creates an ga universals child tracker
|
|
53
254
|
* @param {Object} tracker Tracker configuration data
|
|
54
255
|
* @returns {GaUniversal} plugin instance
|
|
55
|
-
*/
|
|
256
|
+
*/
|
|
257
|
+
createUniversal(tracker) {
|
|
258
|
+
this.accounts.push(...tracker.config.merchant, tracker.config.shopgate);
|
|
259
|
+
this.universalPlugin = new SgGAUniversalTracking(tracker);
|
|
260
|
+
this.registerEvents();
|
|
261
|
+
return this.universalPlugin;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
56
265
|
* Creates a ga classic child tracker
|
|
57
266
|
* @param {Object} tracker Tracker configuration data
|
|
58
267
|
* @returns {GaClassic} plugin instance
|
|
59
|
-
*/
|
|
60
|
-
|
|
268
|
+
*/
|
|
269
|
+
createClassic(tracker) {
|
|
270
|
+
this.accounts.push(...tracker.config.merchant);
|
|
271
|
+
this.classicPlugin = new SgGAClassicTracking(tracker);
|
|
272
|
+
this.registerEvents();
|
|
273
|
+
return this.classicPlugin;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Export and create global instance
|
|
278
|
+
window.SgGATrackingInstance = new GaBase();
|
|
279
|
+
export default window.SgGATrackingInstance;
|
|
@@ -1,34 +1,114 @@
|
|
|
1
|
-
|
|
1
|
+
/* global _gaq */
|
|
2
|
+
|
|
3
|
+
/**
|
|
2
4
|
* Tracking plugin for google analytics classic accounts
|
|
3
|
-
*/
|
|
5
|
+
*/
|
|
6
|
+
class GaClassic {
|
|
7
|
+
/**
|
|
4
8
|
* Constructor
|
|
5
9
|
* @param {Object} options Common Tracking Configuration
|
|
6
10
|
* @param {boolean} [options.overrideUnified] If true -> overrides our unified tracking system
|
|
7
11
|
* @param {boolean} [options.useNativeSdk] If true -> send data via our unified tracking system
|
|
8
12
|
* to the native sdk
|
|
9
13
|
* @param {Object} [options.config] Configuration for google analytics classic tracking
|
|
10
|
-
*/
|
|
11
|
-
|
|
14
|
+
*/
|
|
15
|
+
constructor(options) {
|
|
16
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
17
|
+
window._gaq = window._gaq || [];
|
|
18
|
+
this.merchantAccounts = options.config.merchant;
|
|
19
|
+
|
|
20
|
+
/**
|
|
12
21
|
* List of functions that can be used to filter data
|
|
13
22
|
* @type {Object}
|
|
14
|
-
*/
|
|
15
|
-
|
|
23
|
+
*/
|
|
24
|
+
this.filters = {
|
|
25
|
+
addTrans(data) {
|
|
26
|
+
return [data.orderNumber, data.shopName, data.amountCompleteFloat, data.amountTaxCompleteFloat, data.amountShippingFloat, data.city, '',
|
|
27
|
+
// State
|
|
28
|
+
data.countryId];
|
|
29
|
+
},
|
|
30
|
+
addItem(data) {
|
|
31
|
+
return [data.orderNumber, data.productNumber, data.name, '', data.unitAmount, data.quantity];
|
|
32
|
+
},
|
|
33
|
+
trackEvent(data) {
|
|
34
|
+
return [data.eventCategory, data.eventAction, data.eventLabel, data.eventValue, data.nonInteraction];
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
this.initPlugin();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
16
41
|
* Initiate and setup the SDK
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
42
|
+
*/
|
|
43
|
+
initPlugin() {
|
|
44
|
+
// Load the SDK
|
|
45
|
+
/* eslint-disable eslint-comments/no-unlimited-disable */
|
|
46
|
+
/* eslint-disable */
|
|
47
|
+
if (typeof window._gaq === 'undefined' || typeof window._gaq._getAsyncTracker === 'undefined' || global && global.it) {
|
|
48
|
+
(function () {
|
|
49
|
+
var gaJs = document.createElement('script');
|
|
50
|
+
gaJs.type = 'text/javascript';
|
|
51
|
+
gaJs.async = true;
|
|
52
|
+
gaJs.src = 'https://ssl.google-analytics.com/ga.js';
|
|
53
|
+
var s = document.getElementsByTagName('script')[0];
|
|
54
|
+
s.parentNode.insertBefore(gaJs, s);
|
|
55
|
+
})();
|
|
56
|
+
}
|
|
57
|
+
/* eslint-enable */
|
|
58
|
+
|
|
59
|
+
// Setup merchant accounts
|
|
60
|
+
this.merchantAccounts.forEach((account, index) => {
|
|
61
|
+
const prefix = `${GaClassic.buildMerchantPrefix(index ? account.id : '')}.`;
|
|
62
|
+
_gaq.push([`${prefix}_setAccount`, account.id], [`${prefix}_setAllowLinker`, true]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Set global options
|
|
66
|
+
_gaq.push(['_gat._anonymizeIp', true], ['_gat._forceSSL', true]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
21
70
|
* Helper to generate the prefix for an account
|
|
22
71
|
*
|
|
23
72
|
* @param {string} id Id of the account
|
|
24
73
|
* @returns {string} Prefix for the account
|
|
25
|
-
*/
|
|
74
|
+
*/
|
|
75
|
+
static buildMerchantPrefix(id) {
|
|
76
|
+
return `merchant_${id}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
26
80
|
* Function that sends the given command with the payload to the GA SDK
|
|
27
81
|
* @param {string} command Name of the command
|
|
28
82
|
* @param {Object|Array|string|Function} payload Data for the command,
|
|
29
83
|
* or a function that returns data
|
|
30
84
|
* @param {Object} [scope={}] Info if the event is for merchant and/or shopgate account
|
|
31
|
-
*/
|
|
85
|
+
*/
|
|
86
|
+
send(command, payload, scope = {}) {
|
|
87
|
+
const defaults = {
|
|
88
|
+
merchant: true,
|
|
89
|
+
shopgate: true
|
|
90
|
+
};
|
|
91
|
+
const mergedScope = {
|
|
92
|
+
...defaults,
|
|
93
|
+
...scope
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
32
97
|
* Since we migrates all our classic account to universal,
|
|
33
98
|
* Only the merchant can have classic accounts
|
|
34
|
-
*/
|
|
99
|
+
*/
|
|
100
|
+
if (mergedScope.merchant) {
|
|
101
|
+
this.merchantAccounts.forEach((account, index) => {
|
|
102
|
+
let data = typeof payload === 'function' ? payload(account) : payload;
|
|
103
|
+
data = typeof this.filters[command] !== 'undefined' ? this.filters[command](data) : data;
|
|
104
|
+
const cmd = `${GaClassic.buildMerchantPrefix(index ? account.id : '')}._${command}`;
|
|
105
|
+
if (Array.isArray(data)) {
|
|
106
|
+
_gaq.push([cmd, ...data]);
|
|
107
|
+
} else {
|
|
108
|
+
_gaq.push([cmd, data]);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export default GaClassic;
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import "core-js/modules/es.string.replace.js";
|
|
2
|
+
/* global ga */
|
|
3
|
+
|
|
4
|
+
// SgData access type constant for apps
|
|
5
|
+
const ACCESS_TYPE_APP = 'App';
|
|
6
|
+
|
|
7
|
+
/**
|
|
3
8
|
* Dimensions and metrics
|
|
4
9
|
* See: https://shopgate.atlassian.net/wiki/display/CONSUMER/Google+Analytics
|
|
5
|
-
*/
|
|
10
|
+
*/
|
|
11
|
+
const DIMENSION_SHOP_NUMBER = 'dimension1';
|
|
12
|
+
const DIMENSION_CODEBASE_VERSION = 'dimension2';
|
|
13
|
+
|
|
14
|
+
/**
|
|
6
15
|
* Tracking plugin for google analytics classic accounts
|
|
7
|
-
*/
|
|
16
|
+
*/
|
|
17
|
+
class GaUniversal {
|
|
18
|
+
/**
|
|
8
19
|
* Constructor
|
|
9
20
|
*
|
|
10
21
|
* @param {Object} options Common Tracking Configuration
|
|
@@ -14,33 +25,168 @@ var ACCESS_TYPE_APP='App';/**
|
|
|
14
25
|
* @param {boolean} [options.useNativeSdk] If true -> send data via our unified tracking system
|
|
15
26
|
* to the native sdk
|
|
16
27
|
* @param {Object} [options.config] Configuration for facebook pixel tracking
|
|
17
|
-
*/
|
|
28
|
+
*/
|
|
29
|
+
constructor(options) {
|
|
30
|
+
this.options = options;
|
|
31
|
+
this.merchantAccounts = options.config.merchant;
|
|
32
|
+
this.shopgateAccount = options.config.shopgate;
|
|
33
|
+
this.universalCleanCodesCache = {};
|
|
34
|
+
|
|
35
|
+
/**
|
|
18
36
|
* List of functions that can be used to filter data
|
|
19
37
|
* @type {Object}
|
|
20
|
-
*/
|
|
38
|
+
*/
|
|
39
|
+
this.filters = {
|
|
40
|
+
'ecommerce:addTransaction': data => ({
|
|
41
|
+
revenue: data.amountCompleteFloat,
|
|
42
|
+
tax: data.amountTaxCompleteFloat,
|
|
43
|
+
shipping: data.amountShippingFloat,
|
|
44
|
+
currency: data.currency,
|
|
45
|
+
id: data.orderNumber,
|
|
46
|
+
affiliation: data.shopName
|
|
47
|
+
}),
|
|
48
|
+
'ecommerce:addItem': data => ({
|
|
49
|
+
id: data.orderNumber,
|
|
50
|
+
name: data.name,
|
|
51
|
+
price: data.unitAmount,
|
|
52
|
+
quantity: data.quantity,
|
|
53
|
+
sku: data.productNumber
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
this.initPlugin();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
21
60
|
* Initiate and setup the SDK
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
61
|
+
*/
|
|
62
|
+
initPlugin() {
|
|
63
|
+
// Load the SDK (if the code is executed form a unit test, always load the sdk)
|
|
64
|
+
if (typeof window.ga !== 'function' || typeof global !== 'undefined' && typeof global.it === 'function') {
|
|
65
|
+
/* eslint-disable eslint-comments/no-unlimited-disable */
|
|
66
|
+
/* eslint-disable */
|
|
67
|
+
(function (i, s, o, g, r, a, m) {
|
|
68
|
+
i['GoogleAnalyticsObject'] = r;
|
|
69
|
+
i[r] = i[r] || function () {
|
|
70
|
+
(i[r].q = i[r].q || []).push(arguments);
|
|
71
|
+
}, i[r].l = 1 * new Date();
|
|
72
|
+
a = s.createElement(o), m = s.getElementsByTagName(o)[0];
|
|
73
|
+
a.async = 1;
|
|
74
|
+
a.src = g;
|
|
75
|
+
m.parentNode.insertBefore(a, m);
|
|
76
|
+
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
|
|
77
|
+
/* eslint-enable */
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Setup merchant accounts
|
|
81
|
+
this.merchantAccounts.forEach(account => {
|
|
82
|
+
ga('create', {
|
|
83
|
+
trackingId: account.id,
|
|
84
|
+
cookieDomain: 'auto',
|
|
85
|
+
name: this.buildMerchantPrefix(account.id),
|
|
86
|
+
allowLinker: true
|
|
87
|
+
});
|
|
88
|
+
ga(`${this.buildMerchantPrefix(account.id)}.set`, 'anonymizeIp', true);
|
|
89
|
+
ga(`${this.buildMerchantPrefix(account.id)}.set`, 'forceSSL', true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Setup shopgate account
|
|
93
|
+
ga('create', {
|
|
94
|
+
trackingId: this.shopgateAccount.id,
|
|
95
|
+
cookieDomain: 'auto',
|
|
96
|
+
name: 'shopgate',
|
|
97
|
+
allowLinker: true
|
|
98
|
+
});
|
|
99
|
+
ga('shopgate.set', 'anonymizeIp', true);
|
|
100
|
+
ga('shopgate.set', 'forceSSL', true);
|
|
101
|
+
|
|
102
|
+
// Send custom variables to sdk
|
|
103
|
+
ga('shopgate.set', DIMENSION_SHOP_NUMBER, this.options.shopNumber || window.sgData.shop.shop_number.toString());
|
|
104
|
+
if (this.options.codebaseVersion || window.sgData.device.access === ACCESS_TYPE_APP) {
|
|
105
|
+
ga('shopgate.set', DIMENSION_CODEBASE_VERSION, this.options.codebaseVersion || window.sgData.device.codebase);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
27
110
|
* Removes '-' characters from tracker ID.
|
|
28
111
|
* This, sanitized string is then used as an
|
|
29
112
|
* identifier for universal tracker functions.
|
|
30
113
|
*
|
|
31
114
|
* @param {string} code Google Analytics Property ID
|
|
32
115
|
* @returns {string} sanitized merchantCode
|
|
33
|
-
*/
|
|
116
|
+
*/
|
|
117
|
+
getCleanUniversalMerchantCode(code) {
|
|
118
|
+
if (!this.universalCleanCodesCache.hasOwnProperty(code)) {
|
|
119
|
+
this.universalCleanCodesCache[code] = code.replace(/-/g, '');
|
|
120
|
+
}
|
|
121
|
+
return this.universalCleanCodesCache[code];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
34
125
|
* Helper to generate the prefix for an account
|
|
35
126
|
*
|
|
36
127
|
* @param {string} id Id of the account
|
|
37
128
|
* @returns {string} Prefix for the account
|
|
38
|
-
*/
|
|
129
|
+
*/
|
|
130
|
+
buildMerchantPrefix(id) {
|
|
131
|
+
return `merchant_${this.getCleanUniversalMerchantCode(id)}`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
39
135
|
* Function that sends the given command with the payload to the GA SDK
|
|
40
136
|
* @param {string} command Name of the command
|
|
41
137
|
* @param {Object|Array|string|Function} payload Data for the command,
|
|
42
138
|
* or a function that returns data
|
|
43
139
|
* @param {Object} [scope={}] Info if the event is for merchant and/or shopgate account
|
|
44
|
-
*/
|
|
45
|
-
|
|
46
|
-
|
|
140
|
+
*/
|
|
141
|
+
send(command, payload, scope = {}) {
|
|
142
|
+
const defaults = {
|
|
143
|
+
merchant: true,
|
|
144
|
+
shopgate: true
|
|
145
|
+
};
|
|
146
|
+
const useSendCmd = command !== 'require' && command !== 'set' && command.indexOf(':') === -1;
|
|
147
|
+
const mergedScope = {
|
|
148
|
+
...defaults,
|
|
149
|
+
...scope
|
|
150
|
+
};
|
|
151
|
+
if (mergedScope.merchant) {
|
|
152
|
+
this.merchantAccounts.forEach(account => {
|
|
153
|
+
let data = typeof payload === 'function' ? payload(account) : payload;
|
|
154
|
+
data = typeof this.filters[command] !== 'undefined' ? this.filters[command](data) : data;
|
|
155
|
+
const merchantPrefix = this.buildMerchantPrefix(account.id);
|
|
156
|
+
const cmd = [command];
|
|
157
|
+
if (useSendCmd) {
|
|
158
|
+
cmd.unshift(`${merchantPrefix}.send`);
|
|
159
|
+
} else {
|
|
160
|
+
// We don't need the send command for example for ecommerce:addTransaction
|
|
161
|
+
cmd[0] = `${merchantPrefix}.${cmd[0]}`;
|
|
162
|
+
}
|
|
163
|
+
if (typeof data === 'undefined') {
|
|
164
|
+
ga(...cmd.slice());
|
|
165
|
+
} else if (Array.isArray(data)) {
|
|
166
|
+
ga(...cmd.slice(), ...data);
|
|
167
|
+
} else {
|
|
168
|
+
ga(...cmd.slice(), data);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (mergedScope.shopgate) {
|
|
173
|
+
let data = typeof payload === 'function' ? payload(this.shopgateAccount) : payload;
|
|
174
|
+
data = typeof this.filters[command] !== 'undefined' ? this.filters[command](data) : data;
|
|
175
|
+
const cmd = [command];
|
|
176
|
+
if (useSendCmd) {
|
|
177
|
+
cmd.unshift('shopgate.send');
|
|
178
|
+
} else {
|
|
179
|
+
// We don't need the send command for example for ecommerce:addTransaction
|
|
180
|
+
cmd[0] = `shopgate.${cmd[0]}`;
|
|
181
|
+
}
|
|
182
|
+
if (typeof data === 'undefined') {
|
|
183
|
+
ga(...cmd.slice());
|
|
184
|
+
} else if (Array.isArray(data)) {
|
|
185
|
+
ga(...cmd.slice(), ...data);
|
|
186
|
+
} else {
|
|
187
|
+
ga(...cmd.slice(), data);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export default GaUniversal;
|