@liquidcommercedev/rmn-sdk 1.5.0-beta.5 → 1.5.0-beta.6
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +140 -14
- package/dist/index.esm.js +140 -14
- package/dist/types/enums.d.ts +1 -0
- package/dist/types/modules/event/event.interface.d.ts +5 -0
- package/dist/types/modules/event/helpers/datalayer.monitor.d.ts +12 -1
- package/dist/types/modules/event/helpers/localstorage.service.d.ts +26 -7
- package/dist/types/modules/event/helpers/utils.d.ts +24 -0
- package/dist/types/modules/event/pubsub.d.ts +7 -7
- package/dist/types/modules/event/user.monitor.d.ts +1 -0
- package/dist/types/types.d.ts +1 -1
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.cjs
CHANGED
@@ -62,6 +62,7 @@ exports.RMN_SPOT_EVENT = void 0;
|
|
62
62
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
63
63
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
64
64
|
RMN_SPOT_EVENT["ADD_TO_CART"] = "ADD_TO_CART";
|
65
|
+
RMN_SPOT_EVENT["REMOVE_FROM_CART"] = "REMOVE_FROM_CART";
|
65
66
|
RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
|
66
67
|
RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
|
67
68
|
})(exports.RMN_SPOT_EVENT || (exports.RMN_SPOT_EVENT = {}));
|
@@ -15166,6 +15167,84 @@ const GFONT_CORMORANT = `
|
|
15166
15167
|
<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">
|
15167
15168
|
`;
|
15168
15169
|
|
15170
|
+
function getEventTypeFromRawEvent(event) {
|
15171
|
+
if (!event) {
|
15172
|
+
return null;
|
15173
|
+
}
|
15174
|
+
if (event.includes('cart')) {
|
15175
|
+
if (event.includes('add')) {
|
15176
|
+
return exports.RMN_SPOT_EVENT.ADD_TO_CART;
|
15177
|
+
}
|
15178
|
+
if (event.includes('remove')) {
|
15179
|
+
return exports.RMN_SPOT_EVENT.REMOVE_FROM_CART;
|
15180
|
+
}
|
15181
|
+
}
|
15182
|
+
if (event.includes('purchase')) {
|
15183
|
+
return exports.RMN_SPOT_EVENT.PURCHASE;
|
15184
|
+
}
|
15185
|
+
// if(event.includes('refund')) {
|
15186
|
+
// return RMN_SPOT_EVENT.REFUND;
|
15187
|
+
// }
|
15188
|
+
if (event.includes('wishlist') && event.includes('add')) {
|
15189
|
+
return exports.RMN_SPOT_EVENT.ADD_TO_WISHLIST;
|
15190
|
+
}
|
15191
|
+
return null;
|
15192
|
+
}
|
15193
|
+
/**
|
15194
|
+
* Recursively extracts ID values from a nested data structure.
|
15195
|
+
* Searches for specified property names and collects their primitive values (strings/numbers).
|
15196
|
+
*
|
15197
|
+
* @param data - The data structure to search through (can be nested objects/arrays)
|
15198
|
+
* @param propertyNames - Array of property names to look for (defaults to ['id', 'upc', 'groupingId', 'sku', 'productId'])
|
15199
|
+
* @returns Array of extracted ID values (strings/numbers only)
|
15200
|
+
*
|
15201
|
+
* @example
|
15202
|
+
* const data = {
|
15203
|
+
* id: [1, 2, 3],
|
15204
|
+
* nested: { id: 'abc' },
|
15205
|
+
* items: [{ id: 456 }]
|
15206
|
+
* };
|
15207
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
15208
|
+
*/
|
15209
|
+
function extractDeepIds(data, propertyNames = ['id', 'upc', 'groupingId', 'sku', 'productId']) {
|
15210
|
+
const ids = [];
|
15211
|
+
// Set for faster property name lookups
|
15212
|
+
const propertySet = new Set(propertyNames);
|
15213
|
+
/**
|
15214
|
+
* Processes a value and extracts IDs if it matches criteria
|
15215
|
+
* @param value - The value to process
|
15216
|
+
* @param currentKey - The property name of the current value
|
15217
|
+
*/
|
15218
|
+
const processValue = (value, currentKey) => {
|
15219
|
+
// Early exit for null/undefined values
|
15220
|
+
if (value == null)
|
15221
|
+
return;
|
15222
|
+
// If current key matches our target properties
|
15223
|
+
if (currentKey && propertySet.has(currentKey)) {
|
15224
|
+
if (Array.isArray(value)) {
|
15225
|
+
// Filter and push valid array values in one pass
|
15226
|
+
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
15227
|
+
}
|
15228
|
+
else if (typeof value === 'string' || typeof value === 'number') {
|
15229
|
+
ids.push(value);
|
15230
|
+
}
|
15231
|
+
return; // Stop processing this branch after handling the ID
|
15232
|
+
}
|
15233
|
+
// Recursively process nested structures
|
15234
|
+
if (Array.isArray(value)) {
|
15235
|
+
value.forEach((item) => processValue(item));
|
15236
|
+
}
|
15237
|
+
else if (typeof value === 'object') {
|
15238
|
+
// Process all enumerable properties
|
15239
|
+
for (const [key, val] of Object.entries(value)) {
|
15240
|
+
processValue(val, key);
|
15241
|
+
}
|
15242
|
+
}
|
15243
|
+
};
|
15244
|
+
processValue(data);
|
15245
|
+
return ids; // No need to filter nulls as we handle that during collection
|
15246
|
+
}
|
15247
|
+
|
15169
15248
|
class DataLayerMonitor {
|
15170
15249
|
constructor() {
|
15171
15250
|
if (!window.dataLayer) {
|
@@ -15187,11 +15266,25 @@ class DataLayerMonitor {
|
|
15187
15266
|
const result = this.originalPush.apply(window.dataLayer, args);
|
15188
15267
|
const pushedEvent = args[0];
|
15189
15268
|
if (this.listener) {
|
15190
|
-
this.
|
15269
|
+
const normalizedData = this.cleanEventData(pushedEvent);
|
15270
|
+
if (normalizedData) {
|
15271
|
+
this.listener(normalizedData);
|
15272
|
+
}
|
15191
15273
|
}
|
15192
15274
|
return result;
|
15193
15275
|
};
|
15194
15276
|
}
|
15277
|
+
cleanEventData(data) {
|
15278
|
+
const eventName = getEventTypeFromRawEvent(data.event);
|
15279
|
+
if (!eventName) {
|
15280
|
+
return null;
|
15281
|
+
}
|
15282
|
+
const productIds = extractDeepIds(data.value);
|
15283
|
+
return {
|
15284
|
+
event: eventName,
|
15285
|
+
productIds,
|
15286
|
+
};
|
15287
|
+
}
|
15195
15288
|
stop() {
|
15196
15289
|
if (this.originalPush) {
|
15197
15290
|
window.dataLayer.push = this.originalPush;
|
@@ -15240,6 +15333,14 @@ class IntersectionObserverService {
|
|
15240
15333
|
}
|
15241
15334
|
}
|
15242
15335
|
|
15336
|
+
var ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX;
|
15337
|
+
(function (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX) {
|
15338
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_ID"] = 0] = "SPOT_ID";
|
15339
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_TYPE"] = 1] = "SPOT_TYPE";
|
15340
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["EVENTS"] = 2] = "EVENTS";
|
15341
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["PRODUCT_IDS"] = 3] = "PRODUCT_IDS";
|
15342
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["CREATED_AT"] = 4] = "CREATED_AT";
|
15343
|
+
})(ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX || (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX = {}));
|
15243
15344
|
class LocalStorage {
|
15244
15345
|
constructor() {
|
15245
15346
|
if (typeof window.localStorage === 'undefined') {
|
@@ -15265,7 +15366,11 @@ class LocalStorage {
|
|
15265
15366
|
try {
|
15266
15367
|
const parsedData = JSON.parse(localStorageData);
|
15267
15368
|
if (parsedData && typeof parsedData === 'object') {
|
15268
|
-
|
15369
|
+
const data = {};
|
15370
|
+
for (const [key, value] of Object.entries(parsedData)) {
|
15371
|
+
data[key] = this.arrayToObject(value);
|
15372
|
+
}
|
15373
|
+
this.spots = this.objectToMap(data);
|
15269
15374
|
}
|
15270
15375
|
else {
|
15271
15376
|
this.clearLocalStorage();
|
@@ -15295,13 +15400,17 @@ class LocalStorage {
|
|
15295
15400
|
getSpots() {
|
15296
15401
|
if (!this.spots)
|
15297
15402
|
return undefined;
|
15298
|
-
return this.
|
15403
|
+
return this.mapToObject(this.spots);
|
15299
15404
|
}
|
15300
15405
|
updateLocalStorage() {
|
15301
15406
|
if (!this.spots)
|
15302
15407
|
return undefined;
|
15303
|
-
const data = this.
|
15304
|
-
|
15408
|
+
const data = this.mapToObject(this.spots);
|
15409
|
+
const dataArray = {};
|
15410
|
+
for (const [key, value] of Object.entries(data)) {
|
15411
|
+
dataArray[key] = this.objectToArray(value);
|
15412
|
+
}
|
15413
|
+
window.localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(dataArray));
|
15305
15414
|
}
|
15306
15415
|
clearLocalStorage() {
|
15307
15416
|
window.localStorage.removeItem(LocalStorage.localStorageKey);
|
@@ -15317,12 +15426,24 @@ class LocalStorage {
|
|
15317
15426
|
});
|
15318
15427
|
this.updateLocalStorage();
|
15319
15428
|
}
|
15320
|
-
|
15429
|
+
mapToObject(map) {
|
15321
15430
|
return Object.fromEntries(map);
|
15322
15431
|
}
|
15323
|
-
|
15432
|
+
objectToMap(obj) {
|
15324
15433
|
return new Map(Object.entries(obj));
|
15325
15434
|
}
|
15435
|
+
objectToArray(obj) {
|
15436
|
+
return [obj.spotId, obj.spotType, obj.events, obj.productIds, obj.createdAt];
|
15437
|
+
}
|
15438
|
+
arrayToObject(arr) {
|
15439
|
+
return {
|
15440
|
+
spotId: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_ID],
|
15441
|
+
spotType: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_TYPE],
|
15442
|
+
events: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.EVENTS],
|
15443
|
+
productIds: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.PRODUCT_IDS],
|
15444
|
+
createdAt: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.CREATED_AT],
|
15445
|
+
};
|
15446
|
+
}
|
15326
15447
|
}
|
15327
15448
|
LocalStorage.localStorageKey = 'lc_rmn';
|
15328
15449
|
LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
@@ -18016,7 +18137,7 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
18016
18137
|
/**
|
18017
18138
|
* PubSub class
|
18018
18139
|
* Manages event subscriptions and publications
|
18019
|
-
* @template
|
18140
|
+
* @template IRmnEventMap A record type defining the structure of events and their data
|
18020
18141
|
*/
|
18021
18142
|
class PubSub {
|
18022
18143
|
constructor() {
|
@@ -18070,12 +18191,12 @@ class PubSub {
|
|
18070
18191
|
/**
|
18071
18192
|
* Usage Example:
|
18072
18193
|
*
|
18073
|
-
* interface
|
18194
|
+
* interface IRmnEventMap {
|
18074
18195
|
* userLogin: { username: string; timestamp: number };
|
18075
18196
|
* pageView: { url: string; timestamp: number };
|
18076
18197
|
* }
|
18077
18198
|
*
|
18078
|
-
* const pubSub = new PubSub<
|
18199
|
+
* const pubSub = new PubSub<IRmnEventMap>();
|
18079
18200
|
*
|
18080
18201
|
* // Subscribe to events
|
18081
18202
|
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
@@ -18106,7 +18227,6 @@ var AnalyticsTool;
|
|
18106
18227
|
class UserMonitor {
|
18107
18228
|
constructor() {
|
18108
18229
|
const analyticsTool = this.detectAnalyticsTool();
|
18109
|
-
console.info({ analyticsTool });
|
18110
18230
|
switch (analyticsTool) {
|
18111
18231
|
case AnalyticsTool.GoogleAnalytics:
|
18112
18232
|
this.implementedMonitor = DataLayerMonitor.getInstance();
|
@@ -18130,13 +18250,19 @@ class UserMonitor {
|
|
18130
18250
|
start() {
|
18131
18251
|
if (!this.implementedMonitor)
|
18132
18252
|
return;
|
18133
|
-
this.implementedMonitor.setListener((
|
18253
|
+
this.implementedMonitor.setListener((eventData) => {
|
18134
18254
|
var _a;
|
18135
|
-
|
18136
|
-
console.info({ spots: (_a = this.localStorage) === null || _a === void 0 ? void 0 : _a.getSpots() });
|
18255
|
+
this.matchAndFireEvent(eventData, (_a = this.localStorage) === null || _a === void 0 ? void 0 : _a.getSpots());
|
18137
18256
|
});
|
18138
18257
|
this.implementedMonitor.start();
|
18139
18258
|
}
|
18259
|
+
matchAndFireEvent(
|
18260
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
18261
|
+
_eventData,
|
18262
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
18263
|
+
_spots) {
|
18264
|
+
// console.info({ eventData, spots });
|
18265
|
+
}
|
18140
18266
|
detectAnalyticsTool() {
|
18141
18267
|
let analyticsTool = AnalyticsTool.Other;
|
18142
18268
|
// Check for Google Analytics
|
package/dist/index.esm.js
CHANGED
@@ -60,6 +60,7 @@ var RMN_SPOT_EVENT;
|
|
60
60
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
61
61
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
62
62
|
RMN_SPOT_EVENT["ADD_TO_CART"] = "ADD_TO_CART";
|
63
|
+
RMN_SPOT_EVENT["REMOVE_FROM_CART"] = "REMOVE_FROM_CART";
|
63
64
|
RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
|
64
65
|
RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
|
65
66
|
})(RMN_SPOT_EVENT || (RMN_SPOT_EVENT = {}));
|
@@ -15164,6 +15165,84 @@ const GFONT_CORMORANT = `
|
|
15164
15165
|
<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">
|
15165
15166
|
`;
|
15166
15167
|
|
15168
|
+
function getEventTypeFromRawEvent(event) {
|
15169
|
+
if (!event) {
|
15170
|
+
return null;
|
15171
|
+
}
|
15172
|
+
if (event.includes('cart')) {
|
15173
|
+
if (event.includes('add')) {
|
15174
|
+
return RMN_SPOT_EVENT.ADD_TO_CART;
|
15175
|
+
}
|
15176
|
+
if (event.includes('remove')) {
|
15177
|
+
return RMN_SPOT_EVENT.REMOVE_FROM_CART;
|
15178
|
+
}
|
15179
|
+
}
|
15180
|
+
if (event.includes('purchase')) {
|
15181
|
+
return RMN_SPOT_EVENT.PURCHASE;
|
15182
|
+
}
|
15183
|
+
// if(event.includes('refund')) {
|
15184
|
+
// return RMN_SPOT_EVENT.REFUND;
|
15185
|
+
// }
|
15186
|
+
if (event.includes('wishlist') && event.includes('add')) {
|
15187
|
+
return RMN_SPOT_EVENT.ADD_TO_WISHLIST;
|
15188
|
+
}
|
15189
|
+
return null;
|
15190
|
+
}
|
15191
|
+
/**
|
15192
|
+
* Recursively extracts ID values from a nested data structure.
|
15193
|
+
* Searches for specified property names and collects their primitive values (strings/numbers).
|
15194
|
+
*
|
15195
|
+
* @param data - The data structure to search through (can be nested objects/arrays)
|
15196
|
+
* @param propertyNames - Array of property names to look for (defaults to ['id', 'upc', 'groupingId', 'sku', 'productId'])
|
15197
|
+
* @returns Array of extracted ID values (strings/numbers only)
|
15198
|
+
*
|
15199
|
+
* @example
|
15200
|
+
* const data = {
|
15201
|
+
* id: [1, 2, 3],
|
15202
|
+
* nested: { id: 'abc' },
|
15203
|
+
* items: [{ id: 456 }]
|
15204
|
+
* };
|
15205
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
15206
|
+
*/
|
15207
|
+
function extractDeepIds(data, propertyNames = ['id', 'upc', 'groupingId', 'sku', 'productId']) {
|
15208
|
+
const ids = [];
|
15209
|
+
// Set for faster property name lookups
|
15210
|
+
const propertySet = new Set(propertyNames);
|
15211
|
+
/**
|
15212
|
+
* Processes a value and extracts IDs if it matches criteria
|
15213
|
+
* @param value - The value to process
|
15214
|
+
* @param currentKey - The property name of the current value
|
15215
|
+
*/
|
15216
|
+
const processValue = (value, currentKey) => {
|
15217
|
+
// Early exit for null/undefined values
|
15218
|
+
if (value == null)
|
15219
|
+
return;
|
15220
|
+
// If current key matches our target properties
|
15221
|
+
if (currentKey && propertySet.has(currentKey)) {
|
15222
|
+
if (Array.isArray(value)) {
|
15223
|
+
// Filter and push valid array values in one pass
|
15224
|
+
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
15225
|
+
}
|
15226
|
+
else if (typeof value === 'string' || typeof value === 'number') {
|
15227
|
+
ids.push(value);
|
15228
|
+
}
|
15229
|
+
return; // Stop processing this branch after handling the ID
|
15230
|
+
}
|
15231
|
+
// Recursively process nested structures
|
15232
|
+
if (Array.isArray(value)) {
|
15233
|
+
value.forEach((item) => processValue(item));
|
15234
|
+
}
|
15235
|
+
else if (typeof value === 'object') {
|
15236
|
+
// Process all enumerable properties
|
15237
|
+
for (const [key, val] of Object.entries(value)) {
|
15238
|
+
processValue(val, key);
|
15239
|
+
}
|
15240
|
+
}
|
15241
|
+
};
|
15242
|
+
processValue(data);
|
15243
|
+
return ids; // No need to filter nulls as we handle that during collection
|
15244
|
+
}
|
15245
|
+
|
15167
15246
|
class DataLayerMonitor {
|
15168
15247
|
constructor() {
|
15169
15248
|
if (!window.dataLayer) {
|
@@ -15185,11 +15264,25 @@ class DataLayerMonitor {
|
|
15185
15264
|
const result = this.originalPush.apply(window.dataLayer, args);
|
15186
15265
|
const pushedEvent = args[0];
|
15187
15266
|
if (this.listener) {
|
15188
|
-
this.
|
15267
|
+
const normalizedData = this.cleanEventData(pushedEvent);
|
15268
|
+
if (normalizedData) {
|
15269
|
+
this.listener(normalizedData);
|
15270
|
+
}
|
15189
15271
|
}
|
15190
15272
|
return result;
|
15191
15273
|
};
|
15192
15274
|
}
|
15275
|
+
cleanEventData(data) {
|
15276
|
+
const eventName = getEventTypeFromRawEvent(data.event);
|
15277
|
+
if (!eventName) {
|
15278
|
+
return null;
|
15279
|
+
}
|
15280
|
+
const productIds = extractDeepIds(data.value);
|
15281
|
+
return {
|
15282
|
+
event: eventName,
|
15283
|
+
productIds,
|
15284
|
+
};
|
15285
|
+
}
|
15193
15286
|
stop() {
|
15194
15287
|
if (this.originalPush) {
|
15195
15288
|
window.dataLayer.push = this.originalPush;
|
@@ -15238,6 +15331,14 @@ class IntersectionObserverService {
|
|
15238
15331
|
}
|
15239
15332
|
}
|
15240
15333
|
|
15334
|
+
var ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX;
|
15335
|
+
(function (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX) {
|
15336
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_ID"] = 0] = "SPOT_ID";
|
15337
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_TYPE"] = 1] = "SPOT_TYPE";
|
15338
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["EVENTS"] = 2] = "EVENTS";
|
15339
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["PRODUCT_IDS"] = 3] = "PRODUCT_IDS";
|
15340
|
+
ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["CREATED_AT"] = 4] = "CREATED_AT";
|
15341
|
+
})(ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX || (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX = {}));
|
15241
15342
|
class LocalStorage {
|
15242
15343
|
constructor() {
|
15243
15344
|
if (typeof window.localStorage === 'undefined') {
|
@@ -15263,7 +15364,11 @@ class LocalStorage {
|
|
15263
15364
|
try {
|
15264
15365
|
const parsedData = JSON.parse(localStorageData);
|
15265
15366
|
if (parsedData && typeof parsedData === 'object') {
|
15266
|
-
|
15367
|
+
const data = {};
|
15368
|
+
for (const [key, value] of Object.entries(parsedData)) {
|
15369
|
+
data[key] = this.arrayToObject(value);
|
15370
|
+
}
|
15371
|
+
this.spots = this.objectToMap(data);
|
15267
15372
|
}
|
15268
15373
|
else {
|
15269
15374
|
this.clearLocalStorage();
|
@@ -15293,13 +15398,17 @@ class LocalStorage {
|
|
15293
15398
|
getSpots() {
|
15294
15399
|
if (!this.spots)
|
15295
15400
|
return undefined;
|
15296
|
-
return this.
|
15401
|
+
return this.mapToObject(this.spots);
|
15297
15402
|
}
|
15298
15403
|
updateLocalStorage() {
|
15299
15404
|
if (!this.spots)
|
15300
15405
|
return undefined;
|
15301
|
-
const data = this.
|
15302
|
-
|
15406
|
+
const data = this.mapToObject(this.spots);
|
15407
|
+
const dataArray = {};
|
15408
|
+
for (const [key, value] of Object.entries(data)) {
|
15409
|
+
dataArray[key] = this.objectToArray(value);
|
15410
|
+
}
|
15411
|
+
window.localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(dataArray));
|
15303
15412
|
}
|
15304
15413
|
clearLocalStorage() {
|
15305
15414
|
window.localStorage.removeItem(LocalStorage.localStorageKey);
|
@@ -15315,12 +15424,24 @@ class LocalStorage {
|
|
15315
15424
|
});
|
15316
15425
|
this.updateLocalStorage();
|
15317
15426
|
}
|
15318
|
-
|
15427
|
+
mapToObject(map) {
|
15319
15428
|
return Object.fromEntries(map);
|
15320
15429
|
}
|
15321
|
-
|
15430
|
+
objectToMap(obj) {
|
15322
15431
|
return new Map(Object.entries(obj));
|
15323
15432
|
}
|
15433
|
+
objectToArray(obj) {
|
15434
|
+
return [obj.spotId, obj.spotType, obj.events, obj.productIds, obj.createdAt];
|
15435
|
+
}
|
15436
|
+
arrayToObject(arr) {
|
15437
|
+
return {
|
15438
|
+
spotId: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_ID],
|
15439
|
+
spotType: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_TYPE],
|
15440
|
+
events: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.EVENTS],
|
15441
|
+
productIds: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.PRODUCT_IDS],
|
15442
|
+
createdAt: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.CREATED_AT],
|
15443
|
+
};
|
15444
|
+
}
|
15324
15445
|
}
|
15325
15446
|
LocalStorage.localStorageKey = 'lc_rmn';
|
15326
15447
|
LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
@@ -18014,7 +18135,7 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
18014
18135
|
/**
|
18015
18136
|
* PubSub class
|
18016
18137
|
* Manages event subscriptions and publications
|
18017
|
-
* @template
|
18138
|
+
* @template IRmnEventMap A record type defining the structure of events and their data
|
18018
18139
|
*/
|
18019
18140
|
class PubSub {
|
18020
18141
|
constructor() {
|
@@ -18068,12 +18189,12 @@ class PubSub {
|
|
18068
18189
|
/**
|
18069
18190
|
* Usage Example:
|
18070
18191
|
*
|
18071
|
-
* interface
|
18192
|
+
* interface IRmnEventMap {
|
18072
18193
|
* userLogin: { username: string; timestamp: number };
|
18073
18194
|
* pageView: { url: string; timestamp: number };
|
18074
18195
|
* }
|
18075
18196
|
*
|
18076
|
-
* const pubSub = new PubSub<
|
18197
|
+
* const pubSub = new PubSub<IRmnEventMap>();
|
18077
18198
|
*
|
18078
18199
|
* // Subscribe to events
|
18079
18200
|
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|
@@ -18104,7 +18225,6 @@ var AnalyticsTool;
|
|
18104
18225
|
class UserMonitor {
|
18105
18226
|
constructor() {
|
18106
18227
|
const analyticsTool = this.detectAnalyticsTool();
|
18107
|
-
console.info({ analyticsTool });
|
18108
18228
|
switch (analyticsTool) {
|
18109
18229
|
case AnalyticsTool.GoogleAnalytics:
|
18110
18230
|
this.implementedMonitor = DataLayerMonitor.getInstance();
|
@@ -18128,13 +18248,19 @@ class UserMonitor {
|
|
18128
18248
|
start() {
|
18129
18249
|
if (!this.implementedMonitor)
|
18130
18250
|
return;
|
18131
|
-
this.implementedMonitor.setListener((
|
18251
|
+
this.implementedMonitor.setListener((eventData) => {
|
18132
18252
|
var _a;
|
18133
|
-
|
18134
|
-
console.info({ spots: (_a = this.localStorage) === null || _a === void 0 ? void 0 : _a.getSpots() });
|
18253
|
+
this.matchAndFireEvent(eventData, (_a = this.localStorage) === null || _a === void 0 ? void 0 : _a.getSpots());
|
18135
18254
|
});
|
18136
18255
|
this.implementedMonitor.start();
|
18137
18256
|
}
|
18257
|
+
matchAndFireEvent(
|
18258
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
18259
|
+
_eventData,
|
18260
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
18261
|
+
_spots) {
|
18262
|
+
// console.info({ eventData, spots });
|
18263
|
+
}
|
18138
18264
|
detectAnalyticsTool() {
|
18139
18265
|
let analyticsTool = AnalyticsTool.Other;
|
18140
18266
|
// Check for Google Analytics
|
package/dist/types/enums.d.ts
CHANGED
@@ -44,6 +44,10 @@ export interface IAddToCartEvent {
|
|
44
44
|
placementId: string;
|
45
45
|
spotId: string;
|
46
46
|
}
|
47
|
+
export interface IRemoveFromCartEvent {
|
48
|
+
placementId: string;
|
49
|
+
spotId: string;
|
50
|
+
}
|
47
51
|
export interface IAddToWishlistEvent {
|
48
52
|
placementId: string;
|
49
53
|
spotId: string;
|
@@ -61,6 +65,7 @@ export interface IRmnEventMap {
|
|
61
65
|
[RMN_SPOT_EVENT.CLICK]: IClickEvent;
|
62
66
|
[RMN_SPOT_EVENT.IMPRESSION]: IImpressionEvent;
|
63
67
|
[RMN_SPOT_EVENT.ADD_TO_CART]: IAddToCartEvent;
|
68
|
+
[RMN_SPOT_EVENT.REMOVE_FROM_CART]: IRemoveFromCartEvent;
|
64
69
|
[RMN_SPOT_EVENT.ADD_TO_WISHLIST]: IAddToWishlistEvent;
|
65
70
|
[RMN_SPOT_EVENT.PURCHASE]: IPurchaseEvent;
|
66
71
|
[RMN_SPOT_EVENT.BUY_NOW]: IBuyNowEvent;
|
@@ -1,10 +1,21 @@
|
|
1
|
+
import type { RMN_SPOT_EVENT } from 'enums';
|
2
|
+
export interface IDataLayerEvent {
|
3
|
+
event?: string;
|
4
|
+
value?: any[];
|
5
|
+
[key: string]: any;
|
6
|
+
}
|
7
|
+
export interface INormalizedEventData {
|
8
|
+
event: RMN_SPOT_EVENT;
|
9
|
+
productIds: Array<string | number>;
|
10
|
+
}
|
1
11
|
export declare class DataLayerMonitor {
|
2
12
|
private static instance;
|
3
13
|
private readonly originalPush;
|
4
14
|
private listener?;
|
5
15
|
private constructor();
|
6
16
|
static getInstance(): DataLayerMonitor;
|
7
|
-
setListener(listener: (data:
|
17
|
+
setListener(listener: (data: INormalizedEventData) => void): void;
|
8
18
|
start(): void;
|
19
|
+
private cleanEventData;
|
9
20
|
stop(): void;
|
10
21
|
}
|
@@ -1,9 +1,5 @@
|
|
1
1
|
import type { RMN_SPOT_TYPE } from 'enums';
|
2
2
|
import type { ISpotEvent } from 'modules/selection';
|
3
|
-
export type LocalStorageSpotsMapType = Map<string, // spotId
|
4
|
-
ILocalStorageSpot>;
|
5
|
-
export type LocalStorageSpotsObjType = Record<string, // spotId
|
6
|
-
ILocalStorageSpot>;
|
7
3
|
export interface ILocalStorageSpot {
|
8
4
|
spotId: string;
|
9
5
|
spotType: RMN_SPOT_TYPE;
|
@@ -11,6 +7,27 @@ export interface ILocalStorageSpot {
|
|
11
7
|
productIds: Array<string | number>;
|
12
8
|
createdAt?: number;
|
13
9
|
}
|
10
|
+
export type LocalStorageSpotsMapType = Map<string, // spotId
|
11
|
+
ILocalStorageSpot>;
|
12
|
+
export type LocalStorageSpotsObjectType = Record<string, // spotId
|
13
|
+
ILocalStorageSpot>;
|
14
|
+
export type LocalStorageSpotArray = [
|
15
|
+
string,
|
16
|
+
RMN_SPOT_TYPE,
|
17
|
+
ISpotEvent[],
|
18
|
+
Array<string | number>,
|
19
|
+
// PRODUCT_IDS = 3
|
20
|
+
number | undefined
|
21
|
+
];
|
22
|
+
export declare enum ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX {
|
23
|
+
SPOT_ID = 0,
|
24
|
+
SPOT_TYPE = 1,
|
25
|
+
EVENTS = 2,
|
26
|
+
PRODUCT_IDS = 3,
|
27
|
+
CREATED_AT = 4
|
28
|
+
}
|
29
|
+
export type LocalStorageSpotsArrayType = Record<string, // spotId
|
30
|
+
LocalStorageSpotArray>;
|
14
31
|
export declare class LocalStorage {
|
15
32
|
private spots?;
|
16
33
|
private static instance;
|
@@ -22,10 +39,12 @@ export declare class LocalStorage {
|
|
22
39
|
setSpot(spotId: string, data: ILocalStorageSpot): void;
|
23
40
|
removeSpot(spotId: string): void;
|
24
41
|
getSpot(spotId: string): ILocalStorageSpot | undefined;
|
25
|
-
getSpots():
|
42
|
+
getSpots(): LocalStorageSpotsObjectType | undefined;
|
26
43
|
private updateLocalStorage;
|
27
44
|
private clearLocalStorage;
|
28
45
|
private removeExpiredSpots;
|
29
|
-
private
|
30
|
-
private
|
46
|
+
private mapToObject;
|
47
|
+
private objectToMap;
|
48
|
+
private objectToArray;
|
49
|
+
private arrayToObject;
|
31
50
|
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { RMN_SPOT_EVENT } from 'enums';
|
2
|
+
export interface IExtractIdsProps {
|
3
|
+
id?: string | number;
|
4
|
+
upc?: string | number;
|
5
|
+
[key: string]: string | number | undefined;
|
6
|
+
}
|
7
|
+
export declare function getEventTypeFromRawEvent(event?: string): RMN_SPOT_EVENT | null;
|
8
|
+
/**
|
9
|
+
* Recursively extracts ID values from a nested data structure.
|
10
|
+
* Searches for specified property names and collects their primitive values (strings/numbers).
|
11
|
+
*
|
12
|
+
* @param data - The data structure to search through (can be nested objects/arrays)
|
13
|
+
* @param propertyNames - Array of property names to look for (defaults to ['id', 'upc', 'groupingId', 'sku', 'productId'])
|
14
|
+
* @returns Array of extracted ID values (strings/numbers only)
|
15
|
+
*
|
16
|
+
* @example
|
17
|
+
* const data = {
|
18
|
+
* id: [1, 2, 3],
|
19
|
+
* nested: { id: 'abc' },
|
20
|
+
* items: [{ id: 456 }]
|
21
|
+
* };
|
22
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
23
|
+
*/
|
24
|
+
export declare function extractDeepIds(data: any, propertyNames?: readonly string[]): Array<string | number>;
|
@@ -10,11 +10,11 @@ export type PubSubUnsubscribe = () => void;
|
|
10
10
|
/**
|
11
11
|
* PubSub class
|
12
12
|
* Manages event subscriptions and publications
|
13
|
-
* @template
|
13
|
+
* @template IRmnEventMap A record type defining the structure of events and their data
|
14
14
|
*/
|
15
|
-
export declare class PubSub<
|
15
|
+
export declare class PubSub<IRmnEventMap> {
|
16
16
|
private static instance;
|
17
|
-
static getInstance<
|
17
|
+
static getInstance<IRmnEventMap>(): PubSub<IRmnEventMap>;
|
18
18
|
/**
|
19
19
|
* Object to store subscribers for each event type
|
20
20
|
*/
|
@@ -30,7 +30,7 @@ export declare class PubSub<IEventMap> {
|
|
30
30
|
* console.log(`User ${data.username} logged in`);
|
31
31
|
* });
|
32
32
|
*/
|
33
|
-
subscribe<K extends keyof
|
33
|
+
subscribe<K extends keyof IRmnEventMap>(eventType: K, callback: PubSubCallback<IRmnEventMap[K]>): PubSubUnsubscribe;
|
34
34
|
/**
|
35
35
|
* Publish an event
|
36
36
|
* @param eventType - The type of event to publish
|
@@ -39,17 +39,17 @@ export declare class PubSub<IEventMap> {
|
|
39
39
|
* @Example:
|
40
40
|
* pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
|
41
41
|
*/
|
42
|
-
publish<K extends keyof
|
42
|
+
publish<K extends keyof IRmnEventMap>(eventType: K, data: IRmnEventMap[K]): void;
|
43
43
|
}
|
44
44
|
/**
|
45
45
|
* Usage Example:
|
46
46
|
*
|
47
|
-
* interface
|
47
|
+
* interface IRmnEventMap {
|
48
48
|
* userLogin: { username: string; timestamp: number };
|
49
49
|
* pageView: { url: string; timestamp: number };
|
50
50
|
* }
|
51
51
|
*
|
52
|
-
* const pubSub = new PubSub<
|
52
|
+
* const pubSub = new PubSub<IRmnEventMap>();
|
53
53
|
*
|
54
54
|
* // Subscribe to events
|
55
55
|
* const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
|