@liquidcommercedev/rmn-sdk 1.5.0-beta.12 → 1.5.0-beta.14

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.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 defaulPropertyNames = [
6883
- 'id',
6884
- 'upc',
6885
- 'groupingId',
6886
- 'sku',
6887
- 'productId',
6888
- 'item_id',
6889
- 'isbn',
6890
- 'asin',
6891
- 'mpn',
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
- 'article_number',
6894
- 'variant_id',
6904
+ 'item_variant',
6895
6905
  'item_number',
6896
- 'catalog_id',
6897
- 'reference_id',
6906
+ 'article_number',
6907
+ 'reference',
6908
+ 'groupingId',
6898
6909
  ];
6899
- // Set for faster property name lookups
6900
- const propertySet = new Set(defaulPropertyNames);
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 && propertySet.has(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; // No need to filter nulls as we handle that during collection
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, _b;
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: (_b = config === null || config === void 0 ? void 0 : config.fluid) !== null && _b !== void 0 ? _b : false,
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.value);
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: Methods which create elements are only available in browser environments.');
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
- // Update the state of the spots to loading
19336
- this.updateSpotsState(inject);
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
- // Make the spot selection request
19345
- const response = await this.spotSelectionRequest({ ...params, inject });
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
- // Handle single spot
19396
- if (spots.length === 1) {
19397
- const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
19398
- if (!isInjected) {
19399
- continue;
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
- // Handle multiple spots (carousel)
19403
- if (spots.length > 1) {
19404
- const isInjected = this.injectCarouselSpotElement(placement, spots, itemConfig);
19405
- if (!isInjected) {
19406
- continue;
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
- return false;
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
- return false;
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
- return false;
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
- return true;
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
- // Initialize spots with loading state and identifiers
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>;