@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.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>;