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