@liquidcommercedev/rmn-sdk 1.5.0-beta.12 → 1.5.0-beta.14
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +343 -120
- package/dist/index.esm.js +343 -120
- package/dist/types/common/helpers/utils.helper.d.ts +5 -4
- package/dist/types/modules/element/component/skeleton/index.d.ts +2 -0
- package/dist/types/modules/element/component/skeleton/skeleton.component.d.ts +3 -0
- package/dist/types/modules/element/component/skeleton/skeleton.interface.d.ts +13 -0
- package/dist/types/modules/element/component/skeleton/skeleton.template.d.ts +2 -0
- package/dist/types/modules/element/element.constant.d.ts +3 -0
- package/dist/types/modules/element/element.service.d.ts +11 -0
- package/dist/types/modules/monitor/monitor.interface.d.ts +4 -0
- package/dist/types/rmn-client.d.ts +24 -9
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.esm.js
CHANGED
@@ -6864,40 +6864,60 @@ class ObjectHelper {
|
|
6864
6864
|
/**
|
6865
6865
|
* Recursively extracts ID values from a nested data structure.
|
6866
6866
|
* Searches for specified property names and collects their primitive values (strings/numbers).
|
6867
|
+
* Captures properties ending with 'id' and any additional specified property names.
|
6867
6868
|
*
|
6868
6869
|
* @param data - The data structure to search through (can be nested objects/arrays)
|
6869
|
-
* @param propertyNames - Array of property names to look for
|
6870
|
+
* @param propertyNames - Array of additional property names to look for (optional)
|
6870
6871
|
* @returns Array of extracted ID values (strings/numbers only)
|
6871
6872
|
*
|
6872
6873
|
* @example
|
6873
6874
|
* const data = {
|
6874
6875
|
* id: [1, 2, 3],
|
6875
|
-
* nested: { id: 'abc' },
|
6876
|
-
* items: [{ id: 456 }]
|
6876
|
+
* nested: { id: 'abc', userId: 123 },
|
6877
|
+
* items: [{ id: 456, productId: '789', sku: 'ABC123' }]
|
6877
6878
|
* };
|
6878
|
-
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
6879
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 123, 456, '789', 'ABC123']
|
6879
6880
|
*/
|
6880
6881
|
function extractDeepIds(data, propertyNames) {
|
6881
6882
|
const ids = [];
|
6882
|
-
const
|
6883
|
-
|
6884
|
-
'
|
6885
|
-
'
|
6886
|
-
'
|
6887
|
-
'
|
6888
|
-
'
|
6889
|
-
'
|
6890
|
-
'
|
6891
|
-
'
|
6883
|
+
const defaultPropertyNames = [
|
6884
|
+
// Universal product identifiers
|
6885
|
+
'gtin', // Global Trade Item Number
|
6886
|
+
'gtin8', // 8-digit GTIN
|
6887
|
+
'gtin12', // 12-digit GTIN (UPC)
|
6888
|
+
'gtin13', // 13-digit GTIN (EAN)
|
6889
|
+
'gtin14', // 14-digit GTIN
|
6890
|
+
'mpn', // Manufacturer Part Number
|
6891
|
+
'sku', // Stock Keeping Unit
|
6892
|
+
'upc', // Universal Product Code
|
6893
|
+
'ean', // European Article Number
|
6894
|
+
'isbn', // International Standard Book Number
|
6895
|
+
'isbn10', // 10-digit ISBN
|
6896
|
+
'isbn13', // 13-digit ISBN
|
6897
|
+
'asin', // Amazon Standard Identification Number
|
6898
|
+
// Product codes and references
|
6899
|
+
'coupon',
|
6900
|
+
'barcode',
|
6901
|
+
'product_code',
|
6902
|
+
'part_number',
|
6892
6903
|
'model_number',
|
6893
|
-
'
|
6894
|
-
'variant_id',
|
6904
|
+
'item_variant',
|
6895
6905
|
'item_number',
|
6896
|
-
'
|
6897
|
-
'
|
6906
|
+
'article_number',
|
6907
|
+
'reference',
|
6908
|
+
'groupingId',
|
6898
6909
|
];
|
6899
|
-
//
|
6900
|
-
const
|
6910
|
+
// Convert property names to lowercase for consistent comparison
|
6911
|
+
const additionalProperties = new Set((defaultPropertyNames).map((name) => name.toLowerCase()));
|
6912
|
+
/**
|
6913
|
+
* Checks if a property name is an ID field
|
6914
|
+
* @param key - The property name to check
|
6915
|
+
* @returns boolean indicating if the key is an ID field
|
6916
|
+
*/
|
6917
|
+
const isIdField = (key) => {
|
6918
|
+
const lowercaseKey = key.toLowerCase();
|
6919
|
+
return lowercaseKey.endsWith('id') || additionalProperties.has(lowercaseKey);
|
6920
|
+
};
|
6901
6921
|
/**
|
6902
6922
|
* Processes a value and extracts IDs if it matches criteria
|
6903
6923
|
* @param value - The value to process
|
@@ -6908,7 +6928,7 @@ function extractDeepIds(data, propertyNames) {
|
|
6908
6928
|
if (value == null)
|
6909
6929
|
return;
|
6910
6930
|
// If current key matches our target properties
|
6911
|
-
if (currentKey &&
|
6931
|
+
if (currentKey && isIdField(currentKey)) {
|
6912
6932
|
if (Array.isArray(value)) {
|
6913
6933
|
// Filter and push valid array values in one pass
|
6914
6934
|
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
@@ -6930,7 +6950,7 @@ function extractDeepIds(data, propertyNames) {
|
|
6930
6950
|
}
|
6931
6951
|
};
|
6932
6952
|
processValue(data);
|
6933
|
-
return ids;
|
6953
|
+
return ids;
|
6934
6954
|
}
|
6935
6955
|
// Fallback method using fetch if sendBeacon isn't available
|
6936
6956
|
async function fallbackEventFire(url) {
|
@@ -16123,6 +16143,7 @@ class AuthService extends BaseApi {
|
|
16123
16143
|
|
16124
16144
|
const SPOT_ELEMENT_TAG = 'spot-element';
|
16125
16145
|
const CAROUSEL_ELEMENT_TAG = 'spot-carousel-element';
|
16146
|
+
const SKELETON_ELEMENT_TAG = 'spot-skeleton-element';
|
16126
16147
|
const GFONT_PRECONNECT = `
|
16127
16148
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
16128
16149
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
@@ -16133,6 +16154,45 @@ const GFONT_SOURCE_SANS_3 = `
|
|
16133
16154
|
const GFONT_CORMORANT = `
|
16134
16155
|
<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">
|
16135
16156
|
`;
|
16157
|
+
const SPOT_DIMENSIONS = {
|
16158
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO]: { width: 1140, height: 640 },
|
16159
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE]: { width: 1140, height: 640 },
|
16160
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE]: { width: 1140, height: 640 },
|
16161
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE]: { width: 1140, height: 640 },
|
16162
|
+
[RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT]: { width: 468, height: 410 },
|
16163
|
+
[RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT]: { width: 224, height: 378 },
|
16164
|
+
[RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT]: { width: 224, height: 410 },
|
16165
|
+
[RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK]: { width: 887, height: 344 },
|
16166
|
+
[RMN_SPOT_TYPE.RB_PRODUCT_UPCS]: { width: 1, height: 1 },
|
16167
|
+
[RMN_SPOT_TYPE.RB_NAVIGATION_BANNER]: { width: 440, height: 220 },
|
16168
|
+
[RMN_SPOT_TYPE.SMALL_RECTANGLE]: { width: 180, height: 150 },
|
16169
|
+
[RMN_SPOT_TYPE.MEDIUM_RECTANGLE]: { width: 300, height: 250 },
|
16170
|
+
[RMN_SPOT_TYPE.LARGE_RECTANGLE]: { width: 336, height: 280 },
|
16171
|
+
[RMN_SPOT_TYPE.VERTICAL_RECTANGLE]: { width: 240, height: 400 },
|
16172
|
+
[RMN_SPOT_TYPE.BANNER]: { width: 468, height: 60 },
|
16173
|
+
[RMN_SPOT_TYPE.LEADERBOARD]: { width: 728, height: 90 },
|
16174
|
+
[RMN_SPOT_TYPE.LARGE_LEADERBOARD]: { width: 970, height: 90 },
|
16175
|
+
[RMN_SPOT_TYPE.BILLBOARD]: { width: 970, height: 250 },
|
16176
|
+
[RMN_SPOT_TYPE.SKYSCRAPER]: { width: 120, height: 600 },
|
16177
|
+
[RMN_SPOT_TYPE.WIDE_SKYSCRAPER]: { width: 160, height: 600 },
|
16178
|
+
[RMN_SPOT_TYPE.HALF_PAGE]: { width: 300, height: 600 },
|
16179
|
+
[RMN_SPOT_TYPE.SMALL_SQUARE]: { width: 200, height: 200 },
|
16180
|
+
[RMN_SPOT_TYPE.SQUARE]: { width: 250, height: 250 },
|
16181
|
+
[RMN_SPOT_TYPE.VERTICAL_BANNER]: { width: 120, height: 240 },
|
16182
|
+
[RMN_SPOT_TYPE.BUTTON_2]: { width: 120, height: 60 },
|
16183
|
+
[RMN_SPOT_TYPE.MICRO_BAR]: { width: 88, height: 31 },
|
16184
|
+
[RMN_SPOT_TYPE.POP_UP]: { width: 550, height: 480 },
|
16185
|
+
[RMN_SPOT_TYPE.PORTRAIT]: { width: 300, height: 1050 },
|
16186
|
+
[RMN_SPOT_TYPE.SMARTPHONE_BANNER_1]: { width: 300, height: 50 },
|
16187
|
+
[RMN_SPOT_TYPE.SMARTPHONE_BANNER_2]: { width: 320, height: 50 },
|
16188
|
+
[RMN_SPOT_TYPE.MOBILE_PHONE_INTERSTITIAL_1]: { width: 640, height: 1136 },
|
16189
|
+
[RMN_SPOT_TYPE.MOBILE_PHONE_INTERSTITIAL_2]: { width: 750, height: 1334 },
|
16190
|
+
[RMN_SPOT_TYPE.MOBILE_PHONE_INTERSTITIAL_3]: { width: 1080, height: 1920 },
|
16191
|
+
[RMN_SPOT_TYPE.FEATURE_PHONE_SMALL_BANNER]: { width: 120, height: 20 },
|
16192
|
+
[RMN_SPOT_TYPE.FEATURE_PHONE_MEDIUM_BANNER]: { width: 168, height: 28 },
|
16193
|
+
[RMN_SPOT_TYPE.FEATURE_PHONE_LARGE_BANNER]: { width: 216, height: 36 },
|
16194
|
+
[RMN_SPOT_TYPE.IN_TEXT]: { width: 1, height: 1 },
|
16195
|
+
};
|
16136
16196
|
|
16137
16197
|
class IntersectionObserverService {
|
16138
16198
|
constructor(defaultOptions = {}) {
|
@@ -16971,6 +17031,118 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
16971
17031
|
CarouselElement = CustomCarouselElement;
|
16972
17032
|
}
|
16973
17033
|
|
17034
|
+
function SkeletonTemplate({ fluid, width, height }) {
|
17035
|
+
return `
|
17036
|
+
<style>
|
17037
|
+
:host {
|
17038
|
+
display: block;
|
17039
|
+
position: relative;
|
17040
|
+
box-sizing: border-box;
|
17041
|
+
overflow: hidden;
|
17042
|
+
width: ${fluid ? '100%' : `${width}px`};
|
17043
|
+
height: ${fluid ? '100%' : `${height}px`};
|
17044
|
+
background: #ffffff;
|
17045
|
+
padding: 20px;
|
17046
|
+
border-radius: 5px;
|
17047
|
+
}
|
17048
|
+
|
17049
|
+
.content {
|
17050
|
+
height: 100%;
|
17051
|
+
display: flex;
|
17052
|
+
flex-direction: column;
|
17053
|
+
gap: 20px;
|
17054
|
+
}
|
17055
|
+
|
17056
|
+
.image-placeholder {
|
17057
|
+
width: 100%;
|
17058
|
+
height: 100%;
|
17059
|
+
background: #f0f0f0;
|
17060
|
+
border-radius: 4px;
|
17061
|
+
position: relative;
|
17062
|
+
overflow: hidden;
|
17063
|
+
}
|
17064
|
+
|
17065
|
+
.lines-container {
|
17066
|
+
display: flex;
|
17067
|
+
flex-direction: column;
|
17068
|
+
justify-content: flex-end;
|
17069
|
+
}
|
17070
|
+
|
17071
|
+
.line {
|
17072
|
+
height: 20px;
|
17073
|
+
background: #f0f0f0;
|
17074
|
+
border-radius: 4px;
|
17075
|
+
margin-bottom: 15px;
|
17076
|
+
position: relative;
|
17077
|
+
overflow: hidden;
|
17078
|
+
}
|
17079
|
+
|
17080
|
+
.image-placeholder::after,
|
17081
|
+
.line::after {
|
17082
|
+
content: "";
|
17083
|
+
position: absolute;
|
17084
|
+
top: 0;
|
17085
|
+
left: 0;
|
17086
|
+
width: 100%;
|
17087
|
+
height: 100%;
|
17088
|
+
background: linear-gradient(
|
17089
|
+
90deg,
|
17090
|
+
rgba(255, 255, 255, 0) 0%,
|
17091
|
+
rgba(255, 255, 255, 0.5) 50%,
|
17092
|
+
rgba(255, 255, 255, 0) 100%
|
17093
|
+
);
|
17094
|
+
animation: shimmer 1.5s infinite;
|
17095
|
+
}
|
17096
|
+
|
17097
|
+
.line.header {
|
17098
|
+
width: 25%;
|
17099
|
+
}
|
17100
|
+
|
17101
|
+
.line.description {
|
17102
|
+
width: 65%;
|
17103
|
+
}
|
17104
|
+
|
17105
|
+
.line.button {
|
17106
|
+
width: 40%;
|
17107
|
+
}
|
17108
|
+
|
17109
|
+
@keyframes shimmer {
|
17110
|
+
0% {
|
17111
|
+
transform: translateX(-100%);
|
17112
|
+
}
|
17113
|
+
100% {
|
17114
|
+
transform: translateX(100%);
|
17115
|
+
}
|
17116
|
+
}
|
17117
|
+
</style>
|
17118
|
+
|
17119
|
+
<div class="content">
|
17120
|
+
<div class="image-placeholder"></div>
|
17121
|
+
<div class="lines-container">
|
17122
|
+
<div class="line header"></div>
|
17123
|
+
<div class="line description"></div>
|
17124
|
+
<div class="line button"></div>
|
17125
|
+
</div>
|
17126
|
+
</div>
|
17127
|
+
`;
|
17128
|
+
}
|
17129
|
+
|
17130
|
+
let SkeletonElement;
|
17131
|
+
if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
|
17132
|
+
class CustomSkeletonElement extends HTMLElement {
|
17133
|
+
constructor() {
|
17134
|
+
super();
|
17135
|
+
this.attachShadow({ mode: 'open' });
|
17136
|
+
}
|
17137
|
+
connectedCallback() {
|
17138
|
+
if (!this.shadowRoot || !this.data)
|
17139
|
+
return;
|
17140
|
+
this.shadowRoot.innerHTML = SkeletonTemplate(this.data);
|
17141
|
+
}
|
17142
|
+
}
|
17143
|
+
SkeletonElement = CustomSkeletonElement;
|
17144
|
+
}
|
17145
|
+
|
16974
17146
|
let SpotElement;
|
16975
17147
|
if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
|
16976
17148
|
class CustomSpotElement extends HTMLElement {
|
@@ -17078,15 +17250,14 @@ class ElementService {
|
|
17078
17250
|
* @return {HTMLElement | null} - The html element or null if the browser environment is not available.
|
17079
17251
|
*/
|
17080
17252
|
createSpotElement({ content, config }) {
|
17081
|
-
var _a
|
17253
|
+
var _a;
|
17082
17254
|
if (!this.ensureBrowserEnvironmentAndDefineElement()) {
|
17083
17255
|
return null;
|
17084
17256
|
}
|
17085
17257
|
const spot = document.createElement(SPOT_ELEMENT_TAG);
|
17086
|
-
spot.setAttribute('type', (_a = config === null || config === void 0 ? void 0 : config.spot) !== null && _a !== void 0 ? _a : '');
|
17087
17258
|
spot.data = {
|
17088
17259
|
spot: config === null || config === void 0 ? void 0 : config.spot,
|
17089
|
-
fluid: (
|
17260
|
+
fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
|
17090
17261
|
...config,
|
17091
17262
|
};
|
17092
17263
|
spot.content = content;
|
@@ -17114,6 +17285,27 @@ class ElementService {
|
|
17114
17285
|
carousel.slides = slides;
|
17115
17286
|
return carousel;
|
17116
17287
|
}
|
17288
|
+
/**
|
17289
|
+
* Creates the skeleton html element based on the provided data using shadow dom.
|
17290
|
+
*
|
17291
|
+
* This method is only available in browser environments.
|
17292
|
+
*
|
17293
|
+
* @param {ICreateSkeletonElementParams} params - The parameters to create the final element.
|
17294
|
+
*
|
17295
|
+
* @return {HTMLElement | null} - The html element or null if the browser environment is not available.
|
17296
|
+
*/
|
17297
|
+
createSkeletonElement(params) {
|
17298
|
+
if (!this.ensureBrowserEnvironmentAndDefineElement()) {
|
17299
|
+
return null;
|
17300
|
+
}
|
17301
|
+
const skeleton = document.createElement(SKELETON_ELEMENT_TAG);
|
17302
|
+
const dimensions = SPOT_DIMENSIONS[params.spotType];
|
17303
|
+
skeleton.data = {
|
17304
|
+
fluid: params.fluid,
|
17305
|
+
...dimensions,
|
17306
|
+
};
|
17307
|
+
return skeleton;
|
17308
|
+
}
|
17117
17309
|
/**
|
17118
17310
|
* Overrides the spot colors with the provided colors.
|
17119
17311
|
*
|
@@ -17148,6 +17340,9 @@ class ElementService {
|
|
17148
17340
|
if (!window.customElements.get(CAROUSEL_ELEMENT_TAG)) {
|
17149
17341
|
window.customElements.define(CAROUSEL_ELEMENT_TAG, CarouselElement);
|
17150
17342
|
}
|
17343
|
+
if (!window.customElements.get(SKELETON_ELEMENT_TAG)) {
|
17344
|
+
window.customElements.define(SKELETON_ELEMENT_TAG, SkeletonElement);
|
17345
|
+
}
|
17151
17346
|
return true;
|
17152
17347
|
}
|
17153
17348
|
}
|
@@ -18984,7 +19179,7 @@ class DataLayerMonitor {
|
|
18984
19179
|
if (!eventName) {
|
18985
19180
|
return null;
|
18986
19181
|
}
|
18987
|
-
const productIds = extractDeepIds(data
|
19182
|
+
const productIds = extractDeepIds(data);
|
18988
19183
|
return {
|
18989
19184
|
event: eventName,
|
18990
19185
|
productIds,
|
@@ -19293,6 +19488,7 @@ class LiquidCommerceRmnClient {
|
|
19293
19488
|
this.selectionService = SelectionService.getInstance(auth);
|
19294
19489
|
this.elementService = ElementService.getInstance();
|
19295
19490
|
this.eventService = EventService.getInstance();
|
19491
|
+
this.intersectionObserver = new IntersectionObserverService();
|
19296
19492
|
}
|
19297
19493
|
/**
|
19298
19494
|
* Makes a selection request on our server based on the provided data.
|
@@ -19316,24 +19512,29 @@ class LiquidCommerceRmnClient {
|
|
19316
19512
|
async injectSpotElement(params) {
|
19317
19513
|
var _a;
|
19318
19514
|
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
19319
|
-
console.warn('LiquidCommerce Rmn Sdk:
|
19515
|
+
console.warn('LiquidCommerce Rmn Sdk: injectSpotElement method is only available in the browser environment.');
|
19320
19516
|
return;
|
19321
19517
|
}
|
19322
19518
|
const config = params.config;
|
19323
19519
|
let inject = params.inject;
|
19520
|
+
// Handle no spots error state
|
19324
19521
|
if (!inject.length) {
|
19325
|
-
// Handle no spots error state
|
19326
19522
|
this.eventService.handleSpotState('all', {
|
19327
19523
|
state: {
|
19328
19524
|
error: 'No spot elements provided for injection.',
|
19329
|
-
loading: false,
|
19330
|
-
mounted: false,
|
19331
19525
|
},
|
19332
19526
|
});
|
19333
19527
|
return;
|
19334
19528
|
}
|
19335
|
-
//
|
19336
|
-
|
19529
|
+
// Identify the spot elements
|
19530
|
+
for (const item of inject) {
|
19531
|
+
this.eventService.handleSpotState(item.placementId, {
|
19532
|
+
identifier: {
|
19533
|
+
placementId: item.placementId,
|
19534
|
+
spotType: item.spotType,
|
19535
|
+
},
|
19536
|
+
}, false);
|
19537
|
+
}
|
19337
19538
|
// Prevent duplicate placement ids
|
19338
19539
|
const hasDuplicatePlacementIds = this.preventDuplicateSpotPlacementIds(inject);
|
19339
19540
|
if (!hasDuplicatePlacementIds) {
|
@@ -19341,35 +19542,9 @@ class LiquidCommerceRmnClient {
|
|
19341
19542
|
}
|
19342
19543
|
// Prevent non-existent spot types
|
19343
19544
|
inject = this.preventNonExistentSpotTypes(inject);
|
19344
|
-
//
|
19345
|
-
|
19346
|
-
// const response = await this.useSpotSelectionExample(inject);
|
19347
|
-
// Handle the response
|
19348
|
-
if (typeof response === 'object' && 'error' in response) {
|
19349
|
-
// Handle request error state
|
19350
|
-
this.eventService.handleSpotState('all', {
|
19351
|
-
state: {
|
19352
|
-
error: response.error,
|
19353
|
-
mounted: false,
|
19354
|
-
loading: false,
|
19355
|
-
},
|
19356
|
-
});
|
19357
|
-
return;
|
19358
|
-
}
|
19545
|
+
// Add Intersection Observer to the spot elements to track visibility
|
19546
|
+
// This is useful for lazy loading the spot elements
|
19359
19547
|
for (const item of inject) {
|
19360
|
-
const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
|
19361
|
-
const spots = response[item.placementId];
|
19362
|
-
if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
|
19363
|
-
// Handle no spots found error state
|
19364
|
-
this.eventService.handleSpotState(item.placementId, {
|
19365
|
-
state: {
|
19366
|
-
error: `No spots found for type "${item.spotType}".`,
|
19367
|
-
mounted: false,
|
19368
|
-
loading: false,
|
19369
|
-
},
|
19370
|
-
});
|
19371
|
-
continue;
|
19372
|
-
}
|
19373
19548
|
const placementId = item.placementId.replace('#', '');
|
19374
19549
|
const placement = document.getElementById(placementId);
|
19375
19550
|
if (!placement) {
|
@@ -19377,8 +19552,6 @@ class LiquidCommerceRmnClient {
|
|
19377
19552
|
this.eventService.handleSpotState(item.placementId, {
|
19378
19553
|
state: {
|
19379
19554
|
error: `Placement not found for id "${placementId}".`,
|
19380
|
-
mounted: false,
|
19381
|
-
loading: false,
|
19382
19555
|
},
|
19383
19556
|
});
|
19384
19557
|
continue;
|
@@ -19392,43 +19565,73 @@ class LiquidCommerceRmnClient {
|
|
19392
19565
|
display: 'flex',
|
19393
19566
|
justifyContent: 'center',
|
19394
19567
|
});
|
19395
|
-
|
19396
|
-
|
19397
|
-
|
19398
|
-
|
19399
|
-
|
19400
|
-
|
19568
|
+
const skeletonElement = this.elementService.createSkeletonElement({
|
19569
|
+
fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
|
19570
|
+
spotType: item.spotType,
|
19571
|
+
});
|
19572
|
+
if (!skeletonElement) {
|
19573
|
+
this.eventService.handleSpotState(item.placementId, {
|
19574
|
+
state: {
|
19575
|
+
error: `Failed to create skeleton loader element.`,
|
19576
|
+
mounted: false,
|
19577
|
+
loading: true,
|
19578
|
+
},
|
19579
|
+
});
|
19580
|
+
continue;
|
19401
19581
|
}
|
19402
|
-
|
19403
|
-
|
19404
|
-
|
19405
|
-
|
19406
|
-
|
19582
|
+
placement.replaceChildren(skeletonElement);
|
19583
|
+
const spotPlacementIsNear = async () => {
|
19584
|
+
var _a;
|
19585
|
+
// Set the spot element to loading state
|
19586
|
+
this.eventService.handleSpotState(item.placementId, {
|
19587
|
+
state: {
|
19588
|
+
loading: true,
|
19589
|
+
},
|
19590
|
+
});
|
19591
|
+
// Stop observing the placement
|
19592
|
+
this.intersectionObserver.unobserve(placement);
|
19593
|
+
// Make the spot selection request
|
19594
|
+
const response = await this.spotSelectionRequest({ ...params, inject: [item] });
|
19595
|
+
// const response = await this.useSpotSelectionExample(inject);
|
19596
|
+
// Handle request error state
|
19597
|
+
if (typeof response === 'object' && 'error' in response) {
|
19598
|
+
this.eventService.handleSpotState(item.placementId, {
|
19599
|
+
state: {
|
19600
|
+
error: response.error,
|
19601
|
+
mounted: false,
|
19602
|
+
loading: false,
|
19603
|
+
},
|
19604
|
+
});
|
19605
|
+
this.clearPlacement(item.placementId);
|
19606
|
+
return;
|
19407
19607
|
}
|
19408
|
-
|
19608
|
+
const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
|
19609
|
+
const spots = response[item.placementId];
|
19610
|
+
if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
|
19611
|
+
// Handle no spots found error state
|
19612
|
+
this.eventService.handleSpotState(item.placementId, {
|
19613
|
+
state: {
|
19614
|
+
error: `No spots found for type "${item.spotType}".`,
|
19615
|
+
mounted: false,
|
19616
|
+
loading: false,
|
19617
|
+
},
|
19618
|
+
});
|
19619
|
+
this.clearPlacement(item.placementId);
|
19620
|
+
return;
|
19621
|
+
}
|
19622
|
+
// Handle single spot
|
19623
|
+
if (spots.length === 1) {
|
19624
|
+
this.injectOneSpotElement(item, placement, spots[0], itemConfig);
|
19625
|
+
}
|
19626
|
+
// Handle multiple spots (carousel)
|
19627
|
+
if (spots.length > 1) {
|
19628
|
+
this.injectCarouselSpotElement(placement, spots, itemConfig);
|
19629
|
+
}
|
19630
|
+
};
|
19631
|
+
this.intersectionObserver.observe(placement, spotPlacementIsNear, { rootMargin: '500px' });
|
19409
19632
|
}
|
19410
19633
|
}
|
19411
|
-
/**
|
19412
|
-
* Makes a selection request on our server based on the provided data.
|
19413
|
-
*
|
19414
|
-
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
19415
|
-
*
|
19416
|
-
* @return {Promise<ISpots | {error: string}>} - The spots response object.
|
19417
|
-
*/
|
19418
|
-
async spotSelectionRequest(params) {
|
19419
|
-
const { inject, filter, config } = params;
|
19420
|
-
const request = {
|
19421
|
-
url: config === null || config === void 0 ? void 0 : config.url,
|
19422
|
-
filter,
|
19423
|
-
spots: inject.map((item) => ({
|
19424
|
-
placementId: item.placementId,
|
19425
|
-
spot: item.spotType,
|
19426
|
-
count: item === null || item === void 0 ? void 0 : item.count,
|
19427
|
-
...item === null || item === void 0 ? void 0 : item.filter,
|
19428
|
-
})),
|
19429
|
-
};
|
19430
|
-
return this.spotSelection(request);
|
19431
|
-
}
|
19634
|
+
/** ========================= HELPER METHODS ========================= **/
|
19432
19635
|
/**
|
19433
19636
|
* Injects a carousel element with the provided spots into the placement.
|
19434
19637
|
*
|
@@ -19497,7 +19700,8 @@ class LiquidCommerceRmnClient {
|
|
19497
19700
|
loading: false,
|
19498
19701
|
},
|
19499
19702
|
});
|
19500
|
-
|
19703
|
+
this.clearPlacement(placement.id);
|
19704
|
+
return;
|
19501
19705
|
}
|
19502
19706
|
placement.replaceChildren(carouselElement);
|
19503
19707
|
this.eventService.handleSpotState(placement.id, {
|
@@ -19511,7 +19715,6 @@ class LiquidCommerceRmnClient {
|
|
19511
19715
|
error: undefined,
|
19512
19716
|
},
|
19513
19717
|
});
|
19514
|
-
return true;
|
19515
19718
|
}
|
19516
19719
|
/**
|
19517
19720
|
* Injects a single spot element into the provided placement.
|
@@ -19547,7 +19750,8 @@ class LiquidCommerceRmnClient {
|
|
19547
19750
|
loading: false,
|
19548
19751
|
},
|
19549
19752
|
});
|
19550
|
-
|
19753
|
+
this.clearPlacement(injectItem.placementId);
|
19754
|
+
return;
|
19551
19755
|
}
|
19552
19756
|
// Create the spot element
|
19553
19757
|
const spotElement = this.elementService.createSpotElement({
|
@@ -19568,7 +19772,8 @@ class LiquidCommerceRmnClient {
|
|
19568
19772
|
loading: false,
|
19569
19773
|
},
|
19570
19774
|
});
|
19571
|
-
|
19775
|
+
this.clearPlacement(injectItem.placementId);
|
19776
|
+
return;
|
19572
19777
|
}
|
19573
19778
|
this.eventService.registerSpot({
|
19574
19779
|
spot: spotData,
|
@@ -19587,7 +19792,38 @@ class LiquidCommerceRmnClient {
|
|
19587
19792
|
error: undefined,
|
19588
19793
|
},
|
19589
19794
|
});
|
19590
|
-
|
19795
|
+
}
|
19796
|
+
/**
|
19797
|
+
* Clears the placement element by removing all its children.
|
19798
|
+
*
|
19799
|
+
* @param {string} placementId - The placement id.
|
19800
|
+
*
|
19801
|
+
* @return {void}
|
19802
|
+
*/
|
19803
|
+
clearPlacement(placementId) {
|
19804
|
+
var _a;
|
19805
|
+
(_a = document.getElementById(placementId)) === null || _a === void 0 ? void 0 : _a.replaceChildren();
|
19806
|
+
}
|
19807
|
+
/**
|
19808
|
+
* Makes a selection request on our server based on the provided data.
|
19809
|
+
*
|
19810
|
+
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
19811
|
+
*
|
19812
|
+
* @return {Promise<ISpots | {error: string}>} - The spots response object.
|
19813
|
+
*/
|
19814
|
+
async spotSelectionRequest(params) {
|
19815
|
+
const { inject, filter, config } = params;
|
19816
|
+
const request = {
|
19817
|
+
url: config === null || config === void 0 ? void 0 : config.url,
|
19818
|
+
filter,
|
19819
|
+
spots: inject.map((item) => ({
|
19820
|
+
placementId: item.placementId,
|
19821
|
+
spot: item.spotType,
|
19822
|
+
count: item === null || item === void 0 ? void 0 : item.count,
|
19823
|
+
...item === null || item === void 0 ? void 0 : item.filter,
|
19824
|
+
})),
|
19825
|
+
};
|
19826
|
+
return this.spotSelection(request);
|
19591
19827
|
}
|
19592
19828
|
/**
|
19593
19829
|
* Prevents duplicate placement ids in the inject data.
|
@@ -19605,8 +19841,6 @@ class LiquidCommerceRmnClient {
|
|
19605
19841
|
this.eventService.handleSpotState(item.placementId, {
|
19606
19842
|
state: {
|
19607
19843
|
error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
|
19608
|
-
mounted: false,
|
19609
|
-
loading: false,
|
19610
19844
|
},
|
19611
19845
|
});
|
19612
19846
|
return false;
|
@@ -19615,6 +19849,12 @@ class LiquidCommerceRmnClient {
|
|
19615
19849
|
}
|
19616
19850
|
return true;
|
19617
19851
|
}
|
19852
|
+
/**
|
19853
|
+
* Prevents non-existent spot types in the inject data.
|
19854
|
+
*
|
19855
|
+
* @param {IInjectSpotElement[]} inject - The inject data.
|
19856
|
+
* @return {IInjectSpotElement[]} - The filtered inject data.
|
19857
|
+
*/
|
19618
19858
|
preventNonExistentSpotTypes(inject) {
|
19619
19859
|
const newInject = [];
|
19620
19860
|
for (const item of inject) {
|
@@ -19622,8 +19862,6 @@ class LiquidCommerceRmnClient {
|
|
19622
19862
|
this.eventService.handleSpotState(item.placementId, {
|
19623
19863
|
state: {
|
19624
19864
|
error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
|
19625
|
-
mounted: false,
|
19626
|
-
loading: false,
|
19627
19865
|
},
|
19628
19866
|
});
|
19629
19867
|
continue;
|
@@ -19632,22 +19870,7 @@ class LiquidCommerceRmnClient {
|
|
19632
19870
|
}
|
19633
19871
|
return newInject;
|
19634
19872
|
}
|
19635
|
-
//
|
19636
|
-
updateSpotsState(inject) {
|
19637
|
-
for (const item of inject) {
|
19638
|
-
this.eventService.handleSpotState(item.placementId, {
|
19639
|
-
identifier: {
|
19640
|
-
placementId: item.placementId,
|
19641
|
-
spotType: item.spotType,
|
19642
|
-
},
|
19643
|
-
state: {
|
19644
|
-
loading: true,
|
19645
|
-
mounted: false,
|
19646
|
-
error: undefined,
|
19647
|
-
},
|
19648
|
-
});
|
19649
|
-
}
|
19650
|
-
}
|
19873
|
+
// Use spot selection example data for private testing
|
19651
19874
|
useSpotSelectionExample(inject) {
|
19652
19875
|
const examples = { ...RB_SPOTS_SELECTION_EXAMPLE, ...IAB_SPOTS_SELECTION_EXAMPLE };
|
19653
19876
|
const data = {};
|
@@ -2,18 +2,19 @@ import type { IFireEventParams } from 'modules/event';
|
|
2
2
|
/**
|
3
3
|
* Recursively extracts ID values from a nested data structure.
|
4
4
|
* Searches for specified property names and collects their primitive values (strings/numbers).
|
5
|
+
* Captures properties ending with 'id' and any additional specified property names.
|
5
6
|
*
|
6
7
|
* @param data - The data structure to search through (can be nested objects/arrays)
|
7
|
-
* @param propertyNames - Array of property names to look for
|
8
|
+
* @param propertyNames - Array of additional property names to look for (optional)
|
8
9
|
* @returns Array of extracted ID values (strings/numbers only)
|
9
10
|
*
|
10
11
|
* @example
|
11
12
|
* const data = {
|
12
13
|
* id: [1, 2, 3],
|
13
|
-
* nested: { id: 'abc' },
|
14
|
-
* items: [{ id: 456 }]
|
14
|
+
* nested: { id: 'abc', userId: 123 },
|
15
|
+
* items: [{ id: 456, productId: '789', sku: 'ABC123' }]
|
15
16
|
* };
|
16
|
-
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
|
17
|
+
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 123, 456, '789', 'ABC123']
|
17
18
|
*/
|
18
19
|
export declare function extractDeepIds(data: any, propertyNames?: string[]): Array<string | number>;
|
19
20
|
export declare function fallbackEventFire(url: string): Promise<boolean>;
|