@times-components/ts-components 1.140.5 → 1.141.0
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/CHANGELOG.md +11 -0
- package/dist/helpers/algolia/__tests__/AlgoliaSearchProvider.test.d.ts +1 -0
- package/dist/helpers/algolia/__tests__/AlgoliaSearchProvider.test.js +200 -0
- package/dist/helpers/algolia/__tests__/conversionEvent.test.d.ts +1 -0
- package/dist/helpers/algolia/__tests__/conversionEvent.test.js +388 -0
- package/dist/helpers/algolia/conversionEvent.d.ts +29 -0
- package/dist/helpers/algolia/conversionEvent.js +154 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/package.json +14 -13
- package/rnw.js +1 -1
- package/src/helpers/algolia/__tests__/AlgoliaSearchProvider.test.tsx +367 -0
- package/src/helpers/algolia/__tests__/conversionEvent.test.ts +519 -0
- package/src/helpers/algolia/conversionEvent.ts +206 -0
- package/src/index.ts +5 -0
- package/tslint.json +1 -1
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
const mockAa = jest.fn();
|
|
2
|
+
jest.mock('search-insights', () => mockAa);
|
|
3
|
+
global.aa = mockAa;
|
|
4
|
+
import { sanitizeEventName, sendAlgoliaConversionEvent, trackAlgoliaConversionWithDwellTime, getValidConversionData } from '../conversionEvent';
|
|
5
|
+
const mockLocalStorage = {
|
|
6
|
+
getItem: jest.fn(),
|
|
7
|
+
setItem: jest.fn(),
|
|
8
|
+
removeItem: jest.fn(),
|
|
9
|
+
clear: jest.fn()
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(window, 'localStorage', {
|
|
12
|
+
value: mockLocalStorage,
|
|
13
|
+
writable: true
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(document, 'hidden', {
|
|
16
|
+
value: false,
|
|
17
|
+
writable: true
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(document, 'addEventListener', {
|
|
20
|
+
value: jest.fn(),
|
|
21
|
+
writable: true
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(window, 'addEventListener', {
|
|
24
|
+
value: jest.fn(),
|
|
25
|
+
writable: true
|
|
26
|
+
});
|
|
27
|
+
// Mock window.location.pathname
|
|
28
|
+
Object.defineProperty(window, 'location', {
|
|
29
|
+
value: {
|
|
30
|
+
pathname: '/current-article-path'
|
|
31
|
+
},
|
|
32
|
+
writable: true
|
|
33
|
+
});
|
|
34
|
+
describe('Algolia Conversion Event Helpers', () => {
|
|
35
|
+
const validConversionData = {
|
|
36
|
+
eventName: 'Test Event',
|
|
37
|
+
queryID: 'test-query-456',
|
|
38
|
+
objectID: 'test-object-123',
|
|
39
|
+
indexName: 'test-index',
|
|
40
|
+
applicationId: 'test-app-id',
|
|
41
|
+
apiKey: 'test-api-key',
|
|
42
|
+
timestamp: 1000000000000,
|
|
43
|
+
articleUrl: '/current-article-path'
|
|
44
|
+
};
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
jest.clearAllMocks();
|
|
47
|
+
mockLocalStorage.getItem.mockClear();
|
|
48
|
+
mockLocalStorage.setItem.mockClear();
|
|
49
|
+
mockLocalStorage.removeItem.mockClear();
|
|
50
|
+
mockAa.mockClear();
|
|
51
|
+
document.addEventListener.mockClear();
|
|
52
|
+
window.addEventListener.mockClear();
|
|
53
|
+
});
|
|
54
|
+
describe('sanitizeEventName', () => {
|
|
55
|
+
it('should return the original string if it contains only visible ASCII characters and is under 64 characters', () => {
|
|
56
|
+
const input = 'Valid Event Name 123!@#$%^&*()';
|
|
57
|
+
const result = sanitizeEventName(input);
|
|
58
|
+
expect(result).toBe(input);
|
|
59
|
+
});
|
|
60
|
+
it('should remove non-visible ASCII characters', () => {
|
|
61
|
+
const input = 'Event\u0000Name\u001F\u007F\u0080';
|
|
62
|
+
const result = sanitizeEventName(input);
|
|
63
|
+
expect(result).toBe('EventName');
|
|
64
|
+
});
|
|
65
|
+
it('should truncate strings longer than 64 characters and add ellipsis', () => {
|
|
66
|
+
const input = 'A'.repeat(70);
|
|
67
|
+
const result = sanitizeEventName(input);
|
|
68
|
+
expect(result).toBe('A'.repeat(60) + '...');
|
|
69
|
+
expect(result.length).toBe(63);
|
|
70
|
+
});
|
|
71
|
+
it('should handle exactly 64 characters without truncation', () => {
|
|
72
|
+
const input = 'A'.repeat(64);
|
|
73
|
+
const result = sanitizeEventName(input);
|
|
74
|
+
expect(result).toBe(input);
|
|
75
|
+
expect(result.length).toBe(64);
|
|
76
|
+
});
|
|
77
|
+
it('should handle empty string', () => {
|
|
78
|
+
const result = sanitizeEventName('');
|
|
79
|
+
expect(result).toBe('');
|
|
80
|
+
});
|
|
81
|
+
it('should handle string with only non-visible characters', () => {
|
|
82
|
+
const input = '\u0000\u001F\u007F';
|
|
83
|
+
const result = sanitizeEventName(input);
|
|
84
|
+
expect(result).toBe('');
|
|
85
|
+
});
|
|
86
|
+
it('should handle mixed visible and non-visible characters that exceed 64 chars after cleaning', () => {
|
|
87
|
+
const input = 'Valid'.repeat(15) + '\u0000\u001F';
|
|
88
|
+
const result = sanitizeEventName(input);
|
|
89
|
+
expect(result).toBe('Valid'.repeat(12) + '...');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
describe('sendAlgoliaConversionEvent', () => {
|
|
93
|
+
it('should call aa with correct parameters when all required fields are provided', () => {
|
|
94
|
+
const params = {
|
|
95
|
+
eventName: 'Test Event',
|
|
96
|
+
objectID: 'test-object-123',
|
|
97
|
+
queryID: 'test-query-456',
|
|
98
|
+
indexName: 'test-index'
|
|
99
|
+
};
|
|
100
|
+
sendAlgoliaConversionEvent(params);
|
|
101
|
+
expect(mockAa).toHaveBeenCalledWith('convertedObjectIDsAfterSearch', {
|
|
102
|
+
eventName: 'Test Event',
|
|
103
|
+
index: 'test-index',
|
|
104
|
+
queryID: 'test-query-456',
|
|
105
|
+
objectIDs: ['test-object-123']
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
it('should sanitize event name before sending', () => {
|
|
109
|
+
const params = {
|
|
110
|
+
eventName: 'Test\u0000Event\u001F',
|
|
111
|
+
objectID: 'test-object-123',
|
|
112
|
+
queryID: 'test-query-456',
|
|
113
|
+
indexName: 'test-index'
|
|
114
|
+
};
|
|
115
|
+
sendAlgoliaConversionEvent(params);
|
|
116
|
+
expect(mockAa).toHaveBeenCalledWith('convertedObjectIDsAfterSearch', {
|
|
117
|
+
eventName: 'TestEvent',
|
|
118
|
+
index: 'test-index',
|
|
119
|
+
queryID: 'test-query-456',
|
|
120
|
+
objectIDs: ['test-object-123']
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
it('should not call aa when indexName is missing', () => {
|
|
124
|
+
const params = {
|
|
125
|
+
eventName: 'Test Event',
|
|
126
|
+
objectID: 'test-object-123',
|
|
127
|
+
queryID: 'test-query-456',
|
|
128
|
+
indexName: ''
|
|
129
|
+
};
|
|
130
|
+
sendAlgoliaConversionEvent(params);
|
|
131
|
+
expect(mockAa).not.toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
it('should not call aa when queryID is missing', () => {
|
|
134
|
+
const params = {
|
|
135
|
+
eventName: 'Test Event',
|
|
136
|
+
objectID: 'test-object-123',
|
|
137
|
+
queryID: '',
|
|
138
|
+
indexName: 'test-index'
|
|
139
|
+
};
|
|
140
|
+
sendAlgoliaConversionEvent(params);
|
|
141
|
+
expect(mockAa).not.toHaveBeenCalled();
|
|
142
|
+
});
|
|
143
|
+
it('should not call aa when objectID is missing', () => {
|
|
144
|
+
const params = {
|
|
145
|
+
eventName: 'Test Event',
|
|
146
|
+
objectID: '',
|
|
147
|
+
queryID: 'test-query-456',
|
|
148
|
+
indexName: 'test-index'
|
|
149
|
+
};
|
|
150
|
+
sendAlgoliaConversionEvent(params);
|
|
151
|
+
expect(mockAa).not.toHaveBeenCalled();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe('getValidConversionData', () => {
|
|
155
|
+
it('should return null when no data is found in localStorage', () => {
|
|
156
|
+
mockLocalStorage.getItem.mockReturnValue(null);
|
|
157
|
+
const result = getValidConversionData();
|
|
158
|
+
expect(result).toBeNull();
|
|
159
|
+
expect(mockLocalStorage.getItem).toHaveBeenCalledWith('algoliaConversions');
|
|
160
|
+
});
|
|
161
|
+
it('should return null when stored data is invalid JSON', () => {
|
|
162
|
+
mockLocalStorage.getItem.mockReturnValue('invalid-json');
|
|
163
|
+
const result = getValidConversionData();
|
|
164
|
+
expect(result).toBeNull();
|
|
165
|
+
});
|
|
166
|
+
it('should return null when no matching articleUrl is found', () => {
|
|
167
|
+
const stored = [
|
|
168
|
+
{ ...validConversionData, articleUrl: '/not-this-url' },
|
|
169
|
+
{ ...validConversionData, articleUrl: '/another-url' }
|
|
170
|
+
];
|
|
171
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(stored));
|
|
172
|
+
const result = getValidConversionData();
|
|
173
|
+
expect(result).toBeNull();
|
|
174
|
+
});
|
|
175
|
+
it('should return the matching conversion data for current articleUrl', () => {
|
|
176
|
+
const stored = [
|
|
177
|
+
{ ...validConversionData, articleUrl: '/not-this-url' },
|
|
178
|
+
validConversionData,
|
|
179
|
+
{ ...validConversionData, articleUrl: '/another-url' }
|
|
180
|
+
];
|
|
181
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(stored));
|
|
182
|
+
const result = getValidConversionData();
|
|
183
|
+
expect(result).toEqual(validConversionData);
|
|
184
|
+
});
|
|
185
|
+
it('should return null if stored value is not an array', () => {
|
|
186
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(validConversionData));
|
|
187
|
+
const result = getValidConversionData();
|
|
188
|
+
expect(result).toBeNull();
|
|
189
|
+
});
|
|
190
|
+
it('should return null if array contains invalid objects', () => {
|
|
191
|
+
const stored = [
|
|
192
|
+
{ foo: 'bar' },
|
|
193
|
+
{ ...validConversionData, articleUrl: undefined }
|
|
194
|
+
];
|
|
195
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(stored));
|
|
196
|
+
const result = getValidConversionData();
|
|
197
|
+
expect(result).toBeNull();
|
|
198
|
+
});
|
|
199
|
+
it('should return null when conversion data is missing articleUrl', () => {
|
|
200
|
+
const fixedTime = 1000000000000;
|
|
201
|
+
jest.spyOn(Date, 'now').mockReturnValue(fixedTime);
|
|
202
|
+
const dataWithoutUrl = {
|
|
203
|
+
eventName: 'Test Event',
|
|
204
|
+
queryID: 'test-query-456',
|
|
205
|
+
objectID: 'test-object-123',
|
|
206
|
+
indexName: 'test-index',
|
|
207
|
+
applicationId: 'test-app-id',
|
|
208
|
+
apiKey: 'test-api-key',
|
|
209
|
+
timestamp: 1000000000000
|
|
210
|
+
// Missing articleUrl
|
|
211
|
+
};
|
|
212
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(dataWithoutUrl));
|
|
213
|
+
const result = getValidConversionData();
|
|
214
|
+
expect(result).toBeNull();
|
|
215
|
+
jest.restoreAllMocks();
|
|
216
|
+
});
|
|
217
|
+
it('should return null and remove data when articleUrl does not match current URL', () => {
|
|
218
|
+
const fixedTime = 1000000000000;
|
|
219
|
+
jest.spyOn(Date, 'now').mockReturnValue(fixedTime);
|
|
220
|
+
const dataWithDifferentUrl = {
|
|
221
|
+
...validConversionData,
|
|
222
|
+
articleUrl: '/different-article-path'
|
|
223
|
+
};
|
|
224
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(dataWithDifferentUrl));
|
|
225
|
+
const result = getValidConversionData();
|
|
226
|
+
expect(result).toBeNull();
|
|
227
|
+
jest.restoreAllMocks();
|
|
228
|
+
});
|
|
229
|
+
it('should return valid data when articleUrl matches current URL', () => {
|
|
230
|
+
const fixedTime = 1000000000000;
|
|
231
|
+
jest.spyOn(Date, 'now').mockReturnValue(fixedTime);
|
|
232
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(validConversionData));
|
|
233
|
+
const result = getValidConversionData();
|
|
234
|
+
expect(result).toBeNull();
|
|
235
|
+
});
|
|
236
|
+
it('should return null if array contains invalid objects', () => {
|
|
237
|
+
const stored = [
|
|
238
|
+
{ foo: 'bar' },
|
|
239
|
+
{ ...validConversionData, articleUrl: undefined }
|
|
240
|
+
];
|
|
241
|
+
mockLocalStorage.getItem.mockReturnValue(JSON.stringify(stored));
|
|
242
|
+
const result = getValidConversionData();
|
|
243
|
+
expect(result).toBeNull();
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
describe('trackAlgoliaConversionWithDwellTime', () => {
|
|
247
|
+
beforeEach(() => {
|
|
248
|
+
jest.useFakeTimers();
|
|
249
|
+
jest.spyOn(Date, 'now').mockReturnValue(1000000000000);
|
|
250
|
+
mockAa.mockClear();
|
|
251
|
+
document.addEventListener.mockClear();
|
|
252
|
+
window.addEventListener.mockClear();
|
|
253
|
+
});
|
|
254
|
+
afterEach(() => {
|
|
255
|
+
jest.useRealTimers();
|
|
256
|
+
jest.restoreAllMocks();
|
|
257
|
+
});
|
|
258
|
+
it('should initialize search-insights with provided data', () => {
|
|
259
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
260
|
+
expect(mockAa).toHaveBeenCalledWith('init', {
|
|
261
|
+
appId: 'test-app-id',
|
|
262
|
+
apiKey: 'test-api-key'
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
it('should return early if search-insights initialization fails', () => {
|
|
266
|
+
mockAa.mockImplementationOnce((method) => {
|
|
267
|
+
if (method === 'init') {
|
|
268
|
+
throw new Error('Init failed');
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
272
|
+
expect(mockAa).toHaveBeenCalledWith('init', expect.anything());
|
|
273
|
+
expect(document.addEventListener).not.toHaveBeenCalled();
|
|
274
|
+
});
|
|
275
|
+
it('should set up dwell time tracking with valid data', () => {
|
|
276
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
277
|
+
expect(mockAa).toHaveBeenCalledWith('init', expect.anything());
|
|
278
|
+
expect(document.addEventListener).toHaveBeenCalledWith('visibilitychange', expect.any(Function));
|
|
279
|
+
expect(window.addEventListener).toHaveBeenCalledWith('beforeunload', expect.any(Function));
|
|
280
|
+
});
|
|
281
|
+
it('should track conversion after 8 seconds of dwell time', () => {
|
|
282
|
+
let currentTime = 1000000000000;
|
|
283
|
+
Date.now.mockImplementation(() => currentTime);
|
|
284
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
285
|
+
expect(mockAa).toHaveBeenCalledWith('init', {
|
|
286
|
+
appId: 'test-app-id',
|
|
287
|
+
apiKey: 'test-api-key'
|
|
288
|
+
});
|
|
289
|
+
for (let i = 0; i < 8; i++) {
|
|
290
|
+
currentTime += 1000;
|
|
291
|
+
Date.now.mockReturnValue(currentTime);
|
|
292
|
+
jest.advanceTimersByTime(1000);
|
|
293
|
+
}
|
|
294
|
+
expect(mockAa).toHaveBeenCalledWith('convertedObjectIDsAfterSearch', {
|
|
295
|
+
eventName: 'Test Event',
|
|
296
|
+
index: 'test-index',
|
|
297
|
+
queryID: 'test-query-456',
|
|
298
|
+
objectIDs: ['test-object-123']
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
it('should not track conversion before 8 seconds', () => {
|
|
302
|
+
let currentTime = 1000000000000;
|
|
303
|
+
Date.now.mockImplementation(() => currentTime);
|
|
304
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
305
|
+
for (let i = 0; i < 7; i++) {
|
|
306
|
+
currentTime += 1000;
|
|
307
|
+
Date.now.mockReturnValue(currentTime);
|
|
308
|
+
jest.advanceTimersByTime(1000);
|
|
309
|
+
}
|
|
310
|
+
expect(mockAa).not.toHaveBeenCalledWith('convertedObjectIDsAfterSearch', expect.anything());
|
|
311
|
+
});
|
|
312
|
+
it('should set up proper event listeners for tracking', () => {
|
|
313
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
314
|
+
expect(document.addEventListener).toHaveBeenCalledWith('visibilitychange', expect.any(Function));
|
|
315
|
+
expect(window.addEventListener).toHaveBeenCalledWith('beforeunload', expect.any(Function));
|
|
316
|
+
});
|
|
317
|
+
it('should pause and resume dwell time tracking on visibility changes', () => {
|
|
318
|
+
let currentTime = 1000000000000;
|
|
319
|
+
Date.now.mockImplementation(() => currentTime);
|
|
320
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
321
|
+
const visibilityChangeCallback = document.addEventListener.mock.calls.find(call => call[0] === 'visibilitychange')[1];
|
|
322
|
+
// Simulate 4 seconds of visible time
|
|
323
|
+
for (let i = 0; i < 4; i++) {
|
|
324
|
+
currentTime += 1000;
|
|
325
|
+
Date.now.mockReturnValue(currentTime);
|
|
326
|
+
jest.advanceTimersByTime(1000);
|
|
327
|
+
}
|
|
328
|
+
// Hide the page
|
|
329
|
+
Object.defineProperty(document, 'hidden', {
|
|
330
|
+
value: true,
|
|
331
|
+
writable: true
|
|
332
|
+
});
|
|
333
|
+
visibilityChangeCallback();
|
|
334
|
+
// Advance time while hidden (shouldn't count toward dwell time)
|
|
335
|
+
for (let i = 0; i < 6; i++) {
|
|
336
|
+
currentTime += 1000;
|
|
337
|
+
Date.now.mockReturnValue(currentTime);
|
|
338
|
+
jest.advanceTimersByTime(1000);
|
|
339
|
+
}
|
|
340
|
+
// Show the page again
|
|
341
|
+
Object.defineProperty(document, 'hidden', {
|
|
342
|
+
value: false,
|
|
343
|
+
writable: true
|
|
344
|
+
});
|
|
345
|
+
visibilityChangeCallback();
|
|
346
|
+
// Advance 4 more seconds (total visible time: 8 seconds)
|
|
347
|
+
for (let i = 0; i < 4; i++) {
|
|
348
|
+
currentTime += 1000;
|
|
349
|
+
Date.now.mockReturnValue(currentTime);
|
|
350
|
+
jest.advanceTimersByTime(1000);
|
|
351
|
+
}
|
|
352
|
+
expect(mockAa).toHaveBeenCalledWith('convertedObjectIDsAfterSearch', {
|
|
353
|
+
eventName: 'Test Event',
|
|
354
|
+
index: 'test-index',
|
|
355
|
+
queryID: 'test-query-456',
|
|
356
|
+
objectIDs: ['test-object-123']
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
it('should clean up timer when conversion is tracked', () => {
|
|
360
|
+
let currentTime = 1000000000000;
|
|
361
|
+
Date.now.mockImplementation(() => currentTime);
|
|
362
|
+
const clearIntervalSpy = jest.spyOn(global, 'clearInterval');
|
|
363
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
364
|
+
for (let i = 0; i < 8; i++) {
|
|
365
|
+
currentTime += 1000;
|
|
366
|
+
Date.now.mockReturnValue(currentTime);
|
|
367
|
+
jest.advanceTimersByTime(1000);
|
|
368
|
+
}
|
|
369
|
+
expect(clearIntervalSpy).toHaveBeenCalled();
|
|
370
|
+
clearIntervalSpy.mockRestore();
|
|
371
|
+
});
|
|
372
|
+
it('should handle beforeunload without tracking if dwell time not reached', () => {
|
|
373
|
+
let currentTime = 1000000000000;
|
|
374
|
+
Date.now.mockImplementation(() => currentTime);
|
|
375
|
+
trackAlgoliaConversionWithDwellTime(validConversionData);
|
|
376
|
+
const beforeunloadCallback = window.addEventListener.mock.calls.find(call => call[0] === 'beforeunload')[1];
|
|
377
|
+
// Only 5 seconds of dwell time
|
|
378
|
+
for (let i = 0; i < 5; i++) {
|
|
379
|
+
currentTime += 1000;
|
|
380
|
+
Date.now.mockReturnValue(currentTime);
|
|
381
|
+
jest.advanceTimersByTime(1000);
|
|
382
|
+
}
|
|
383
|
+
beforeunloadCallback();
|
|
384
|
+
expect(mockAa).not.toHaveBeenCalledWith('convertedObjectIDsAfterSearch', expect.anything());
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVyc2lvbkV2ZW50LnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvaGVscGVycy9hbGdvbGlhL19fdGVzdHNfXy9jb252ZXJzaW9uRXZlbnQudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7QUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUUxQyxNQUFjLENBQUMsRUFBRSxHQUFHLE1BQU0sQ0FBQztBQUU1QixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLDBCQUEwQixFQUMxQixtQ0FBbUMsRUFDbkMsc0JBQXNCLEVBQ3ZCLE1BQU0sb0JBQW9CLENBQUM7QUFFNUIsTUFBTSxnQkFBZ0IsR0FBRztJQUN2QixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtJQUNsQixPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtJQUNsQixVQUFVLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtJQUNyQixLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtDQUNqQixDQUFDO0FBRUYsTUFBTSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsY0FBYyxFQUFFO0lBQzVDLEtBQUssRUFBRSxnQkFBZ0I7SUFDdkIsUUFBUSxFQUFFLElBQUk7Q0FDZixDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUU7SUFDeEMsS0FBSyxFQUFFLEtBQUs7SUFDWixRQUFRLEVBQUUsSUFBSTtDQUNmLENBQUMsQ0FBQztBQUVILE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLGtCQUFrQixFQUFFO0lBQ2xELEtBQUssRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO0lBQ2hCLFFBQVEsRUFBRSxJQUFJO0NBQ2YsQ0FBQyxDQUFD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
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const sanitizeEventName: (name: string) => string;
|
|
2
|
+
interface AlgoliaConversionData {
|
|
3
|
+
queryID: string;
|
|
4
|
+
objectID: string;
|
|
5
|
+
indexName: string;
|
|
6
|
+
applicationId: string;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
eventName: string;
|
|
10
|
+
articleUrl: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const sendAlgoliaConversionEvent: ({ eventName, objectID, queryID, indexName }: {
|
|
13
|
+
eventName: string;
|
|
14
|
+
objectID: string;
|
|
15
|
+
queryID: string;
|
|
16
|
+
indexName: string;
|
|
17
|
+
}) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves and validates Algolia conversion data from localStorage
|
|
20
|
+
* Supports multiple articles stored as an array
|
|
21
|
+
* @returns AlgoliaConversionData if valid for current URL, null otherwise
|
|
22
|
+
*/
|
|
23
|
+
export declare const getValidConversionData: () => AlgoliaConversionData | null;
|
|
24
|
+
/**
|
|
25
|
+
* Tracks Algolia conversion after user spends 8 seconds on an article page
|
|
26
|
+
* Assumes conversionData has already been validated by the caller
|
|
27
|
+
*/
|
|
28
|
+
export declare const trackAlgoliaConversionWithDwellTime: (conversionData: AlgoliaConversionData) => void;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import aa from 'search-insights';
|
|
2
|
+
export const sanitizeEventName = (name) => {
|
|
3
|
+
const visibleAsciiOnly = name.replace(/[^\x20-\x7E]/g, '');
|
|
4
|
+
if (visibleAsciiOnly.length > 64) {
|
|
5
|
+
return visibleAsciiOnly.substring(0, 60) + '...';
|
|
6
|
+
}
|
|
7
|
+
return visibleAsciiOnly;
|
|
8
|
+
};
|
|
9
|
+
export const sendAlgoliaConversionEvent = ({ eventName, objectID, queryID, indexName }) => {
|
|
10
|
+
const truncatedEventName = sanitizeEventName(eventName);
|
|
11
|
+
if (!indexName || !queryID || !objectID) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
aa('convertedObjectIDsAfterSearch', {
|
|
15
|
+
eventName: truncatedEventName,
|
|
16
|
+
index: indexName,
|
|
17
|
+
queryID,
|
|
18
|
+
objectIDs: [objectID]
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves and validates Algolia conversion data from localStorage
|
|
23
|
+
* Supports multiple articles stored as an array
|
|
24
|
+
* @returns AlgoliaConversionData if valid for current URL, null otherwise
|
|
25
|
+
*/
|
|
26
|
+
export const getValidConversionData = () => {
|
|
27
|
+
try {
|
|
28
|
+
const currentUrl = window.location.pathname;
|
|
29
|
+
const storedArrayData = localStorage.getItem('algoliaConversions');
|
|
30
|
+
if (storedArrayData) {
|
|
31
|
+
const conversionsArray = JSON.parse(storedArrayData);
|
|
32
|
+
if (Array.isArray(conversionsArray)) {
|
|
33
|
+
const matchingConversion = conversionsArray.find(conversion => conversion.articleUrl === currentUrl);
|
|
34
|
+
if (matchingConversion && isValidConversionData(matchingConversion)) {
|
|
35
|
+
return matchingConversion;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const isValidConversionData = (conversionData) => {
|
|
46
|
+
return (conversionData &&
|
|
47
|
+
conversionData.eventName &&
|
|
48
|
+
conversionData.queryID &&
|
|
49
|
+
conversionData.objectID &&
|
|
50
|
+
conversionData.indexName &&
|
|
51
|
+
conversionData.applicationId &&
|
|
52
|
+
conversionData.apiKey &&
|
|
53
|
+
conversionData.articleUrl);
|
|
54
|
+
};
|
|
55
|
+
const cleanupConversionData = (articleUrl) => {
|
|
56
|
+
const storedArrayData = localStorage.getItem('algoliaConversions');
|
|
57
|
+
if (storedArrayData) {
|
|
58
|
+
const conversionsArray = JSON.parse(storedArrayData);
|
|
59
|
+
if (Array.isArray(conversionsArray)) {
|
|
60
|
+
const filteredArray = conversionsArray.filter(conversion => conversion.articleUrl !== articleUrl);
|
|
61
|
+
if (filteredArray.length === 0) {
|
|
62
|
+
localStorage.removeItem('algoliaConversions');
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
localStorage.setItem('algoliaConversions', JSON.stringify(filteredArray));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Tracks Algolia conversion after user spends 8 seconds on an article page
|
|
72
|
+
* Assumes conversionData has already been validated by the caller
|
|
73
|
+
*/
|
|
74
|
+
export const trackAlgoliaConversionWithDwellTime = (conversionData) => {
|
|
75
|
+
try {
|
|
76
|
+
aa('init', {
|
|
77
|
+
appId: conversionData.applicationId,
|
|
78
|
+
apiKey: conversionData.apiKey
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
let tracked = false;
|
|
85
|
+
let dwellStartTime = Date.now();
|
|
86
|
+
let totalDwellTime = 0;
|
|
87
|
+
let isPageVisible = !document.hidden;
|
|
88
|
+
const trackConversion = () => {
|
|
89
|
+
if (tracked) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
sendAlgoliaConversionEvent({
|
|
93
|
+
eventName: conversionData.eventName,
|
|
94
|
+
indexName: conversionData.indexName,
|
|
95
|
+
queryID: conversionData.queryID,
|
|
96
|
+
objectID: conversionData.objectID
|
|
97
|
+
});
|
|
98
|
+
tracked = true;
|
|
99
|
+
cleanupConversionData(conversionData.articleUrl);
|
|
100
|
+
};
|
|
101
|
+
const updateDwellTime = () => {
|
|
102
|
+
if (isPageVisible) {
|
|
103
|
+
const currentTime = Date.now();
|
|
104
|
+
const sessionTime = currentTime - dwellStartTime;
|
|
105
|
+
totalDwellTime += sessionTime;
|
|
106
|
+
dwellStartTime = currentTime;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const checkDwellTime = () => {
|
|
110
|
+
updateDwellTime();
|
|
111
|
+
if (totalDwellTime >= 8000) {
|
|
112
|
+
trackConversion();
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
};
|
|
117
|
+
// Check dwell time every second
|
|
118
|
+
// --- Setup listeners and timer ---
|
|
119
|
+
const visibilityHandler = () => {
|
|
120
|
+
const now = Date.now();
|
|
121
|
+
if (document.hidden && isPageVisible) {
|
|
122
|
+
const sessionTime = now - dwellStartTime;
|
|
123
|
+
totalDwellTime += sessionTime;
|
|
124
|
+
isPageVisible = false;
|
|
125
|
+
}
|
|
126
|
+
else if (!document.hidden && !isPageVisible) {
|
|
127
|
+
dwellStartTime = now;
|
|
128
|
+
isPageVisible = true;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const beforeUnloadHandler = () => {
|
|
132
|
+
const conversionTracked = checkDwellTime();
|
|
133
|
+
if (!conversionTracked) {
|
|
134
|
+
cleanupConversionData(conversionData.articleUrl);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
document.addEventListener('visibilitychange', visibilityHandler);
|
|
138
|
+
window.addEventListener('beforeunload', beforeUnloadHandler);
|
|
139
|
+
const dwellTimer = setInterval(() => {
|
|
140
|
+
if (!tracked) {
|
|
141
|
+
if (checkDwellTime()) {
|
|
142
|
+
clearInterval(dwellTimer);
|
|
143
|
+
document.removeEventListener('visibilitychange', visibilityHandler);
|
|
144
|
+
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
clearInterval(dwellTimer);
|
|
149
|
+
document.removeEventListener('visibilitychange', visibilityHandler);
|
|
150
|
+
window.removeEventListener('beforeunload', beforeUnloadHandler);
|
|
151
|
+
}
|
|
152
|
+
}, 1000);
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVyc2lvbkV2ZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2hlbHBlcnMvYWxnb2xpYS9jb252ZXJzaW9uRXZlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakMsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxJQUFZLEVBQVUsRUFBRTtJQUN4RCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzNELElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLEVBQUUsRUFBRTtRQUNoQyxPQUFPLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDO0tBQ2xEO0lBQ0QsT0FBTyxnQkFBZ0IsQ0FBQztBQUMxQixDQUFDLENBQUM7QUFhRixNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxDQUFDLEVBQ3pDLFNBQVMsRUFDVCxRQUFRLEVBQ1IsT0FBTyxFQUNQLFNBQVMsRUFNVixFQUFRLEVBQUU7SUFDVCxNQUFNLGtCQUFrQixHQUFHLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRXhELElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxRQUFRLEVBQUU7UUFDdkMsT0FBTztLQUNSO0lBRUQsRUFBRSxDQUFDLCtCQUErQixFQUFFO1FBQ2xDLFNBQVMsRUFBRSxrQkFBa0I7UUFDN0IsS0FBSyxFQUFFLFNBQVM7UUFDaEIsT0FBTztRQUNQLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQztLQUN0QixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsR0FBaUMsRUFBRTtJQUN2RSxJQUFJO1FBQ0YsTUFBTSxVQUFVLEdBQUcsTUFBTSxD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
|
package/dist/index.d.ts
CHANGED
|
@@ -48,3 +48,4 @@ export { SocialMediaEmbed } from './components/social-embed/SocialMediaEmbed';
|
|
|
48
48
|
export { useSocialEmbedsContext, SocialEmbedsProvider } from './contexts/SocialEmbedsProvider';
|
|
49
49
|
export { AffiliateLinkDisclaimer } from './components/affiliate-link-disclaimer/AffiliateLinkDisclaimer';
|
|
50
50
|
export { ArticleCard } from './components/article-cards/ArticleCard';
|
|
51
|
+
export { trackAlgoliaConversionWithDwellTime, getValidConversionData } from './helpers/algolia/conversionEvent';
|
package/dist/index.js
CHANGED
|
@@ -55,4 +55,5 @@ export { SocialMediaEmbed } from './components/social-embed/SocialMediaEmbed';
|
|
|
55
55
|
export { useSocialEmbedsContext, SocialEmbedsProvider } from './contexts/SocialEmbedsProvider';
|
|
56
56
|
export { AffiliateLinkDisclaimer } from './components/affiliate-link-disclaimer/AffiliateLinkDisclaimer';
|
|
57
57
|
export { ArticleCard } from './components/article-cards/ArticleCard';
|
|
58
|
-
|
|
58
|
+
export { trackAlgoliaConversionWithDwellTime, getValidConversionData } from './helpers/algolia/conversionEvent';
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscUJBQXFCO0FBQ3JCLE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsZUFBZSxFQUNoQixNQUFNLDJDQUEyQyxDQUFDO0FBQ25ELE9BQU8sRUFFTCx1QkFBdUIsRUFDeEIsTUFBTSw0Q0FBNEMsQ0FBQztBQUNwRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDM0UsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUN4RSxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3JCLE1BQU0scUVBQXFFLENBQUM7QUFDN0UsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdEQUFnRCxDQUFDO0FBQzVFLE9BQU8sRUFDTCxXQUFXLEVBQ1gsWUFBWSxFQUNaLGNBQWMsRUFDZCxrQkFBa0IsRUFDbEIsb0JBQW9CLEVBQ3BCLG9CQUFvQixFQUNwQixtQkFBbUIsRUFDcEIsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDeEUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzNELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUNoRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMENBQTBDLENBQUM7QUFDeEUsT0FBTyxFQUNMLHFCQUFxQixFQUN0QixNQUFNLHFEQUFxRCxDQUFDO0FBQzdELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFFNUQsd0JBQXdCO0FBQ3hCLE9BQU8sRUFDTCxrQkFBa0IsRUFDbkIsTUFBTSxp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
|