@liquidcommercedev/rmn-sdk 1.4.6-beta.6 → 1.4.6-beta.8

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.cjs CHANGED
@@ -56,8 +56,7 @@ exports.RMN_FILTER_PROPERTIES = void 0;
56
56
  })(exports.RMN_FILTER_PROPERTIES || (exports.RMN_FILTER_PROPERTIES = {}));
57
57
  exports.RMN_SPOT_EVENT = void 0;
58
58
  (function (RMN_SPOT_EVENT) {
59
- RMN_SPOT_EVENT["MOUNTED"] = "MOUNTED";
60
- RMN_SPOT_EVENT["UNMOUNTED"] = "UNMOUNTED";
59
+ RMN_SPOT_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
61
60
  RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
62
61
  RMN_SPOT_EVENT["CLICK"] = "CLICK";
63
62
  RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
@@ -16827,11 +16826,11 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
16827
16826
  align-items: flex-start;
16828
16827
  width: 100%;
16829
16828
  height: fit-content;
16830
- gap: 5px;
16829
+ gap: 8px;
16831
16830
  }
16832
16831
 
16833
16832
  .${prefix}__header {
16834
- font-size: 18px;
16833
+ font-size: 24px;
16835
16834
  margin: 0;
16836
16835
  font-family: "Cormorant";
16837
16836
  font-style: normal;
@@ -16889,10 +16888,6 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
16889
16888
  height: 50%;
16890
16889
  }
16891
16890
 
16892
- .${prefix}__header {
16893
- font-size: 22px;
16894
- }
16895
-
16896
16891
  .${prefix}__description {
16897
16892
  font-size: 12px;
16898
16893
  }
@@ -16904,7 +16899,7 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
16904
16899
 
16905
16900
  @container (min-width: 1024px) {
16906
16901
  .${prefix}__header {
16907
- font-size: 24px;
16902
+ font-size: 26px;
16908
16903
  }
16909
16904
 
16910
16905
  .${prefix}__description {
@@ -16965,7 +16960,7 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16965
16960
  display: flex;
16966
16961
  flex-direction: column;
16967
16962
  background-color: transparent;
16968
- gap: 5px;
16963
+ gap: 6px;
16969
16964
  color: inherit;
16970
16965
  cursor: pointer;
16971
16966
  }
@@ -16984,7 +16979,7 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
16984
16979
  height: 40%;
16985
16980
  display: flex;
16986
16981
  flex-direction: row;
16987
- gap: 5px;
16982
+ gap: 6px;
16988
16983
  }
16989
16984
 
16990
16985
  .${prefix}__secondary-image {
@@ -17006,7 +17001,7 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
17006
17001
  align-items: center;
17007
17002
  width: 50%;
17008
17003
  height: 100%;
17009
- gap: 5px;
17004
+ gap: 10px;
17010
17005
  padding: 0 10px;
17011
17006
  box-sizing: border-box;
17012
17007
  }
@@ -17152,7 +17147,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
17152
17147
  display: flex;
17153
17148
  flex-direction: column-reverse;
17154
17149
  background-color: transparent;
17155
- gap: 5px;
17150
+ gap: 6px;
17156
17151
  cursor: pointer;
17157
17152
  container-type: inline-size;
17158
17153
  position: relative;
@@ -17177,7 +17172,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
17177
17172
  align-items: center;
17178
17173
  width: 100%;
17179
17174
  height: 100%;
17180
- gap: 5px;
17175
+ gap: 10px;
17181
17176
  padding: 0 10px;
17182
17177
  box-sizing: border-box;
17183
17178
  }
@@ -17787,6 +17782,7 @@ class EventService {
17787
17782
  constructor() {
17788
17783
  this.pubSub = new PubSub();
17789
17784
  this.activeSpots = new Map();
17785
+ this.spotStates = new Map();
17790
17786
  this.intersectionObserver = new IntersectionObserverService();
17791
17787
  }
17792
17788
  static getInstance() {
@@ -17795,6 +17791,46 @@ class EventService {
17795
17791
  }
17796
17792
  return EventService.instance;
17797
17793
  }
17794
+ subscribe(eventType, callback) {
17795
+ return this.pubSub.subscribe(eventType, callback);
17796
+ }
17797
+ publish(eventType, data) {
17798
+ this.pubSub.publish(eventType, data);
17799
+ }
17800
+ handleSpotState(placementId, updates, publish = true) {
17801
+ let currentState = this.spotStates.get(placementId);
17802
+ if (!currentState) {
17803
+ currentState = {
17804
+ identifier: {
17805
+ placementId,
17806
+ spotId: '',
17807
+ spotType: '',
17808
+ },
17809
+ dom: {
17810
+ element: undefined,
17811
+ visible: false,
17812
+ },
17813
+ state: {
17814
+ mounted: false,
17815
+ unmounted: false,
17816
+ loading: false,
17817
+ error: undefined,
17818
+ },
17819
+ displayConfig: {
17820
+ isCarousel: false,
17821
+ isCarouselItem: false,
17822
+ isSingleItem: false,
17823
+ },
17824
+ };
17825
+ }
17826
+ this.spotStates.set(placementId, {
17827
+ ...currentState,
17828
+ ...updates,
17829
+ });
17830
+ if (publish) {
17831
+ this.pubSub.publish(exports.RMN_SPOT_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
17832
+ }
17833
+ }
17798
17834
  registerSpot({ placementId, element, spot }) {
17799
17835
  this.activeSpots.set(spot.id, {
17800
17836
  placementId,
@@ -17817,23 +17853,20 @@ class EventService {
17817
17853
  eventUrl: (_b = (_a = spot.events.find((event) => event.event === exports.RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
17818
17854
  });
17819
17855
  });
17820
- // Publish spot created event
17821
- this.pubSub.publish(exports.RMN_SPOT_EVENT.MOUNTED, {
17822
- placementId,
17823
- spotId: spot.id,
17824
- spotType: spot.spot,
17825
- spotVariant: spot.variant,
17826
- element,
17827
- });
17828
17856
  }
17829
17857
  unregisterSpot(spotId) {
17830
17858
  const spotData = this.activeSpots.get(spotId);
17831
17859
  if (spotData) {
17832
17860
  this.intersectionObserver.unobserve(spotData.element);
17833
- // this.resizeObserver?.disconnect();
17834
- this.pubSub.publish(exports.RMN_SPOT_EVENT.UNMOUNTED, {
17835
- placementId: spotData.placementId,
17836
- spotId,
17861
+ this.handleSpotState(spotData.placementId, {
17862
+ dom: {
17863
+ element: undefined,
17864
+ visible: false,
17865
+ },
17866
+ state: {
17867
+ unmounted: true,
17868
+ mounted: false,
17869
+ },
17837
17870
  });
17838
17871
  this.activeSpots.delete(spotId);
17839
17872
  }
@@ -17852,6 +17885,12 @@ class EventService {
17852
17885
  element,
17853
17886
  impressionTracked: true,
17854
17887
  });
17888
+ this.handleSpotState(placementId, {
17889
+ dom: {
17890
+ element,
17891
+ visible: true,
17892
+ },
17893
+ });
17855
17894
  // Fire impression event
17856
17895
  await this.fireEvent({
17857
17896
  event: exports.RMN_SPOT_EVENT.IMPRESSION,
@@ -17860,12 +17899,6 @@ class EventService {
17860
17899
  };
17861
17900
  this.intersectionObserver.observe(element, spotIsVisibleCb);
17862
17901
  }
17863
- subscribe(eventType, callback) {
17864
- return this.pubSub.subscribe(eventType, callback);
17865
- }
17866
- publish(eventType, data) {
17867
- this.pubSub.publish(eventType, data);
17868
- }
17869
17902
  /**
17870
17903
  * Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
17871
17904
  *
@@ -17913,24 +17946,39 @@ class SelectionService extends BaseApi {
17913
17946
  *
17914
17947
  * @param {ISpotSelectionParams} data - Spots selection parameters.
17915
17948
  *
17916
- * @return {Promise<ISpots>} - The spots response object.
17949
+ * @return {Promise<ISpots | { error: string }>} - The spots response object.
17917
17950
  */
17918
17951
  async spotSelection(data) {
17919
17952
  const { isOk, val, isErr } = await this.post(SELECTION_API_PATH, data, {});
17920
17953
  if (isErr) {
17921
- throw new Error(`There was an error during spot selection: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})`);
17954
+ return { error: `There was an error during spot selection: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})` };
17922
17955
  }
17923
17956
  if (isOk && val && val.data && (val === null || val === void 0 ? void 0 : val.refresh.token)) {
17924
17957
  this.authInfo.authenticated = true;
17925
17958
  this.authInfo.token = val.refresh.token;
17926
17959
  return val.data.spots;
17927
17960
  }
17928
- throw new Error('Spot selection response was not successful');
17961
+ return { error: 'Spot selection response was not successful' };
17929
17962
  }
17930
17963
  }
17931
17964
 
17932
17965
  class LiquidCommerceRmnClient {
17933
17966
  constructor(auth) {
17967
+ /**
17968
+ * Returns the event manager instance.
17969
+ *
17970
+ * @return {EventService} - The event manager instance.
17971
+ */
17972
+ this.eventManager = {
17973
+ subscribe: (eventType, callback
17974
+ /* eslint-disable arrow-body-style */
17975
+ ) => {
17976
+ return this.eventService.subscribe(eventType, callback);
17977
+ },
17978
+ publish: (eventType, data) => {
17979
+ this.eventService.publish(eventType, data);
17980
+ },
17981
+ };
17934
17982
  this.selectionService = SelectionService.getInstance(auth);
17935
17983
  this.elementService = ElementService.getInstance();
17936
17984
  this.eventService = EventService.getInstance();
@@ -17942,7 +17990,7 @@ class LiquidCommerceRmnClient {
17942
17990
  *
17943
17991
  * @param {ISpotSelectionParams} params - Spots selection parameters.
17944
17992
  *
17945
- * @return {Promise<ISpots>} - The spots response object.
17993
+ * @return {Promise<ISpots | {error : string}>} - The spots response object.
17946
17994
  */
17947
17995
  async spotSelection(params) {
17948
17996
  return this.selectionService.spotSelection(params);
@@ -17956,60 +18004,94 @@ class LiquidCommerceRmnClient {
17956
18004
  */
17957
18005
  async injectSpotElement(params) {
17958
18006
  var _a;
17959
- const { inject, config } = params;
18007
+ const config = params.config;
18008
+ let inject = params.inject;
17960
18009
  if (!inject.length) {
17961
- console.warn('RmnSdk: Failed to inject spot element. Please provide at least one spot element to inject.');
18010
+ this.eventService.handleSpotState('all', {
18011
+ state: {
18012
+ error: 'No spot elements provided for injection.',
18013
+ loading: false,
18014
+ },
18015
+ });
18016
+ return;
18017
+ }
18018
+ // Update the state of the spots to loading
18019
+ this.updateSpotsState(inject);
18020
+ // Prevent duplicate placement ids
18021
+ const hasDuplicatePlacementIds = this.preventDuplicateSpotPlacementIds(inject);
18022
+ if (!hasDuplicatePlacementIds) {
18023
+ return;
18024
+ }
18025
+ // Prevent non-existent spot types
18026
+ inject = this.preventNonExistentSpotTypes(inject);
18027
+ // Make the spot selection request
18028
+ const response = await this.spotSelectionRequest({ ...params, inject });
18029
+ // Handle the response
18030
+ if (typeof response === 'object' && 'error' in response) {
18031
+ this.eventService.handleSpotState('all', {
18032
+ state: {
18033
+ error: response.error,
18034
+ },
18035
+ });
17962
18036
  return;
17963
18037
  }
17964
- this.preventDuplicateSpotPlacementIds(inject);
17965
- const response = await this.spotSelectionRequest(params);
17966
18038
  for (const item of inject) {
17967
18039
  const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
17968
18040
  const spots = response[item.placementId];
17969
18041
  if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
17970
- console.warn(`RmnSdk: Failed to inject spot element. No spots found for type "${item.spotType}".`);
18042
+ this.eventService.handleSpotState(item.placementId, {
18043
+ state: {
18044
+ error: `No spots found for type "${item.spotType}".`,
18045
+ loading: false,
18046
+ },
18047
+ });
17971
18048
  continue;
17972
18049
  }
17973
18050
  const placementId = item.placementId.replace('#', '');
17974
18051
  const placement = document.getElementById(placementId);
17975
18052
  if (!placement) {
17976
- console.warn(`RmnSdk: Failed to inject spot element. Placement not found for id "#${placementId}".`);
18053
+ this.eventService.handleSpotState(item.placementId, {
18054
+ state: {
18055
+ error: `Placement not found for id "${placementId}".`,
18056
+ loading: false,
18057
+ },
18058
+ });
17977
18059
  continue;
17978
18060
  }
17979
18061
  if (spots.length === 1) {
17980
- this.injectOneSpotElement(item, placement, spots[0], itemConfig);
18062
+ const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
18063
+ if (!isInjected) {
18064
+ continue;
18065
+ }
17981
18066
  }
17982
18067
  if (spots.length > 1) {
17983
- this.injectCarouselSpotElement(placement, spots, itemConfig);
18068
+ const isInjected = this.injectCarouselSpotElement(placement, spots, itemConfig);
18069
+ if (!isInjected) {
18070
+ continue;
18071
+ }
17984
18072
  }
17985
18073
  }
17986
18074
  }
17987
- /**
17988
- * Returns the event manager instance.
17989
- *
17990
- * @return {EventService} - The event manager instance.
17991
- */
17992
- eventManager() {
17993
- return this.eventService;
17994
- }
17995
18075
  /**
17996
18076
  * Makes a selection request on our server based on the provided data.
17997
18077
  *
17998
18078
  * @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
17999
18079
  *
18000
- * @return {Promise<ISpots>} - The spots response object.
18080
+ * @return {Promise<ISpots | {error: string}>} - The spots response object.
18001
18081
  */
18002
18082
  async spotSelectionRequest(params) {
18003
18083
  const { inject, filter, config } = params;
18004
18084
  const request = {
18005
18085
  url: config === null || config === void 0 ? void 0 : config.url,
18006
18086
  filter,
18007
- spots: inject.map((item) => ({
18008
- placementId: item.placementId,
18009
- spot: item.spotType,
18010
- count: item === null || item === void 0 ? void 0 : item.count,
18011
- ...item === null || item === void 0 ? void 0 : item.filter,
18012
- })),
18087
+ spots: inject.map((item) => {
18088
+ return {
18089
+ placementId: item.placementId,
18090
+ spot: item.spotType,
18091
+ count: item === null || item === void 0 ? void 0 : item.count,
18092
+ ...item === null || item === void 0 ? void 0 : item.filter,
18093
+ };
18094
+ }),
18013
18095
  };
18014
18096
  return this.spotSelection(request);
18015
18097
  }
@@ -18026,23 +18108,39 @@ class LiquidCommerceRmnClient {
18026
18108
  var _a;
18027
18109
  const carouselSlides = [];
18028
18110
  for (const spotItem of spots) {
18111
+ this.eventService.handleSpotState(placement.id, {
18112
+ displayConfig: {
18113
+ isCarousel: true,
18114
+ isCarouselItem: true,
18115
+ isSingleItem: false,
18116
+ },
18117
+ }, false);
18029
18118
  const spot = this.elementService.overrideSpotColors(spotItem, config === null || config === void 0 ? void 0 : config.colors);
18030
18119
  const content = SPOT_TEMPLATE_HTML_ELEMENT(spot, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
18031
18120
  if (!content) {
18032
- console.warn(`RmnSdk: Failed to inject carousel spot element. Could not create element for type "${spot.spot}".`);
18033
- return;
18121
+ this.eventService.handleSpotState(placement.id, {
18122
+ state: {
18123
+ error: `Failed to inject carousel spot item element. Could not create element for type "${spot.spot}".`,
18124
+ loading: false,
18125
+ },
18126
+ });
18127
+ continue;
18034
18128
  }
18035
- this.eventSpotElement({
18129
+ this.eventService.registerSpot({
18036
18130
  spot,
18037
18131
  placementId: placement.id,
18038
18132
  element: content,
18039
18133
  });
18040
18134
  carouselSlides.push(content);
18041
18135
  }
18042
- const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
18043
- maxWidth: Math.max(max.maxWidth, spot.width),
18044
- maxHeight: Math.max(max.maxHeight, spot.height),
18045
- }), { maxWidth: 0, maxHeight: 0 });
18136
+ // Get the max width and height of the spots
18137
+ const { maxWidth, maxHeight } = spots.reduce((max, spot) => {
18138
+ return {
18139
+ maxWidth: Math.max(max.maxWidth, spot.width),
18140
+ maxHeight: Math.max(max.maxHeight, spot.height),
18141
+ };
18142
+ }, { maxWidth: 0, maxHeight: 0 });
18143
+ // Create the carousel element
18046
18144
  const carouselElement = this.elementService.createCarouselElement({
18047
18145
  slides: carouselSlides,
18048
18146
  config: {
@@ -18054,10 +18152,25 @@ class LiquidCommerceRmnClient {
18054
18152
  },
18055
18153
  });
18056
18154
  if (!carouselElement) {
18057
- console.warn(`RmnSdk: Failed to inject spot carousel element. Could not create spot carousel element.`);
18058
- return;
18155
+ this.eventService.handleSpotState(placement.id, {
18156
+ state: {
18157
+ error: `Failed to inject spot carousel element. Could not create spot carousel element.`,
18158
+ loading: false,
18159
+ },
18160
+ });
18161
+ return false;
18059
18162
  }
18060
18163
  placement.replaceChildren(carouselElement);
18164
+ this.eventService.handleSpotState(placement.id, {
18165
+ dom: {
18166
+ element: carouselElement,
18167
+ },
18168
+ state: {
18169
+ mounted: true,
18170
+ loading: false,
18171
+ },
18172
+ });
18173
+ return true;
18061
18174
  }
18062
18175
  /**
18063
18176
  * Injects a single spot element into the provided placement.
@@ -18072,11 +18185,23 @@ class LiquidCommerceRmnClient {
18072
18185
  injectOneSpotElement(injectItem, placement, spot, config) {
18073
18186
  var _a;
18074
18187
  const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
18188
+ this.eventService.handleSpotState(injectItem.placementId, {
18189
+ displayConfig: {
18190
+ isSingleItem: true,
18191
+ },
18192
+ }, false);
18193
+ // Create the spot template element
18075
18194
  const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
18076
18195
  if (!content) {
18077
- console.warn(`RmnSdk: Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`);
18078
- return;
18196
+ this.eventService.handleSpotState(injectItem.placementId, {
18197
+ state: {
18198
+ error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
18199
+ loading: false,
18200
+ },
18201
+ });
18202
+ return false;
18079
18203
  }
18204
+ // Create the spot element
18080
18205
  const spotElement = this.elementService.createSpotElement({
18081
18206
  content,
18082
18207
  config: {
@@ -18088,22 +18213,30 @@ class LiquidCommerceRmnClient {
18088
18213
  },
18089
18214
  });
18090
18215
  if (!spotElement) {
18091
- console.warn(`RmnSdk: Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`);
18092
- return;
18216
+ this.eventService.handleSpotState(injectItem.placementId, {
18217
+ state: {
18218
+ error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
18219
+ loading: false,
18220
+ },
18221
+ });
18222
+ return false;
18093
18223
  }
18094
- this.eventSpotElement({
18095
- spot,
18224
+ this.eventService.registerSpot({
18225
+ spot: spotData,
18096
18226
  placementId: injectItem.placementId,
18097
18227
  element: spotElement,
18098
18228
  });
18099
18229
  placement.replaceChildren(spotElement);
18100
- }
18101
- eventSpotElement({ spot, placementId, element, }) {
18102
- this.eventService.registerSpot({
18103
- placementId,
18104
- element,
18105
- spot,
18230
+ this.eventService.handleSpotState(injectItem.placementId, {
18231
+ dom: {
18232
+ element: spotElement,
18233
+ },
18234
+ state: {
18235
+ mounted: true,
18236
+ loading: false,
18237
+ },
18106
18238
  });
18239
+ return true;
18107
18240
  }
18108
18241
  /**
18109
18242
  * Prevents duplicate placement ids in the inject data.
@@ -18118,10 +18251,44 @@ class LiquidCommerceRmnClient {
18118
18251
  const placementIds = new Set();
18119
18252
  for (const item of inject) {
18120
18253
  if (placementIds.has(item.placementId)) {
18121
- throw new Error(`RmnSdk: Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`);
18254
+ this.eventService.handleSpotState(item.placementId, {
18255
+ state: {
18256
+ error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
18257
+ },
18258
+ });
18259
+ return false;
18122
18260
  }
18123
18261
  placementIds.add(item.placementId);
18124
18262
  }
18263
+ return true;
18264
+ }
18265
+ preventNonExistentSpotTypes(inject) {
18266
+ const newInject = [];
18267
+ for (const item of inject) {
18268
+ if (!Object.values(exports.RMN_SPOT_TYPE).includes(item.spotType)) {
18269
+ this.eventService.handleSpotState(item.placementId, {
18270
+ state: {
18271
+ error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
18272
+ },
18273
+ });
18274
+ continue;
18275
+ }
18276
+ newInject.push(item);
18277
+ }
18278
+ return newInject;
18279
+ }
18280
+ updateSpotsState(inject) {
18281
+ for (const item of inject) {
18282
+ this.eventService.handleSpotState(item.placementId, {
18283
+ identifier: {
18284
+ placementId: item.placementId,
18285
+ spotType: item.spotType,
18286
+ },
18287
+ state: {
18288
+ loading: true,
18289
+ },
18290
+ });
18291
+ }
18125
18292
  }
18126
18293
  }
18127
18294
  /**