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