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

Sign up to get free protection for your applications and to get access to all the features.
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
  /**