@liquidcommercedev/rmn-sdk 1.5.0-beta.7 → 1.5.0-beta.9
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/dist/index.cjs +385 -293
- package/dist/index.esm.js +386 -294
- package/dist/types/common/helpers/utils.helper.d.ts +50 -0
- package/dist/types/enums.d.ts +4 -1
- package/dist/types/modules/event/event.interface.d.ts +6 -36
- package/dist/types/modules/event/event.service.d.ts +5 -23
- package/dist/types/modules/event/index.d.ts +0 -2
- package/dist/types/modules/{event/helpers → helper-service}/index.d.ts +1 -1
- package/dist/types/modules/{event/helpers → helper-service}/localstorage.service.d.ts +2 -2
- package/dist/types/modules/{event/pubsub.d.ts → helper-service/pubsub.service.d.ts} +4 -4
- package/dist/types/modules/monitor/index.d.ts +2 -0
- package/dist/types/modules/monitor/monitor.enums.d.ts +4 -0
- package/dist/types/modules/monitor/monitor.interface.d.ts +12 -0
- package/dist/types/modules/monitor/monitor.service.d.ts +12 -0
- package/dist/types/modules/{event/helpers → monitor/monitors}/datalayer.monitor.d.ts +1 -10
- package/dist/types/types.d.ts +4 -4
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
- package/dist/types/modules/element/component/utils.d.ts +0 -1
- package/dist/types/modules/event/helpers/utils.d.ts +0 -24
- package/dist/types/modules/event/user.monitor.d.ts +0 -14
- /package/dist/types/modules/{event/helpers → helper-service}/intersection.service.d.ts +0 -0
- /package/dist/types/modules/{event/helpers → helper-service}/resize.service.d.ts +0 -0
package/dist/index.cjs
CHANGED
@@ -55,9 +55,13 @@ exports.RMN_FILTER_PROPERTIES = void 0;
|
|
55
55
|
RMN_FILTER_PROPERTIES["PUBLISHERS"] = "publishers";
|
56
56
|
RMN_FILTER_PROPERTIES["SECTION"] = "section";
|
57
57
|
})(exports.RMN_FILTER_PROPERTIES || (exports.RMN_FILTER_PROPERTIES = {}));
|
58
|
+
exports.RMN_EVENT = void 0;
|
59
|
+
(function (RMN_EVENT) {
|
60
|
+
RMN_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
|
61
|
+
RMN_EVENT["SPOT_EVENT"] = "SPOT_EVENT";
|
62
|
+
})(exports.RMN_EVENT || (exports.RMN_EVENT = {}));
|
58
63
|
exports.RMN_SPOT_EVENT = void 0;
|
59
64
|
(function (RMN_SPOT_EVENT) {
|
60
|
-
RMN_SPOT_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
|
61
65
|
RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
|
62
66
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
63
67
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
@@ -15167,6 +15171,12 @@ const GFONT_CORMORANT = `
|
|
15167
15171
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,300..700;1,300..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap">
|
15168
15172
|
`;
|
15169
15173
|
|
15174
|
+
/**
|
15175
|
+
* Determines the event type from a raw event string.
|
15176
|
+
*
|
15177
|
+
* @param {string} [event] - The raw event string to evaluate.
|
15178
|
+
* @returns {RMN_SPOT_EVENT | null} - The corresponding RMN_SPOT_EVENT or null if no match is found.
|
15179
|
+
*/
|
15170
15180
|
function getEventTypeFromRawEvent(event) {
|
15171
15181
|
if (!event) {
|
15172
15182
|
return null;
|
@@ -15195,7 +15205,7 @@ function getEventTypeFromRawEvent(event) {
|
|
15195
15205
|
* Searches for specified property names and collects their primitive values (strings/numbers).
|
15196
15206
|
*
|
15197
15207
|
* @param data - The data structure to search through (can be nested objects/arrays)
|
15198
|
-
* @param propertyNames - Array of property names to look for
|
15208
|
+
* @param propertyNames - Array of property names to look for
|
15199
15209
|
* @returns Array of extracted ID values (strings/numbers only)
|
15200
15210
|
*
|
15201
15211
|
* @example
|
@@ -15206,10 +15216,27 @@ function getEventTypeFromRawEvent(event) {
|
|
15206
15216
|
* };
|
15207
15217
|
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
15208
15218
|
*/
|
15209
|
-
function extractDeepIds(data, propertyNames
|
15219
|
+
function extractDeepIds(data, propertyNames) {
|
15210
15220
|
const ids = [];
|
15221
|
+
const defaulPropertyNames = [
|
15222
|
+
'id',
|
15223
|
+
'upc',
|
15224
|
+
'groupingId',
|
15225
|
+
'sku',
|
15226
|
+
'productId',
|
15227
|
+
'item_id',
|
15228
|
+
'isbn',
|
15229
|
+
'asin',
|
15230
|
+
'mpn',
|
15231
|
+
'model_number',
|
15232
|
+
'article_number',
|
15233
|
+
'variant_id',
|
15234
|
+
'item_number',
|
15235
|
+
'catalog_id',
|
15236
|
+
'reference_id',
|
15237
|
+
];
|
15211
15238
|
// Set for faster property name lookups
|
15212
|
-
const propertySet = new Set(
|
15239
|
+
const propertySet = new Set(defaulPropertyNames);
|
15213
15240
|
/**
|
15214
15241
|
* Processes a value and extracts IDs if it matches criteria
|
15215
15242
|
* @param value - The value to process
|
@@ -15244,54 +15271,106 @@ function extractDeepIds(data, propertyNames = ['id', 'upc', 'groupingId', 'sku',
|
|
15244
15271
|
processValue(data);
|
15245
15272
|
return ids; // No need to filter nulls as we handle that during collection
|
15246
15273
|
}
|
15247
|
-
|
15248
|
-
|
15249
|
-
|
15250
|
-
|
15251
|
-
|
15252
|
-
|
15253
|
-
|
15274
|
+
// Fallback method using fetch if sendBeacon isn't available
|
15275
|
+
async function fallbackEventFire(url) {
|
15276
|
+
try {
|
15277
|
+
const racePromise = Promise.race([
|
15278
|
+
// Promise #1: The fetch request
|
15279
|
+
fetch(url, {
|
15280
|
+
method: 'POST',
|
15281
|
+
keepalive: true,
|
15282
|
+
}),
|
15283
|
+
// Promise #2: The timeout
|
15284
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 2000)),
|
15285
|
+
]);
|
15286
|
+
/**
|
15287
|
+
* Prevent requests from hanging indefinitely
|
15288
|
+
* Improve user experience by failing fast
|
15289
|
+
* Handle slow network conditions gracefully
|
15290
|
+
* Ensure resources are freed up in a timely manner
|
15291
|
+
*/
|
15292
|
+
const response = await racePromise;
|
15293
|
+
return response.ok;
|
15254
15294
|
}
|
15255
|
-
|
15256
|
-
|
15257
|
-
|
15295
|
+
catch (_a) {
|
15296
|
+
return false;
|
15297
|
+
}
|
15298
|
+
}
|
15299
|
+
/**
|
15300
|
+
* Extracts and decodes a URL from a base64-encoded query parameter.
|
15301
|
+
*
|
15302
|
+
* @param {string} url - The URL containing the base64-encoded query parameter.
|
15303
|
+
* @returns {string | null} - The decoded URL or null if not found or invalid.
|
15304
|
+
*/
|
15305
|
+
function getRedirectUrlFromPayload(url) {
|
15306
|
+
try {
|
15307
|
+
const base64String = new URL(url).searchParams.get('e');
|
15308
|
+
if (!base64String) {
|
15309
|
+
return null;
|
15258
15310
|
}
|
15259
|
-
|
15311
|
+
const data = JSON.parse(atob(base64String));
|
15312
|
+
return data.ur || null;
|
15260
15313
|
}
|
15261
|
-
|
15262
|
-
|
15314
|
+
catch (_a) {
|
15315
|
+
return null;
|
15263
15316
|
}
|
15264
|
-
|
15265
|
-
|
15266
|
-
|
15267
|
-
|
15268
|
-
|
15269
|
-
|
15270
|
-
|
15271
|
-
|
15272
|
-
|
15317
|
+
}
|
15318
|
+
/**
|
15319
|
+
* Fires an event using the navigator.sendBeacon method or a fallback method if sendBeacon is not available.
|
15320
|
+
* If the event is a click event and a redirect URL is found, it redirects the user to that URL.
|
15321
|
+
*
|
15322
|
+
* @param {IFireEventParams} params - The parameters for firing the event.
|
15323
|
+
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
15324
|
+
* @param {string} params.eventUrl - The URL to which the event is sent.
|
15325
|
+
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
15326
|
+
*/
|
15327
|
+
async function fireEvent({ event, eventUrl }) {
|
15328
|
+
var _a;
|
15329
|
+
try {
|
15330
|
+
const didFireEvent = ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === null || _a === void 0 ? void 0 : _a.call(navigator, eventUrl)) || (await fallbackEventFire(eventUrl));
|
15331
|
+
if (!didFireEvent) {
|
15332
|
+
return;
|
15333
|
+
}
|
15334
|
+
if (event === exports.RMN_SPOT_EVENT.CLICK) {
|
15335
|
+
const redirectUrl = getRedirectUrlFromPayload(eventUrl);
|
15336
|
+
if (redirectUrl) {
|
15337
|
+
window.location.href = redirectUrl;
|
15273
15338
|
}
|
15274
|
-
return result;
|
15275
|
-
};
|
15276
|
-
}
|
15277
|
-
cleanEventData(data) {
|
15278
|
-
const eventName = getEventTypeFromRawEvent(data.event);
|
15279
|
-
if (!eventName) {
|
15280
|
-
return null;
|
15281
15339
|
}
|
15282
|
-
const productIds = extractDeepIds(data.value);
|
15283
|
-
return {
|
15284
|
-
event: eventName,
|
15285
|
-
productIds,
|
15286
|
-
};
|
15287
15340
|
}
|
15288
|
-
|
15289
|
-
|
15290
|
-
window.dataLayer.push = this.originalPush;
|
15291
|
-
}
|
15292
|
-
this.listener = undefined;
|
15341
|
+
catch (_b) {
|
15342
|
+
// Handle errors silently
|
15293
15343
|
}
|
15294
15344
|
}
|
15345
|
+
function calculateScaleFactor(elementScale) {
|
15346
|
+
// Step 1: Apply square root for non-linear scaling
|
15347
|
+
// This creates a more gradual scaling effect, especially for larger changes
|
15348
|
+
// For example:
|
15349
|
+
// - elementScale of 0.25 (1/4 size) becomes 0.5
|
15350
|
+
// - elementScale of 1 (unchanged) remains 1
|
15351
|
+
// - elementScale of 4 (4x size) becomes 2
|
15352
|
+
const baseFactor = Math.sqrt(elementScale);
|
15353
|
+
// Step 2: Apply additional dampening to further soften the scaling effect
|
15354
|
+
// The dampening factor (0.5) can be adjusted:
|
15355
|
+
// - Lower values (closer to 0) make scaling more subtle
|
15356
|
+
// - Higher values (closer to 1) make scaling more pronounced
|
15357
|
+
const dampening = 0.35;
|
15358
|
+
// Calculate the scaleFactor:
|
15359
|
+
// 1. (baseFactor - 1) represents the change from the original size
|
15360
|
+
// 2. Multiply by dampening to reduce the effect
|
15361
|
+
// 3. Add 1 to center the scaling around the original size
|
15362
|
+
// For example, if baseFactor is 2:
|
15363
|
+
// scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
|
15364
|
+
const scaleFactor = 1 + (baseFactor - 1) * dampening;
|
15365
|
+
// Step 3: Define the allowed range for the scale factor
|
15366
|
+
// This ensures that the font size never changes too drastically
|
15367
|
+
const minScale = 0.35; // Font will never be smaller than 50% of original
|
15368
|
+
const maxScale = 1.5; // Font will never be larger than 150% of original
|
15369
|
+
// Step 4: Clamp the scale factor to the defined range
|
15370
|
+
// Math.min ensures the value doesn't exceed maxScale
|
15371
|
+
// Math.max ensures the value isn't less than minScale
|
15372
|
+
return Math.max(minScale, Math.min(maxScale, scaleFactor));
|
15373
|
+
}
|
15295
15374
|
|
15296
15375
|
class IntersectionObserverService {
|
15297
15376
|
constructor(defaultOptions = {}) {
|
@@ -15341,7 +15420,7 @@ var ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX;
|
|
15341
15420
|
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["PRODUCT_IDS"] = 3] = "PRODUCT_IDS";
|
15342
15421
|
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["CREATED_AT"] = 4] = "CREATED_AT";
|
15343
15422
|
})(ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX || (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX = {}));
|
15344
|
-
class
|
15423
|
+
class LocalStorageService {
|
15345
15424
|
constructor() {
|
15346
15425
|
if (typeof window.localStorage === 'undefined') {
|
15347
15426
|
console.warn('Local storage is not supported in this environment');
|
@@ -15354,13 +15433,13 @@ class LocalStorage {
|
|
15354
15433
|
this.removeExpiredSpots();
|
15355
15434
|
}
|
15356
15435
|
static getInstance() {
|
15357
|
-
if (!
|
15358
|
-
|
15436
|
+
if (!LocalStorageService.instance) {
|
15437
|
+
LocalStorageService.instance = new LocalStorageService();
|
15359
15438
|
}
|
15360
|
-
return
|
15439
|
+
return LocalStorageService.instance;
|
15361
15440
|
}
|
15362
15441
|
syncLocalStorage() {
|
15363
|
-
const localStorageData = window.localStorage.getItem(
|
15442
|
+
const localStorageData = window.localStorage.getItem(LocalStorageService.localStorageKey);
|
15364
15443
|
// TODO: Encrypt the data before storing it in the local storage
|
15365
15444
|
if (localStorageData) {
|
15366
15445
|
try {
|
@@ -15410,17 +15489,17 @@ class LocalStorage {
|
|
15410
15489
|
for (const [key, value] of Object.entries(data)) {
|
15411
15490
|
dataArray[key] = this.objectToArray(value);
|
15412
15491
|
}
|
15413
|
-
window.localStorage.setItem(
|
15492
|
+
window.localStorage.setItem(LocalStorageService.localStorageKey, JSON.stringify(dataArray));
|
15414
15493
|
}
|
15415
15494
|
clearLocalStorage() {
|
15416
|
-
window.localStorage.removeItem(
|
15495
|
+
window.localStorage.removeItem(LocalStorageService.localStorageKey);
|
15417
15496
|
}
|
15418
15497
|
removeExpiredSpots() {
|
15419
15498
|
var _a;
|
15420
15499
|
const currentTime = Date.now();
|
15421
15500
|
(_a = this.spots) === null || _a === void 0 ? void 0 : _a.forEach((spot, spotId) => {
|
15422
15501
|
var _a, _b;
|
15423
|
-
if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) >
|
15502
|
+
if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) > LocalStorageService.spotExpirationTime) {
|
15424
15503
|
(_b = this.spots) === null || _b === void 0 ? void 0 : _b.delete(spotId);
|
15425
15504
|
}
|
15426
15505
|
});
|
@@ -15445,8 +15524,89 @@ class LocalStorage {
|
|
15445
15524
|
};
|
15446
15525
|
}
|
15447
15526
|
}
|
15448
|
-
|
15449
|
-
|
15527
|
+
LocalStorageService.localStorageKey = 'lc_rmn';
|
15528
|
+
LocalStorageService.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
15529
|
+
|
15530
|
+
/**
|
15531
|
+
* PubsubService class
|
15532
|
+
* Manages event subscriptions and publications
|
15533
|
+
* @template IRmnEventMap A record type defining the structure of events and their data
|
15534
|
+
*/
|
15535
|
+
class PubsubService {
|
15536
|
+
constructor() {
|
15537
|
+
/**
|
15538
|
+
* Object to store subscribers for each event type
|
15539
|
+
*/
|
15540
|
+
this.subscribers = {};
|
15541
|
+
}
|
15542
|
+
static getInstance() {
|
15543
|
+
if (!PubsubService.instance) {
|
15544
|
+
PubsubService.instance = new PubsubService();
|
15545
|
+
}
|
15546
|
+
return PubsubService.instance;
|
15547
|
+
}
|
15548
|
+
/**
|
15549
|
+
* Subscribe to an event
|
15550
|
+
* @param eventType - The type of event to subscribe to
|
15551
|
+
* @param callback - The function to be called when the event is published
|
15552
|
+
* @returns A function to unsubscribe from the event
|
15553
|
+
*
|
15554
|
+
* @Example:
|
15555
|
+
* const unsubscribe = pubSub.subscribe('userLogin', (data) => {
|
15556
|
+
* console.log(`User ${data.username} logged in`);
|
15557
|
+
* });
|
15558
|
+
*/
|
15559
|
+
subscribe(eventType, callback) {
|
15560
|
+
if (!this.subscribers[eventType]) {
|
15561
|
+
this.subscribers[eventType] = [];
|
15562
|
+
}
|
15563
|
+
this.subscribers[eventType].push(callback);
|
15564
|
+
// Return an unsubscribe function
|
15565
|
+
return () => {
|
15566
|
+
this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
|
15567
|
+
};
|
15568
|
+
}
|
15569
|
+
/**
|
15570
|
+
* Publish an event
|
15571
|
+
* @param eventType - The type of event to publish
|
15572
|
+
* @param data - The data to be passed to the event subscribers
|
15573
|
+
*
|
15574
|
+
* @Example:
|
15575
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
15576
|
+
*/
|
15577
|
+
publish(eventType, data) {
|
15578
|
+
if (!this.subscribers[eventType]) {
|
15579
|
+
return;
|
15580
|
+
}
|
15581
|
+
this.subscribers[eventType].forEach((callback) => callback(data));
|
15582
|
+
}
|
15583
|
+
}
|
15584
|
+
/**
|
15585
|
+
* Usage Example:
|
15586
|
+
*
|
15587
|
+
* interface IRmnEventMap {
|
15588
|
+
* userLogin: { username: string; timestamp: number };
|
15589
|
+
* pageView: { url: string; timestamp: number };
|
15590
|
+
* }
|
15591
|
+
*
|
15592
|
+
* const pubSub = new PubsubService<IRmnEventMap>();
|
15593
|
+
*
|
15594
|
+
* // Subscribe to events
|
15595
|
+
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
15596
|
+
* console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
|
15597
|
+
* });
|
15598
|
+
*
|
15599
|
+
* pubSub.subscribe('pageView', (data) => {
|
15600
|
+
* console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
|
15601
|
+
* });
|
15602
|
+
*
|
15603
|
+
* // Publish events
|
15604
|
+
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
15605
|
+
* pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
|
15606
|
+
*
|
15607
|
+
* // Unsubscribe from an event
|
15608
|
+
* unsubscribeLogin();
|
15609
|
+
*/
|
15450
15610
|
|
15451
15611
|
class ResizeObserverService {
|
15452
15612
|
constructor({ element, maxSize, minScale }) {
|
@@ -15516,36 +15676,6 @@ class ResizeObserverService {
|
|
15516
15676
|
}
|
15517
15677
|
}
|
15518
15678
|
|
15519
|
-
function calculateScaleFactor(elementScale) {
|
15520
|
-
// Step 1: Apply square root for non-linear scaling
|
15521
|
-
// This creates a more gradual scaling effect, especially for larger changes
|
15522
|
-
// For example:
|
15523
|
-
// - elementScale of 0.25 (1/4 size) becomes 0.5
|
15524
|
-
// - elementScale of 1 (unchanged) remains 1
|
15525
|
-
// - elementScale of 4 (4x size) becomes 2
|
15526
|
-
const baseFactor = Math.sqrt(elementScale);
|
15527
|
-
// Step 2: Apply additional dampening to further soften the scaling effect
|
15528
|
-
// The dampening factor (0.5) can be adjusted:
|
15529
|
-
// - Lower values (closer to 0) make scaling more subtle
|
15530
|
-
// - Higher values (closer to 1) make scaling more pronounced
|
15531
|
-
const dampening = 0.35;
|
15532
|
-
// Calculate the scaleFactor:
|
15533
|
-
// 1. (baseFactor - 1) represents the change from the original size
|
15534
|
-
// 2. Multiply by dampening to reduce the effect
|
15535
|
-
// 3. Add 1 to center the scaling around the original size
|
15536
|
-
// For example, if baseFactor is 2:
|
15537
|
-
// scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
|
15538
|
-
const scaleFactor = 1 + (baseFactor - 1) * dampening;
|
15539
|
-
// Step 3: Define the allowed range for the scale factor
|
15540
|
-
// This ensures that the font size never changes too drastically
|
15541
|
-
const minScale = 0.35; // Font will never be smaller than 50% of original
|
15542
|
-
const maxScale = 1.5; // Font will never be larger than 150% of original
|
15543
|
-
// Step 4: Clamp the scale factor to the defined range
|
15544
|
-
// Math.min ensures the value doesn't exceed maxScale
|
15545
|
-
// Math.max ensures the value isn't less than minScale
|
15546
|
-
return Math.max(minScale, Math.min(maxScale, scaleFactor));
|
15547
|
-
}
|
15548
|
-
|
15549
15679
|
const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
15550
15680
|
:host {
|
15551
15681
|
position: relative;
|
@@ -15560,11 +15690,13 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
|
15560
15690
|
position: relative;
|
15561
15691
|
height: 100%;
|
15562
15692
|
width: 100%;
|
15693
|
+
display: flex;
|
15694
|
+
transition: transform 0.5s ease-in-out;
|
15563
15695
|
}
|
15564
15696
|
|
15565
15697
|
.slide {
|
15566
|
-
|
15567
|
-
|
15698
|
+
flex: 0 0 100%;
|
15699
|
+
display: flex;
|
15568
15700
|
justify-content: center;
|
15569
15701
|
align-items: center;
|
15570
15702
|
height: 100%;
|
@@ -15869,9 +16001,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15869
16001
|
renderSlides() {
|
15870
16002
|
const slidesContainer = document.createElement('div');
|
15871
16003
|
slidesContainer.className = 'slides';
|
15872
|
-
this.slides.forEach((slide
|
16004
|
+
this.slides.forEach((slide) => {
|
15873
16005
|
const slideElement = document.createElement('div');
|
15874
|
-
slideElement.className =
|
16006
|
+
slideElement.className = 'slide';
|
15875
16007
|
if (slide instanceof HTMLElement) {
|
15876
16008
|
slideElement.appendChild(slide);
|
15877
16009
|
}
|
@@ -15950,10 +16082,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15950
16082
|
updateCarousel() {
|
15951
16083
|
if (!this.slidesContainer)
|
15952
16084
|
return;
|
15953
|
-
|
15954
|
-
|
15955
|
-
|
15956
|
-
});
|
16085
|
+
// Calculate the translation distance based on current slide
|
16086
|
+
const translateX = -this.currentSlide * 100;
|
16087
|
+
this.slidesContainer.style.transform = `translateX(${translateX}%)`;
|
15957
16088
|
this.updateDots();
|
15958
16089
|
}
|
15959
16090
|
updateDots() {
|
@@ -16377,12 +16508,13 @@ function spotHtmlStringToElement(htmlString) {
|
|
16377
16508
|
spot.className = 'spot';
|
16378
16509
|
spot.innerHTML = htmlString;
|
16379
16510
|
Object.assign(spot.style, {
|
16380
|
-
position: 'relative',
|
16381
16511
|
display: 'block',
|
16382
16512
|
width: '100%',
|
16383
16513
|
height: '100%',
|
16384
16514
|
margin: '0',
|
16385
16515
|
padding: '0',
|
16516
|
+
containerType: 'inline-size',
|
16517
|
+
position: 'relative',
|
16386
16518
|
});
|
16387
16519
|
return spot;
|
16388
16520
|
}
|
@@ -17252,7 +17384,6 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
17252
17384
|
box-sizing: border-box;
|
17253
17385
|
color: ${textColor};
|
17254
17386
|
cursor: pointer;
|
17255
|
-
container-type: inline-size;
|
17256
17387
|
}
|
17257
17388
|
|
17258
17389
|
.${prefix}__text {
|
@@ -17268,7 +17399,7 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
17268
17399
|
.${prefix}__header {
|
17269
17400
|
font-size: 24px;
|
17270
17401
|
margin: 0;
|
17271
|
-
font-family: "Cormorant";
|
17402
|
+
font-family: "Cormorant", system-ui;
|
17272
17403
|
font-style: normal;
|
17273
17404
|
font-weight: 300;
|
17274
17405
|
line-height: normal;
|
@@ -17387,7 +17518,6 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
17387
17518
|
height: 100%;
|
17388
17519
|
display: block;
|
17389
17520
|
position: relative;
|
17390
|
-
container-type: inline-size;
|
17391
17521
|
}
|
17392
17522
|
|
17393
17523
|
.${prefix}__content {
|
@@ -17578,15 +17708,20 @@ function rbHomepageHeroThreeTileTemplate(spot, config) {
|
|
17578
17708
|
const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
|
17579
17709
|
<style>
|
17580
17710
|
.${prefix} {
|
17711
|
+
width: 100%;
|
17712
|
+
height: 100%;
|
17713
|
+
background-color: transparent;
|
17714
|
+
cursor: pointer;
|
17715
|
+
position: relative;
|
17716
|
+
}
|
17717
|
+
|
17718
|
+
.${prefix}__content {
|
17581
17719
|
width: 100%;
|
17582
17720
|
height: 100%;
|
17583
17721
|
display: flex;
|
17584
17722
|
flex-direction: column-reverse;
|
17585
17723
|
background-color: transparent;
|
17586
17724
|
gap: 6px;
|
17587
|
-
cursor: pointer;
|
17588
|
-
container-type: inline-size;
|
17589
|
-
position: relative;
|
17590
17725
|
}
|
17591
17726
|
|
17592
17727
|
.${prefix}__image {
|
@@ -17617,7 +17752,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
17617
17752
|
font-size: 18px;
|
17618
17753
|
margin: 0;
|
17619
17754
|
color: inherit;
|
17620
|
-
font-family: "Cormorant";
|
17755
|
+
font-family: "Cormorant", system-ui;
|
17621
17756
|
font-style: normal;
|
17622
17757
|
font-weight: 700;
|
17623
17758
|
line-height: normal;
|
@@ -17659,7 +17794,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
17659
17794
|
}
|
17660
17795
|
|
17661
17796
|
@container (min-width: 768px) {
|
17662
|
-
.${prefix} {
|
17797
|
+
.${prefix}__content {
|
17663
17798
|
flex-direction: row;
|
17664
17799
|
}
|
17665
17800
|
.${prefix}__image {
|
@@ -17714,12 +17849,14 @@ function rbHomepageHeroTwoTileTemplate(spot, config) {
|
|
17714
17849
|
${GFONT_CORMORANT}
|
17715
17850
|
${STYLES$4(spot, config)}
|
17716
17851
|
<div class="${prefix}">
|
17717
|
-
|
17718
|
-
|
17719
|
-
|
17720
|
-
|
17721
|
-
|
17722
|
-
|
17852
|
+
<div class="${prefix}__content">
|
17853
|
+
<div class="${prefix}__text">
|
17854
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
17855
|
+
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
17856
|
+
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
17857
|
+
</div>
|
17858
|
+
<div class="${prefix}__image"></div>
|
17859
|
+
</div>
|
17723
17860
|
</div>
|
17724
17861
|
`;
|
17725
17862
|
}
|
@@ -17742,12 +17879,10 @@ const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
17742
17879
|
overflow: hidden;
|
17743
17880
|
cursor: pointer;
|
17744
17881
|
color: ${textColor};
|
17745
|
-
container-type: inline-size;
|
17746
17882
|
}
|
17747
17883
|
|
17748
17884
|
.${prefix}__text {
|
17749
17885
|
padding: 20px;
|
17750
|
-
width: 70%;
|
17751
17886
|
display: flex;
|
17752
17887
|
flex-direction: column;
|
17753
17888
|
justify-content: center;
|
@@ -17759,7 +17894,7 @@ const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
17759
17894
|
color: inherit;
|
17760
17895
|
margin: 0;
|
17761
17896
|
font-size: 20px;
|
17762
|
-
font-family: "Cormorant";
|
17897
|
+
font-family: "Cormorant", system-ui;
|
17763
17898
|
font-style: normal;
|
17764
17899
|
font-weight: 300;
|
17765
17900
|
line-height: normal;
|
@@ -17878,7 +18013,6 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
17878
18013
|
background-size: cover;
|
17879
18014
|
background-position: center;
|
17880
18015
|
background-repeat: no-repeat;
|
17881
|
-
container-type: inline-size;
|
17882
18016
|
position: relative;
|
17883
18017
|
}
|
17884
18018
|
|
@@ -17948,12 +18082,7 @@ const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
17948
18082
|
border-radius: 5px;
|
17949
18083
|
overflow: hidden;
|
17950
18084
|
cursor: pointer;
|
17951
|
-
|
17952
|
-
}
|
17953
|
-
|
17954
|
-
.${prefix}__text {
|
17955
|
-
padding: 10px;
|
17956
|
-
width: 70%;
|
18085
|
+
position: relative;
|
17957
18086
|
}
|
17958
18087
|
|
17959
18088
|
.${prefix}__header {
|
@@ -17964,6 +18093,7 @@ const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
17964
18093
|
font-style: normal;
|
17965
18094
|
font-weight: 400;
|
17966
18095
|
margin: 0;
|
18096
|
+
padding: 10px;
|
17967
18097
|
}
|
17968
18098
|
|
17969
18099
|
@container (min-width: 640px) {
|
@@ -17981,9 +18111,7 @@ function rbSmallCategoryImageToutTemplate(spot, config) {
|
|
17981
18111
|
${GFONT_CORMORANT}
|
17982
18112
|
${STYLES$1(spot, config)}
|
17983
18113
|
<div class="${prefix}">
|
17984
|
-
|
17985
|
-
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
17986
|
-
</div>
|
18114
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
17987
18115
|
</div>
|
17988
18116
|
`;
|
17989
18117
|
}
|
@@ -17998,7 +18126,6 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
|
|
17998
18126
|
display: flex;
|
17999
18127
|
flex-direction: column;
|
18000
18128
|
border-radius: 5px;
|
18001
|
-
container-type: inline-size;
|
18002
18129
|
}
|
18003
18130
|
|
18004
18131
|
.${prefix}__image {
|
@@ -18134,97 +18261,65 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
18134
18261
|
return spotHtmlStringToElement(spotHtmlString);
|
18135
18262
|
};
|
18136
18263
|
|
18137
|
-
|
18138
|
-
|
18139
|
-
|
18140
|
-
|
18141
|
-
|
18142
|
-
|
18264
|
+
// For the moment, we will only focus on sites that use Google Analytics,
|
18265
|
+
// but we will add support for other analytics tools in the future.
|
18266
|
+
var AnalyticsTool;
|
18267
|
+
(function (AnalyticsTool) {
|
18268
|
+
AnalyticsTool["GoogleAnalytics"] = "google-analytics";
|
18269
|
+
AnalyticsTool["Other"] = "Other";
|
18270
|
+
})(AnalyticsTool || (AnalyticsTool = {}));
|
18271
|
+
|
18272
|
+
class DataLayerMonitor {
|
18143
18273
|
constructor() {
|
18144
|
-
|
18145
|
-
|
18146
|
-
|
18147
|
-
this.
|
18274
|
+
if (!window.dataLayer) {
|
18275
|
+
return;
|
18276
|
+
}
|
18277
|
+
this.originalPush = window.dataLayer.push;
|
18148
18278
|
}
|
18149
18279
|
static getInstance() {
|
18150
|
-
if (!
|
18151
|
-
|
18280
|
+
if (!DataLayerMonitor.instance) {
|
18281
|
+
DataLayerMonitor.instance = new DataLayerMonitor();
|
18152
18282
|
}
|
18153
|
-
return
|
18283
|
+
return DataLayerMonitor.instance;
|
18154
18284
|
}
|
18155
|
-
|
18156
|
-
|
18157
|
-
|
18158
|
-
|
18159
|
-
|
18160
|
-
|
18161
|
-
|
18162
|
-
|
18163
|
-
|
18164
|
-
|
18165
|
-
|
18166
|
-
|
18167
|
-
|
18168
|
-
|
18285
|
+
setListener(listener) {
|
18286
|
+
this.listener = listener;
|
18287
|
+
}
|
18288
|
+
start() {
|
18289
|
+
window.dataLayer.push = (...args) => {
|
18290
|
+
const result = this.originalPush.apply(window.dataLayer, args);
|
18291
|
+
const pushedEvent = args[0];
|
18292
|
+
if (this.listener) {
|
18293
|
+
const normalizedData = this.cleanEventData(pushedEvent);
|
18294
|
+
if (normalizedData) {
|
18295
|
+
this.listener(normalizedData);
|
18296
|
+
}
|
18297
|
+
}
|
18298
|
+
return result;
|
18299
|
+
};
|
18300
|
+
}
|
18301
|
+
cleanEventData(data) {
|
18302
|
+
const eventName = getEventTypeFromRawEvent(data.event);
|
18303
|
+
if (!eventName) {
|
18304
|
+
return null;
|
18169
18305
|
}
|
18170
|
-
|
18171
|
-
|
18172
|
-
|
18173
|
-
|
18306
|
+
const productIds = extractDeepIds(data.value);
|
18307
|
+
return {
|
18308
|
+
event: eventName,
|
18309
|
+
productIds,
|
18174
18310
|
};
|
18175
18311
|
}
|
18176
|
-
|
18177
|
-
|
18178
|
-
|
18179
|
-
* @param data - The data to be passed to the event subscribers
|
18180
|
-
*
|
18181
|
-
* @Example:
|
18182
|
-
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
18183
|
-
*/
|
18184
|
-
publish(eventType, data) {
|
18185
|
-
if (!this.subscribers[eventType]) {
|
18186
|
-
return;
|
18312
|
+
stop() {
|
18313
|
+
if (this.originalPush) {
|
18314
|
+
window.dataLayer.push = this.originalPush;
|
18187
18315
|
}
|
18188
|
-
this.
|
18316
|
+
this.listener = undefined;
|
18189
18317
|
}
|
18190
18318
|
}
|
18191
|
-
/**
|
18192
|
-
* Usage Example:
|
18193
|
-
*
|
18194
|
-
* interface IRmnEventMap {
|
18195
|
-
* userLogin: { username: string; timestamp: number };
|
18196
|
-
* pageView: { url: string; timestamp: number };
|
18197
|
-
* }
|
18198
|
-
*
|
18199
|
-
* const pubSub = new PubSub<IRmnEventMap>();
|
18200
|
-
*
|
18201
|
-
* // Subscribe to events
|
18202
|
-
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
18203
|
-
* console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
|
18204
|
-
* });
|
18205
|
-
*
|
18206
|
-
* pubSub.subscribe('pageView', (data) => {
|
18207
|
-
* console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
|
18208
|
-
* });
|
18209
|
-
*
|
18210
|
-
* // Publish events
|
18211
|
-
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
18212
|
-
* pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
|
18213
|
-
*
|
18214
|
-
* // Unsubscribe from an event
|
18215
|
-
* unsubscribeLogin();
|
18216
|
-
*/
|
18217
18319
|
|
18218
18320
|
// @TODO: Add support for user to push events to our own data layer, if they don't use any analytics tool.
|
18219
18321
|
// window.rmnDataLayer = window.rmnDataLayer || [];
|
18220
|
-
|
18221
|
-
// but we will add support for other analytics tools in the future.
|
18222
|
-
var AnalyticsTool;
|
18223
|
-
(function (AnalyticsTool) {
|
18224
|
-
AnalyticsTool["GoogleAnalytics"] = "google-analytics";
|
18225
|
-
AnalyticsTool["Other"] = "Other";
|
18226
|
-
})(AnalyticsTool || (AnalyticsTool = {}));
|
18227
|
-
class UserMonitor {
|
18322
|
+
class MonitorService {
|
18228
18323
|
constructor() {
|
18229
18324
|
const analyticsTool = this.detectAnalyticsTool();
|
18230
18325
|
switch (analyticsTool) {
|
@@ -18239,29 +18334,97 @@ class UserMonitor {
|
|
18239
18334
|
if (analyticsTool === AnalyticsTool.Other) {
|
18240
18335
|
return;
|
18241
18336
|
}
|
18242
|
-
this.
|
18337
|
+
this.pubSubService = PubsubService.getInstance();
|
18338
|
+
this.localStorageService = LocalStorageService.getInstance();
|
18243
18339
|
}
|
18244
18340
|
static getInstance() {
|
18245
|
-
if (!
|
18246
|
-
|
18341
|
+
if (!MonitorService.instance) {
|
18342
|
+
MonitorService.instance = new MonitorService();
|
18247
18343
|
}
|
18248
|
-
return
|
18344
|
+
return MonitorService.instance;
|
18249
18345
|
}
|
18250
18346
|
start() {
|
18251
18347
|
if (!this.implementedMonitor)
|
18252
18348
|
return;
|
18253
|
-
this.implementedMonitor.setListener((eventData) => {
|
18349
|
+
this.implementedMonitor.setListener(async (eventData) => {
|
18254
18350
|
var _a;
|
18255
|
-
this.matchAndFireEvent(eventData, (_a = this.
|
18351
|
+
await this.matchAndFireEvent(eventData, (_a = this.localStorageService) === null || _a === void 0 ? void 0 : _a.getSpots());
|
18256
18352
|
});
|
18257
18353
|
this.implementedMonitor.start();
|
18258
18354
|
}
|
18259
|
-
matchAndFireEvent(
|
18260
|
-
|
18261
|
-
|
18262
|
-
|
18263
|
-
|
18264
|
-
|
18355
|
+
async matchAndFireEvent(eventData, spots) {
|
18356
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
18357
|
+
if (!spots)
|
18358
|
+
return;
|
18359
|
+
const eventProductIds = new Set(eventData.productIds);
|
18360
|
+
for (const spot of Object.values(spots)) {
|
18361
|
+
if (!spot.productIds.length)
|
18362
|
+
continue;
|
18363
|
+
const hasCommonProductIds = spot.productIds.find((productId) => eventProductIds.has(productId));
|
18364
|
+
if (hasCommonProductIds) {
|
18365
|
+
switch (eventData.event) {
|
18366
|
+
case exports.RMN_SPOT_EVENT.ADD_TO_CART:
|
18367
|
+
await this.fireAndPublishSpotEvent({
|
18368
|
+
spotEvent: exports.RMN_SPOT_EVENT.ADD_TO_CART,
|
18369
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.ADD_TO_CART)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
18370
|
+
placementId: '',
|
18371
|
+
spotId: spot.spotId,
|
18372
|
+
spotElement: undefined,
|
18373
|
+
});
|
18374
|
+
break;
|
18375
|
+
case exports.RMN_SPOT_EVENT.REMOVE_FROM_CART:
|
18376
|
+
await this.fireAndPublishSpotEvent({
|
18377
|
+
spotEvent: exports.RMN_SPOT_EVENT.REMOVE_FROM_CART,
|
18378
|
+
eventUrl: (_d = (_c = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.REMOVE_FROM_CART)) === null || _c === void 0 ? void 0 : _c.url) !== null && _d !== void 0 ? _d : '',
|
18379
|
+
placementId: '',
|
18380
|
+
spotId: spot.spotId,
|
18381
|
+
spotElement: undefined,
|
18382
|
+
});
|
18383
|
+
break;
|
18384
|
+
case exports.RMN_SPOT_EVENT.PURCHASE:
|
18385
|
+
await this.fireAndPublishSpotEvent({
|
18386
|
+
spotEvent: exports.RMN_SPOT_EVENT.PURCHASE,
|
18387
|
+
eventUrl: (_f = (_e = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.PURCHASE)) === null || _e === void 0 ? void 0 : _e.url) !== null && _f !== void 0 ? _f : '',
|
18388
|
+
placementId: '',
|
18389
|
+
spotId: spot.spotId,
|
18390
|
+
spotElement: undefined,
|
18391
|
+
});
|
18392
|
+
break;
|
18393
|
+
case exports.RMN_SPOT_EVENT.ADD_TO_WISHLIST:
|
18394
|
+
await this.fireAndPublishSpotEvent({
|
18395
|
+
spotEvent: exports.RMN_SPOT_EVENT.ADD_TO_WISHLIST,
|
18396
|
+
eventUrl: (_h = (_g = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.ADD_TO_WISHLIST)) === null || _g === void 0 ? void 0 : _g.url) !== null && _h !== void 0 ? _h : '',
|
18397
|
+
placementId: '',
|
18398
|
+
spotId: spot.spotId,
|
18399
|
+
spotElement: undefined,
|
18400
|
+
});
|
18401
|
+
break;
|
18402
|
+
case exports.RMN_SPOT_EVENT.BUY_NOW:
|
18403
|
+
await this.fireAndPublishSpotEvent({
|
18404
|
+
spotEvent: exports.RMN_SPOT_EVENT.BUY_NOW,
|
18405
|
+
eventUrl: (_k = (_j = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.BUY_NOW)) === null || _j === void 0 ? void 0 : _j.url) !== null && _k !== void 0 ? _k : '',
|
18406
|
+
placementId: '',
|
18407
|
+
spotId: spot.spotId,
|
18408
|
+
spotElement: undefined,
|
18409
|
+
});
|
18410
|
+
break;
|
18411
|
+
}
|
18412
|
+
}
|
18413
|
+
}
|
18414
|
+
}
|
18415
|
+
async fireAndPublishSpotEvent({ spotEvent, eventUrl, placementId, spotId, spotElement, }) {
|
18416
|
+
await fireEvent({
|
18417
|
+
event: spotEvent,
|
18418
|
+
eventUrl,
|
18419
|
+
});
|
18420
|
+
if (!this.pubSubService)
|
18421
|
+
return;
|
18422
|
+
this.pubSubService.publish(exports.RMN_EVENT.SPOT_EVENT, {
|
18423
|
+
eventType: spotEvent,
|
18424
|
+
placementId,
|
18425
|
+
spotId,
|
18426
|
+
spotElement,
|
18427
|
+
});
|
18265
18428
|
}
|
18266
18429
|
detectAnalyticsTool() {
|
18267
18430
|
let analyticsTool = AnalyticsTool.Other;
|
@@ -18289,13 +18452,13 @@ class UserMonitor {
|
|
18289
18452
|
|
18290
18453
|
class EventService {
|
18291
18454
|
constructor() {
|
18292
|
-
this.
|
18293
|
-
this.
|
18455
|
+
this.pubSubService = PubsubService.getInstance();
|
18456
|
+
this.localStorageService = LocalStorageService.getInstance();
|
18294
18457
|
this.activeSpots = new Map();
|
18295
18458
|
this.spotStates = new Map();
|
18296
18459
|
this.intersectionObserver = new IntersectionObserverService();
|
18297
18460
|
// Start the user monitor, which will track and check user interactions
|
18298
|
-
|
18461
|
+
MonitorService.getInstance().start();
|
18299
18462
|
}
|
18300
18463
|
static getInstance() {
|
18301
18464
|
if (!EventService.instance) {
|
@@ -18304,10 +18467,10 @@ class EventService {
|
|
18304
18467
|
return EventService.instance;
|
18305
18468
|
}
|
18306
18469
|
subscribe(eventType, callback) {
|
18307
|
-
return this.
|
18470
|
+
return this.pubSubService.subscribe(eventType, callback);
|
18308
18471
|
}
|
18309
18472
|
publish(eventType, data) {
|
18310
|
-
this.
|
18473
|
+
this.pubSubService.publish(eventType, data);
|
18311
18474
|
}
|
18312
18475
|
registerSpot(params) {
|
18313
18476
|
const { placementId, spot, spotElement } = params;
|
@@ -18391,7 +18554,7 @@ class EventService {
|
|
18391
18554
|
const merged = this.deepMerge(currentState, updates);
|
18392
18555
|
this.spotStates.set(placementId, merged);
|
18393
18556
|
if (publish) {
|
18394
|
-
this.
|
18557
|
+
this.pubSubService.publish(exports.RMN_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
|
18395
18558
|
}
|
18396
18559
|
}
|
18397
18560
|
deepMerge(current, updates) {
|
@@ -18422,19 +18585,18 @@ class EventService {
|
|
18422
18585
|
}
|
18423
18586
|
async handleClick({ placementId, spot, spotElement, }) {
|
18424
18587
|
var _a, _b, _c;
|
18425
|
-
|
18426
|
-
|
18588
|
+
this.pubSubService.publish(exports.RMN_EVENT.SPOT_EVENT, {
|
18589
|
+
eventType: exports.RMN_SPOT_EVENT.CLICK,
|
18427
18590
|
placementId,
|
18428
18591
|
spotId: spot.id,
|
18429
18592
|
spotElement,
|
18430
18593
|
});
|
18431
|
-
|
18432
|
-
await this.fireEvent({
|
18594
|
+
await fireEvent({
|
18433
18595
|
event: exports.RMN_SPOT_EVENT.CLICK,
|
18434
18596
|
eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
18435
18597
|
});
|
18436
18598
|
// Save spot to local storage for event tracking
|
18437
|
-
this.
|
18599
|
+
this.localStorageService.setSpot(spot.id, {
|
18438
18600
|
spotId: spot.id,
|
18439
18601
|
spotType: spot.spot,
|
18440
18602
|
events: spot.events,
|
@@ -18454,90 +18616,20 @@ class EventService {
|
|
18454
18616
|
this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
|
18455
18617
|
}
|
18456
18618
|
fireImpressionEvent(placementId, spot, spotElement) {
|
18457
|
-
this.
|
18619
|
+
this.pubSubService.publish(exports.RMN_EVENT.SPOT_EVENT, {
|
18620
|
+
eventType: exports.RMN_SPOT_EVENT.IMPRESSION,
|
18458
18621
|
placementId,
|
18459
18622
|
spotId: spot.id,
|
18460
18623
|
spotElement,
|
18461
18624
|
});
|
18462
18625
|
(async () => {
|
18463
18626
|
var _a, _b;
|
18464
|
-
await
|
18627
|
+
await fireEvent({
|
18465
18628
|
event: exports.RMN_SPOT_EVENT.IMPRESSION,
|
18466
18629
|
eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
18467
18630
|
});
|
18468
18631
|
})();
|
18469
18632
|
}
|
18470
|
-
/**
|
18471
|
-
* Fires an event using the navigator.sendBeacon method or a fallback method if sendBeacon is not available.
|
18472
|
-
* If the event is a click event and a redirect URL is found, it redirects the user to that URL.
|
18473
|
-
*
|
18474
|
-
* @param {IFireEventParams} params - The parameters for firing the event.
|
18475
|
-
* @param {RMN_SPOT_EVENT} params.event - The event type.
|
18476
|
-
* @param {string} params.eventUrl - The URL to which the event is sent.
|
18477
|
-
* @returns {Promise<void>} - A promise that resolves when the event is fired.
|
18478
|
-
*/
|
18479
|
-
async fireEvent({ event, eventUrl }) {
|
18480
|
-
var _a;
|
18481
|
-
try {
|
18482
|
-
const didFireEvent = ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === null || _a === void 0 ? void 0 : _a.call(navigator, eventUrl)) || (await this.fallbackEventFire(eventUrl));
|
18483
|
-
if (!didFireEvent) {
|
18484
|
-
return;
|
18485
|
-
}
|
18486
|
-
if (event === exports.RMN_SPOT_EVENT.CLICK) {
|
18487
|
-
const redirectUrl = this.getRedirectUrlFromPayload(eventUrl);
|
18488
|
-
if (redirectUrl) {
|
18489
|
-
window.location.href = redirectUrl;
|
18490
|
-
}
|
18491
|
-
}
|
18492
|
-
}
|
18493
|
-
catch (_b) {
|
18494
|
-
// Handle errors silently
|
18495
|
-
}
|
18496
|
-
}
|
18497
|
-
// Fallback method using fetch if sendBeacon isn't available
|
18498
|
-
async fallbackEventFire(url) {
|
18499
|
-
try {
|
18500
|
-
const racePromise = Promise.race([
|
18501
|
-
// Promise #1: The fetch request
|
18502
|
-
fetch(url, {
|
18503
|
-
method: 'POST',
|
18504
|
-
keepalive: true,
|
18505
|
-
}),
|
18506
|
-
// Promise #2: The timeout
|
18507
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 2000)),
|
18508
|
-
]);
|
18509
|
-
/**
|
18510
|
-
* Prevent requests from hanging indefinitely
|
18511
|
-
* Improve user experience by failing fast
|
18512
|
-
* Handle slow network conditions gracefully
|
18513
|
-
* Ensure resources are freed up in a timely manner
|
18514
|
-
*/
|
18515
|
-
const response = await racePromise;
|
18516
|
-
return response.ok;
|
18517
|
-
}
|
18518
|
-
catch (_a) {
|
18519
|
-
return false;
|
18520
|
-
}
|
18521
|
-
}
|
18522
|
-
/**
|
18523
|
-
* Extracts and decodes a URL from a base64-encoded query parameter.
|
18524
|
-
*
|
18525
|
-
* @param {string} url - The URL containing the base64-encoded query parameter.
|
18526
|
-
* @returns {string | null} - The decoded URL or null if not found or invalid.
|
18527
|
-
*/
|
18528
|
-
getRedirectUrlFromPayload(url) {
|
18529
|
-
try {
|
18530
|
-
const base64String = new URL(url).searchParams.get('e');
|
18531
|
-
if (!base64String) {
|
18532
|
-
return null;
|
18533
|
-
}
|
18534
|
-
const data = JSON.parse(atob(base64String));
|
18535
|
-
return data.ur || null;
|
18536
|
-
}
|
18537
|
-
catch (_a) {
|
18538
|
-
return null;
|
18539
|
-
}
|
18540
|
-
}
|
18541
18633
|
}
|
18542
18634
|
|
18543
18635
|
const SELECTION_API_PATH = '/spots/selection';
|