@liquidcommercedev/rmn-sdk 1.5.0-beta.1 → 1.5.0-beta.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/dist/index.cjs +1414 -602
  2. package/dist/index.esm.js +1415 -603
  3. package/dist/types/common/helpers/event-type.helper.d.ts +8 -0
  4. package/dist/types/common/helpers/index.d.ts +4 -0
  5. package/dist/types/common/helpers/utils.helper.d.ts +37 -0
  6. package/dist/types/enums.d.ts +8 -1
  7. package/dist/types/modules/element/element.interface.d.ts +5 -2
  8. package/dist/types/modules/event/event.interface.d.ts +6 -32
  9. package/dist/types/modules/event/event.service.d.ts +7 -22
  10. package/dist/types/modules/event/index.d.ts +0 -1
  11. package/dist/types/modules/{event/helpers → helper-service}/index.d.ts +1 -0
  12. package/dist/types/modules/{event/helpers → helper-service}/intersection.service.d.ts +1 -1
  13. package/dist/types/modules/helper-service/localstorage.service.d.ts +56 -0
  14. package/dist/types/modules/{event/pubsub.d.ts → helper-service/pubsub.service.d.ts} +8 -8
  15. package/dist/types/modules/{event/helpers → helper-service}/resize.service.d.ts +1 -1
  16. package/dist/types/modules/monitor/index.d.ts +2 -0
  17. package/dist/types/modules/monitor/monitor.enums.d.ts +4 -0
  18. package/dist/types/modules/monitor/monitor.interface.d.ts +11 -0
  19. package/dist/types/modules/monitor/monitor.service.d.ts +12 -0
  20. package/dist/types/modules/monitor/monitors/datalayer.monitor.d.ts +12 -0
  21. package/dist/types/modules/selection/selection.interface.d.ts +3 -1
  22. package/dist/types/rmn-client.d.ts +1 -1
  23. package/dist/types/types.d.ts +5 -4
  24. package/package.json +1 -1
  25. package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
  26. package/dist/types/modules/element/component/utils.d.ts +0 -1
  27. package/dist/types/modules/event/helpers/localstorage.service.d.ts +0 -26
  28. /package/dist/types/{static.constant.d.ts → example.constant.d.ts} +0 -0
package/dist/index.esm.js CHANGED
@@ -1,6 +1,7 @@
1
1
  var RMN_SPOT_TYPE;
2
2
  (function (RMN_SPOT_TYPE) {
3
3
  // Reserve Bar Spot Types
4
+ RMN_SPOT_TYPE["RB_HOMEPAGE_HERO"] = "rbHomepageHero";
4
5
  RMN_SPOT_TYPE["RB_HOMEPAGE_HERO_THREE_TILE"] = "rbHomepageHeroThreeTile";
5
6
  RMN_SPOT_TYPE["RB_HOMEPAGE_HERO_TWO_TILE"] = "rbHomepageHeroTwoTile";
6
7
  RMN_SPOT_TYPE["RB_HOMEPAGE_HERO_FULL_IMAGE"] = "rbHomepageHeroFullImage";
@@ -52,14 +53,21 @@ var RMN_FILTER_PROPERTIES;
52
53
  RMN_FILTER_PROPERTIES["PUBLISHERS"] = "publishers";
53
54
  RMN_FILTER_PROPERTIES["SECTION"] = "section";
54
55
  })(RMN_FILTER_PROPERTIES || (RMN_FILTER_PROPERTIES = {}));
56
+ var RMN_EVENT;
57
+ (function (RMN_EVENT) {
58
+ RMN_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
59
+ RMN_EVENT["SPOT_EVENT"] = "SPOT_EVENT";
60
+ })(RMN_EVENT || (RMN_EVENT = {}));
55
61
  var RMN_SPOT_EVENT;
56
62
  (function (RMN_SPOT_EVENT) {
57
- RMN_SPOT_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
58
63
  RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
59
64
  RMN_SPOT_EVENT["CLICK"] = "CLICK";
60
65
  RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
61
66
  RMN_SPOT_EVENT["ADD_TO_CART"] = "ADD_TO_CART";
67
+ RMN_SPOT_EVENT["REMOVE_FROM_CART"] = "REMOVE_FROM_CART";
68
+ RMN_SPOT_EVENT["ADD_TO_CART_FROM_DETAILS"] = "ADD_TO_CART_FROM_DETAILS";
62
69
  RMN_SPOT_EVENT["ADD_TO_WISHLIST"] = "ADD_TO_WISHLIST";
70
+ RMN_SPOT_EVENT["EXPAND_PRODUCT"] = "EXPAND_PRODUCT";
63
71
  RMN_SPOT_EVENT["BUY_NOW"] = "BUY_NOW";
64
72
  })(RMN_SPOT_EVENT || (RMN_SPOT_EVENT = {}));
65
73
  var RMN_ENV;
@@ -70,6 +78,511 @@ var RMN_ENV;
70
78
  RMN_ENV["PRODUCTION"] = "production";
71
79
  })(RMN_ENV || (RMN_ENV = {}));
72
80
 
81
+ const SPOT_EVENTS_EXAMPLE = [
82
+ {
83
+ event: RMN_SPOT_EVENT.CLICK,
84
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
85
+ },
86
+ {
87
+ event: RMN_SPOT_EVENT.IMPRESSION,
88
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
89
+ },
90
+ {
91
+ event: RMN_SPOT_EVENT.PURCHASE,
92
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
93
+ },
94
+ {
95
+ event: RMN_SPOT_EVENT.ADD_TO_CART,
96
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
97
+ },
98
+ {
99
+ event: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
100
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
101
+ },
102
+ {
103
+ event: RMN_SPOT_EVENT.BUY_NOW,
104
+ url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
105
+ },
106
+ ];
107
+ const RB_SPOTS_SELECTION_EXAMPLE = {
108
+ rbHomepageHero: [
109
+ {
110
+ id: 'abc123',
111
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
112
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
113
+ width: 1140,
114
+ height: 640,
115
+ header: 'Premium Wine Collection',
116
+ description: 'Discover our exclusive selection of vintage wines',
117
+ ctaText: 'Shop Wines',
118
+ textColor: '#ffffff',
119
+ ctaTextColor: '#ffffff',
120
+ primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Collection',
121
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Wine',
122
+ events: SPOT_EVENTS_EXAMPLE,
123
+ productIds: [1, 2, 3],
124
+ },
125
+ {
126
+ id: 'jkl012',
127
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
128
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
129
+ width: 1140,
130
+ height: 640,
131
+ header: 'Whiskey Collection',
132
+ description: 'Premium whiskeys from around the world',
133
+ ctaText: 'Shop Whiskeys',
134
+ textColor: '#ffffff',
135
+ backgroundColor: '#2c1810',
136
+ ctaTextColor: '#2c1810',
137
+ primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey',
138
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
139
+ events: SPOT_EVENTS_EXAMPLE,
140
+ productIds: [10, 11],
141
+ },
142
+ {
143
+ id: 'stu901',
144
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
145
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
146
+ width: 1140,
147
+ height: 640,
148
+ header: 'Summer Cocktails',
149
+ description: 'Essential spirits for summer mixing',
150
+ ctaText: 'Mix It Up',
151
+ textColor: '#ffffff',
152
+ backgroundColor: '#4d3a0a',
153
+ ctaTextColor: '#4d3a0a',
154
+ primaryImage: 'https://placehold.co/1140x640/png?text=Cocktails',
155
+ secondaryImage: 'https://placehold.co/1140x640/png?text=Mixers',
156
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktails',
157
+ mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Mixers',
158
+ events: SPOT_EVENTS_EXAMPLE,
159
+ productIds: [16, 17, 18],
160
+ },
161
+ {
162
+ id: 'def456',
163
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
164
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
165
+ width: 1140,
166
+ height: 640,
167
+ header: 'Craft Beer Festival',
168
+ description: 'Local breweries and exclusive releases',
169
+ ctaText: 'Explore Beers',
170
+ textColor: '#ffffff',
171
+ ctaTextColor: '#ffffff',
172
+ primaryImage: 'https://placehold.co/1140x640/png?text=Beer+Festival',
173
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Beer',
174
+ events: SPOT_EVENTS_EXAMPLE,
175
+ productIds: [4, 5, 6],
176
+ },
177
+ {
178
+ id: 'mno345',
179
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
180
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
181
+ width: 1140,
182
+ height: 640,
183
+ header: 'Champagne Selection',
184
+ description: 'Finest champagnes for every occasion',
185
+ ctaText: 'View Champagnes',
186
+ textColor: '#ffffff',
187
+ backgroundColor: '#1a1a1a',
188
+ ctaTextColor: '#1a1a1a',
189
+ primaryImage: 'https://placehold.co/1140x640/png?text=Champagne',
190
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Champagne',
191
+ events: SPOT_EVENTS_EXAMPLE,
192
+ productIds: [12, 13],
193
+ },
194
+ {
195
+ id: 'vwx234',
196
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
197
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
198
+ width: 1140,
199
+ height: 640,
200
+ header: 'Wine Regions',
201
+ description: 'Explore wines from top regions',
202
+ ctaText: 'Tour Regions',
203
+ textColor: '#ffffff',
204
+ backgroundColor: '#4d0a0a',
205
+ ctaTextColor: '#4d0a0a',
206
+ primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Regions',
207
+ secondaryImage: 'https://placehold.co/1140x640/png?text=Vineyards',
208
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Regions',
209
+ mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Vineyards',
210
+ events: SPOT_EVENTS_EXAMPLE,
211
+ productIds: [19, 20, 21],
212
+ },
213
+ {
214
+ id: 'ghi789',
215
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
216
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
217
+ width: 1140,
218
+ height: 640,
219
+ header: 'Rare Spirits',
220
+ description: 'Limited edition spirits collection',
221
+ ctaText: 'View Collection',
222
+ textColor: '#ffffff',
223
+ ctaTextColor: '#ffffff',
224
+ primaryImage: 'https://placehold.co/1140x640/png?text=Rare+Spirits',
225
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Spirits',
226
+ events: SPOT_EVENTS_EXAMPLE,
227
+ productIds: [7, 8, 9],
228
+ },
229
+ {
230
+ id: 'pqr678',
231
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
232
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
233
+ width: 1140,
234
+ height: 640,
235
+ header: 'Gin Collection',
236
+ description: 'Artisanal gins and botanicals',
237
+ ctaText: 'Explore Gins',
238
+ textColor: '#ffffff',
239
+ backgroundColor: '#0a4d4d',
240
+ ctaTextColor: '#0a4d4d',
241
+ primaryImage: 'https://placehold.co/1140x640/png?text=Gin',
242
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gin',
243
+ events: SPOT_EVENTS_EXAMPLE,
244
+ productIds: [14, 15],
245
+ },
246
+ {
247
+ id: 'yz5678',
248
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
249
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
250
+ width: 1140,
251
+ height: 640,
252
+ header: 'Tequila Collection',
253
+ description: 'Premium tequilas and mezcals',
254
+ ctaText: 'Shop Tequila',
255
+ textColor: '#ffffff',
256
+ backgroundColor: '#0a4d2b',
257
+ ctaTextColor: '#0a4d2b',
258
+ primaryImage: 'https://placehold.co/1140x640/png?text=Tequila',
259
+ secondaryImage: 'https://placehold.co/1140x640/png?text=Mezcal',
260
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Tequila',
261
+ mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Mezcal',
262
+ events: SPOT_EVENTS_EXAMPLE,
263
+ productIds: [22, 23, 24],
264
+ },
265
+ ],
266
+ rbHomepageHeroFullImage: [
267
+ {
268
+ id: 'hjk567',
269
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
270
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
271
+ width: 1140,
272
+ height: 640,
273
+ header: 'Holiday Gift Guide',
274
+ description: 'Perfect spirits for every occasion',
275
+ ctaText: 'Shop Gifts',
276
+ textColor: '#ffffff',
277
+ ctaTextColor: '#ffffff',
278
+ primaryImage: 'https://placehold.co/1140x640/png?text=Gift+Guide',
279
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gifts',
280
+ events: SPOT_EVENTS_EXAMPLE,
281
+ productIds: [25, 26],
282
+ },
283
+ {
284
+ id: 'qwe890',
285
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
286
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
287
+ width: 1140,
288
+ height: 640,
289
+ header: 'Summer Wine Festival',
290
+ description: 'Refreshing wines for summer',
291
+ ctaText: 'Shop Festival',
292
+ textColor: '#ffffff',
293
+ ctaTextColor: '#ffffff',
294
+ primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Festival',
295
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Festival',
296
+ events: SPOT_EVENTS_EXAMPLE,
297
+ productIds: [27, 28],
298
+ },
299
+ ],
300
+ rbHomepageHeroTwoTile: [
301
+ {
302
+ id: 'iop987',
303
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
304
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
305
+ width: 1140,
306
+ height: 640,
307
+ header: 'Bourbon Selection',
308
+ description: "Kentucky's finest bourbons",
309
+ ctaText: 'Shop Bourbon',
310
+ textColor: '#ffffff',
311
+ backgroundColor: '#2c1810',
312
+ ctaTextColor: '#2c1810',
313
+ primaryImage: 'https://placehold.co/1140x640/png?text=Bourbon',
314
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Bourbon',
315
+ events: SPOT_EVENTS_EXAMPLE,
316
+ productIds: [29, 30],
317
+ },
318
+ {
319
+ id: 'lkj012',
320
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
321
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
322
+ width: 1140,
323
+ height: 640,
324
+ header: 'Vodka Collection',
325
+ description: 'Premium vodkas from around the world',
326
+ ctaText: 'Shop Vodka',
327
+ textColor: '#ffffff',
328
+ backgroundColor: '#1a1a1a',
329
+ ctaTextColor: '#1a1a1a',
330
+ primaryImage: 'https://placehold.co/1140x640/png?text=Vodka',
331
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Vodka',
332
+ events: SPOT_EVENTS_EXAMPLE,
333
+ productIds: [31, 32],
334
+ },
335
+ ],
336
+ rbHomepageHeroThreeTile: [
337
+ {
338
+ id: 'bnm345',
339
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
340
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
341
+ width: 1140,
342
+ height: 640,
343
+ header: 'Rum Collection',
344
+ description: 'Caribbean and craft rums',
345
+ ctaText: 'Shop Rum',
346
+ textColor: '#ffffff',
347
+ backgroundColor: '#4d3a0a',
348
+ ctaTextColor: '#4d3a0a',
349
+ primaryImage: 'https://placehold.co/1140x640/png?text=Rum',
350
+ secondaryImage: 'https://placehold.co/1140x640/png?text=Craft+Rum',
351
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Rum',
352
+ mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Craft',
353
+ events: SPOT_EVENTS_EXAMPLE,
354
+ productIds: [33, 34],
355
+ },
356
+ {
357
+ id: 'fgh678',
358
+ spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
359
+ variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
360
+ width: 1140,
361
+ height: 640,
362
+ header: 'Scotch Selection',
363
+ description: 'Single malts and blends',
364
+ ctaText: 'Shop Scotch',
365
+ textColor: '#ffffff',
366
+ backgroundColor: '#4d0a0a',
367
+ ctaTextColor: '#4d0a0a',
368
+ primaryImage: 'https://placehold.co/1140x640/png?text=Scotch',
369
+ secondaryImage: 'https://placehold.co/1140x640/png?text=Single+Malts',
370
+ mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Scotch',
371
+ mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Malts',
372
+ events: SPOT_EVENTS_EXAMPLE,
373
+ productIds: [35, 36],
374
+ },
375
+ ],
376
+ rbLargeCategoryImageTout: [
377
+ {
378
+ id: 'cde567',
379
+ spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
380
+ variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
381
+ width: 468,
382
+ height: 410,
383
+ header: 'Rare & Limited Edition',
384
+ description: 'Discover our collection of hard-to-find and limited release spirits.',
385
+ textColor: '#ffffff',
386
+ ctaTextColor: '#ffffff',
387
+ primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
388
+ mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
389
+ ctaText: 'Shop Rare Spirits',
390
+ events: SPOT_EVENTS_EXAMPLE,
391
+ productIds: [37, 38, 39, 40, 41],
392
+ },
393
+ {
394
+ id: 'efg789',
395
+ spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
396
+ variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
397
+ width: 468,
398
+ height: 410,
399
+ header: 'Vintage Champagnes',
400
+ description: 'Explore our prestigious collection of aged champagnes.',
401
+ textColor: '#ffffff',
402
+ ctaTextColor: '#ffffff',
403
+ primaryImage: 'https://placehold.co/468x410/png?text=Vintage+Champagne',
404
+ mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Champagne',
405
+ ctaText: 'View Collection',
406
+ events: SPOT_EVENTS_EXAMPLE,
407
+ productIds: [42, 43, 44, 45, 46],
408
+ },
409
+ {
410
+ id: 'ghi012',
411
+ spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
412
+ variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
413
+ width: 468,
414
+ height: 410,
415
+ header: 'Small Batch Bourbon',
416
+ description: 'Hand-selected premium bourbon from craft distilleries.',
417
+ textColor: '#ffffff',
418
+ ctaTextColor: '#ffffff',
419
+ primaryImage: 'https://placehold.co/468x410/png?text=Craft+Bourbon',
420
+ mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Bourbon',
421
+ ctaText: 'Explore Bourbon',
422
+ events: SPOT_EVENTS_EXAMPLE,
423
+ productIds: [47, 48, 49, 50, 51],
424
+ },
425
+ ],
426
+ rbSmallDiscoverTout: [
427
+ {
428
+ id: 'jkl345',
429
+ spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
430
+ variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
431
+ width: 224,
432
+ height: 378,
433
+ header: 'Château Margaux 2015 Bordeaux',
434
+ textColor: '#ffffff',
435
+ primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
436
+ mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
437
+ events: SPOT_EVENTS_EXAMPLE,
438
+ productIds: [52, 53, 54, 55, 56],
439
+ },
440
+ {
441
+ id: 'lmn678',
442
+ spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
443
+ variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
444
+ width: 224,
445
+ height: 378,
446
+ header: 'Macallan 25 Year',
447
+ textColor: '#ffffff',
448
+ primaryImage: 'https://placehold.co/224x378/png?text=Macallan+25',
449
+ mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Macallan',
450
+ events: SPOT_EVENTS_EXAMPLE,
451
+ productIds: [57, 58, 59, 60, 61],
452
+ },
453
+ {
454
+ id: 'nop901',
455
+ spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
456
+ variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
457
+ width: 224,
458
+ height: 378,
459
+ header: 'Louis XIII Cognac',
460
+ textColor: '#ffffff',
461
+ primaryImage: 'https://placehold.co/224x378/png?text=Louis+XIII',
462
+ mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Louis+XIII',
463
+ events: SPOT_EVENTS_EXAMPLE,
464
+ productIds: [62, 63, 64, 65, 66],
465
+ },
466
+ ],
467
+ rbSmallCategoryImageTout: [
468
+ {
469
+ id: 'qrs234',
470
+ spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
471
+ variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
472
+ width: 224,
473
+ height: 410,
474
+ header: 'Japanese Sake',
475
+ textColor: '#ffffff',
476
+ primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
477
+ mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
478
+ events: SPOT_EVENTS_EXAMPLE,
479
+ productIds: [67, 68, 69, 70, 71],
480
+ },
481
+ {
482
+ id: 'stu567',
483
+ spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
484
+ variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
485
+ width: 224,
486
+ height: 410,
487
+ header: 'Craft Vermouth',
488
+ textColor: '#ffffff',
489
+ primaryImage: 'https://placehold.co/224x410/png?text=Craft+Vermouth',
490
+ mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Vermouth',
491
+ events: SPOT_EVENTS_EXAMPLE,
492
+ productIds: [72, 73, 74, 75, 76],
493
+ },
494
+ {
495
+ id: 'vwx890',
496
+ spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
497
+ variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
498
+ width: 224,
499
+ height: 410,
500
+ header: 'Premium Mezcal',
501
+ textColor: '#ffffff',
502
+ primaryImage: 'https://placehold.co/224x410/png?text=Premium+Mezcal',
503
+ mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Mezcal',
504
+ events: SPOT_EVENTS_EXAMPLE,
505
+ productIds: [77, 78, 79, 80, 81],
506
+ },
507
+ ],
508
+ rbCollectionBannerWithoutTextBlock: [
509
+ {
510
+ id: 'yz1234',
511
+ spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
512
+ variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
513
+ width: 887,
514
+ height: 344,
515
+ primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
516
+ mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
517
+ events: SPOT_EVENTS_EXAMPLE,
518
+ productIds: [82, 83, 84, 85, 86],
519
+ },
520
+ {
521
+ id: 'abc567',
522
+ spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
523
+ variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
524
+ width: 887,
525
+ height: 344,
526
+ primaryImage: 'https://placehold.co/887x344/png?text=Holiday+Spirits',
527
+ mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Holiday+Spirits',
528
+ events: SPOT_EVENTS_EXAMPLE,
529
+ productIds: [87, 88, 89, 90, 91],
530
+ },
531
+ {
532
+ id: 'def901',
533
+ spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
534
+ variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
535
+ width: 887,
536
+ height: 344,
537
+ primaryImage: 'https://placehold.co/887x344/png?text=Wine+Essentials',
538
+ mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Wine+Essentials',
539
+ events: SPOT_EVENTS_EXAMPLE,
540
+ productIds: [92, 93, 94, 95, 96],
541
+ },
542
+ ],
543
+ rbNavigationBanner: [
544
+ {
545
+ id: 'ghi234',
546
+ spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
547
+ variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
548
+ width: 440,
549
+ height: 220,
550
+ header: 'Explore Tequilas',
551
+ textColor: '#ffffff',
552
+ primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
553
+ mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
554
+ events: SPOT_EVENTS_EXAMPLE,
555
+ productIds: [97, 98, 99, 100, 101],
556
+ },
557
+ {
558
+ id: 'jkl678',
559
+ spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
560
+ variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
561
+ width: 440,
562
+ height: 220,
563
+ header: 'Craft Gin Selection',
564
+ textColor: '#ffffff',
565
+ primaryImage: 'https://placehold.co/440x220/png?text=Gin+Selection',
566
+ mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Gin+Selection',
567
+ events: SPOT_EVENTS_EXAMPLE,
568
+ productIds: [102, 103, 104, 105, 106],
569
+ },
570
+ {
571
+ id: 'mno012',
572
+ spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
573
+ variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
574
+ width: 440,
575
+ height: 220,
576
+ header: 'Premium Vodka',
577
+ textColor: '#ffffff',
578
+ primaryImage: 'https://placehold.co/440x220/png?text=Vodka+Premium',
579
+ mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Vodka+Premium',
580
+ events: SPOT_EVENTS_EXAMPLE,
581
+ productIds: [107, 108, 109, 110, 111],
582
+ },
583
+ ],
584
+ };
585
+
73
586
  const REQUEST_CLOUD_PARTNER_SITE = 'X-Liquid-Partner-Site';
74
587
  const REQUEST_CLOUD_PROTECTED_KEY = 'X-Liquid-Protected';
75
588
  const REQUEST_CLOUD_PROTECTED_TIMESTAMP = 'X-Liquid-Timestamp';
@@ -6032,6 +6545,94 @@ axios.HttpStatusCode = HttpStatusCode;
6032
6545
 
6033
6546
  axios.default = axios;
6034
6547
 
6548
+ /**
6549
+ * Keyword patterns for each RMN_SPOT_EVENT.
6550
+ * Each event type has required keywords that must be present and optional ones.
6551
+ *
6552
+ * Note: The order of checks matters - more specific patterns must be checked before general ones
6553
+ * to avoid incorrect matches.
6554
+ */
6555
+ const EVENT_KEYWORDS = {
6556
+ [RMN_SPOT_EVENT.ADD_TO_CART_FROM_DETAILS]: {
6557
+ required: ['add', 'cart'],
6558
+ optional: ['details', 'detail', 'single', 'profile', 'page', 'pdp'],
6559
+ },
6560
+ [RMN_SPOT_EVENT.BUY_NOW]: {
6561
+ required: ['buy', 'now'],
6562
+ },
6563
+ [RMN_SPOT_EVENT.EXPAND_PRODUCT]: {
6564
+ required: ['product'],
6565
+ optional: ['details', 'expand', 'modal', 'popup', 'quickview', 'view'],
6566
+ },
6567
+ [RMN_SPOT_EVENT.ADD_TO_WISHLIST]: {
6568
+ required: ['add', 'wishlist'],
6569
+ },
6570
+ [RMN_SPOT_EVENT.REMOVE_FROM_CART]: {
6571
+ required: ['remove', 'cart'],
6572
+ },
6573
+ [RMN_SPOT_EVENT.PURCHASE]: {
6574
+ required: ['purchase'],
6575
+ },
6576
+ [RMN_SPOT_EVENT.ADD_TO_CART]: {
6577
+ required: ['add', 'cart'],
6578
+ },
6579
+ };
6580
+ /**
6581
+ * Normalizes an event name by converting to lowercase, removing special characters,
6582
+ * and splitting into words.
6583
+ */
6584
+ function normalizeEventName(event) {
6585
+ return event
6586
+ .toLowerCase()
6587
+ .replace(/[^a-z0-9\s]+/g, ' ') // Replace special chars with spaces
6588
+ .split(/\s+/) // Split on whitespace
6589
+ .filter(Boolean); // Remove empty strings
6590
+ }
6591
+ /**
6592
+ * Checks if a word matches a keyword, considering word boundaries.
6593
+ * This prevents partial word matches (e.g., "card" shouldn't match "cart").
6594
+ */
6595
+ function wordMatchesKeyword(word, keyword) {
6596
+ // Create a RegExp that matches the keyword as a whole word
6597
+ const keywordRegex = new RegExp(`^${keyword}s?$|${keyword}s?\\W|\\W${keyword}s?$|\\W${keyword}s?\\W`);
6598
+ return keywordRegex.test(` ${word} `); // Add spaces to handle word boundaries
6599
+ }
6600
+ /**
6601
+ * Checks if all required keywords and at least one optional keyword (if specified) are present.
6602
+ */
6603
+ function matchesKeywordPattern(words, required, optional) {
6604
+ // Check if all required keywords are present as whole words
6605
+ const hasAllRequired = required.every((keyword) => words.some((word) => wordMatchesKeyword(word, keyword)));
6606
+ if (!hasAllRequired) {
6607
+ return false;
6608
+ }
6609
+ // If no optional keywords are specified, return true
6610
+ if (!(optional === null || optional === void 0 ? void 0 : optional.length)) {
6611
+ return true;
6612
+ }
6613
+ // If optional keywords exist, check if at least one matches as a whole word
6614
+ return optional.some((keyword) => words.some((word) => wordMatchesKeyword(word, keyword)));
6615
+ }
6616
+ /**
6617
+ * Determines the event type from a raw event string by checking for keyword patterns.
6618
+ *
6619
+ * @param {string} [event] - The raw event string to evaluate
6620
+ * @returns {RMN_SPOT_EVENT | null} - The corresponding RMN_SPOT_EVENT or null if no match
6621
+ */
6622
+ function getEventTypeFromRawEvent(event) {
6623
+ if (!(event === null || event === void 0 ? void 0 : event.trim())) {
6624
+ return null;
6625
+ }
6626
+ const words = normalizeEventName(event);
6627
+ // Use Object.entries to maintain the exact order defined in EVENT_KEYWORDS
6628
+ for (const [eventType, { required, optional }] of Object.entries(EVENT_KEYWORDS)) {
6629
+ if (matchesKeywordPattern(words, required, optional)) {
6630
+ return eventType;
6631
+ }
6632
+ }
6633
+ return null;
6634
+ }
6635
+
6035
6636
  class SingletonManager {
6036
6637
  /**
6037
6638
  * Retrieves an instance of the specified class using the provided instance creator function.
@@ -6088,114 +6689,421 @@ class ObjectHelper {
6088
6689
  return Object.values(source);
6089
6690
  }
6090
6691
  /**
6091
- * Checks if a given key is present in a source object.
6092
- *
6093
- * @param {Record<string, any>} source - The object to search within.
6094
- * @param {string} key - The key to check for.
6095
- * @return {boolean} - True if the key is present in the source, false otherwise.
6692
+ * Checks if a given key is present in a source object.
6693
+ *
6694
+ * @param {Record<string, any>} source - The object to search within.
6695
+ * @param {string} key - The key to check for.
6696
+ * @return {boolean} - True if the key is present in the source, false otherwise.
6697
+ */
6698
+ includes(source, key) {
6699
+ return key in source;
6700
+ }
6701
+ /**
6702
+ * Checks if the given value is included in the values of a source object.
6703
+ *
6704
+ * @param {Record<string, any>} source - The source object to check the values from.
6705
+ * @param {string} value - The value to search for in the source object values.
6706
+ * @returns {boolean} - True if the value is found in the source object values, false otherwise.
6707
+ */
6708
+ valuesIncludes(source, value) {
6709
+ const sourceValues = Object.values(source);
6710
+ return sourceValues.includes(value);
6711
+ }
6712
+ /**
6713
+ * Checks if all keys from the given 'keys' array are present in the 'source' object.
6714
+ *
6715
+ * @param {Record<string, any>} source - The object to be checked.
6716
+ * @param {string[]} keys - The array of keys to be checked in the 'source' object.
6717
+ * @return {boolean} - Returns true if all keys are present in the 'source' object,
6718
+ * false otherwise.
6719
+ */
6720
+ hasAllValues(source, keys) {
6721
+ const sourceKeys = Object.keys(source);
6722
+ return keys.every((key) => sourceKeys.includes(key));
6723
+ }
6724
+ /**
6725
+ * Checks if the given object is an array.
6726
+ *
6727
+ * @param {any} obj - The object to check.
6728
+ * @return {boolean} - Returns true if the object is an array, otherwise returns false.
6729
+ */
6730
+ isArray(obj) {
6731
+ return Object.prototype.toString.call(obj) === '[object Array]';
6732
+ }
6733
+ /**
6734
+ * Merges the value with the target value.
6735
+ *
6736
+ * @param {any[] | Record<string, T>} targetValue - The target value to merge with.
6737
+ * @param {Record<string, any>} value - The value to merge.
6738
+ * @returns {Record<string, any>} - The merged value.
6739
+ */
6740
+ mergeValue(targetValue, value) {
6741
+ var _a;
6742
+ if (this.isArray(value)) {
6743
+ return this.mergeArrayValues(targetValue, value);
6744
+ }
6745
+ else if (typeof value === 'object') {
6746
+ return this.mergeObjectValues(targetValue, value);
6747
+ }
6748
+ return (_a = value !== null && value !== void 0 ? value : targetValue) !== null && _a !== void 0 ? _a : undefined;
6749
+ }
6750
+ /**
6751
+ * Merges the values of an array or object with a given array of objects and returns the merged result as an object.
6752
+ * If the targetValue is not an array, it returns a copy of the value array.
6753
+ *
6754
+ * @param targetValue - The target array or object to merge values into.
6755
+ * @param value - The array of objects containing values to merge into the targetValue.
6756
+ * @returns The merged result as an object.
6757
+ */
6758
+ mergeArrayValues(targetValue, value) {
6759
+ if (!this.isArray(targetValue)) {
6760
+ return [...value];
6761
+ }
6762
+ // make TypeScript understand that targetValue is an array
6763
+ const targetArray = targetValue;
6764
+ for (let i = 0, l = value.length; i < l; i++) {
6765
+ targetArray[i] = this.mergeValue(targetArray[i], value[i]);
6766
+ }
6767
+ return targetArray;
6768
+ }
6769
+ /**
6770
+ * Merges the values of two objects or arrays into a single object.
6771
+ * If the target value is an array or a record, the method merges the values into the target value.
6772
+ * If the target value is not an array or a record, it returns the new value.
6773
+ *
6774
+ * @template T - The type of the values in the target object.
6775
+ * @param {object[]|Record<string, T>} targetValue - The target object or array to merge the values into.
6776
+ * @param {Record<string, any>} value - The new values to merge into the target object or array.
6777
+ * @returns {Record<string, any>} - The merged object or array.
6778
+ */
6779
+ mergeObjectValues(targetValue, value) {
6780
+ if (targetValue && typeof targetValue === 'object') {
6781
+ this.innerMerge(targetValue, value);
6782
+ return targetValue;
6783
+ }
6784
+ return value ? { ...value } : value;
6785
+ }
6786
+ /**
6787
+ * Merges the properties of the source object into the target object.
6788
+ *
6789
+ * @param {Record<string, any>} target - The target object to merge the properties into.
6790
+ * @param {Record<string, any>} source - The source object containing the properties to merge.
6791
+ *
6792
+ * @return {void} - This method does not return any value.
6793
+ */
6794
+ innerMerge(target, source) {
6795
+ for (const key of Object.keys(source)) {
6796
+ target[key] = this.mergeValue(target[key], source[key]);
6797
+ }
6798
+ }
6799
+ }
6800
+
6801
+ /**
6802
+ * Recursively extracts ID values from a nested data structure.
6803
+ * Searches for specified property names and collects their primitive values (strings/numbers).
6804
+ *
6805
+ * @param data - The data structure to search through (can be nested objects/arrays)
6806
+ * @param propertyNames - Array of property names to look for
6807
+ * @returns Array of extracted ID values (strings/numbers only)
6808
+ *
6809
+ * @example
6810
+ * const data = {
6811
+ * id: [1, 2, 3],
6812
+ * nested: { id: 'abc' },
6813
+ * items: [{ id: 456 }]
6814
+ * };
6815
+ * extractDeepIds(data); // Returns [1, 2, 3, 'abc', 456]
6816
+ */
6817
+ function extractDeepIds(data, propertyNames) {
6818
+ const ids = [];
6819
+ const defaulPropertyNames = [
6820
+ 'id',
6821
+ 'upc',
6822
+ 'groupingId',
6823
+ 'sku',
6824
+ 'productId',
6825
+ 'item_id',
6826
+ 'isbn',
6827
+ 'asin',
6828
+ 'mpn',
6829
+ 'model_number',
6830
+ 'article_number',
6831
+ 'variant_id',
6832
+ 'item_number',
6833
+ 'catalog_id',
6834
+ 'reference_id',
6835
+ ];
6836
+ // Set for faster property name lookups
6837
+ const propertySet = new Set(defaulPropertyNames);
6838
+ /**
6839
+ * Processes a value and extracts IDs if it matches criteria
6840
+ * @param value - The value to process
6841
+ * @param currentKey - The property name of the current value
6842
+ */
6843
+ const processValue = (value, currentKey) => {
6844
+ // Early exit for null/undefined values
6845
+ if (value == null)
6846
+ return;
6847
+ // If current key matches our target properties
6848
+ if (currentKey && propertySet.has(currentKey)) {
6849
+ if (Array.isArray(value)) {
6850
+ // Filter and push valid array values in one pass
6851
+ ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
6852
+ }
6853
+ else if (typeof value === 'string' || typeof value === 'number') {
6854
+ ids.push(value);
6855
+ }
6856
+ return; // Stop processing this branch after handling the ID
6857
+ }
6858
+ // Recursively process nested structures
6859
+ if (Array.isArray(value)) {
6860
+ value.forEach((item) => processValue(item));
6861
+ }
6862
+ else if (typeof value === 'object') {
6863
+ // Process all enumerable properties
6864
+ for (const [key, val] of Object.entries(value)) {
6865
+ processValue(val, key);
6866
+ }
6867
+ }
6868
+ };
6869
+ processValue(data);
6870
+ return ids; // No need to filter nulls as we handle that during collection
6871
+ }
6872
+ // Fallback method using fetch if sendBeacon isn't available
6873
+ async function fallbackEventFire(url) {
6874
+ try {
6875
+ const racePromise = Promise.race([
6876
+ // Promise #1: The fetch request
6877
+ fetch(url, {
6878
+ method: 'POST',
6879
+ keepalive: true,
6880
+ }),
6881
+ // Promise #2: The timeout
6882
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Request timeout')), 2000)),
6883
+ ]);
6884
+ /**
6885
+ * Prevent requests from hanging indefinitely
6886
+ * Improve user experience by failing fast
6887
+ * Handle slow network conditions gracefully
6888
+ * Ensure resources are freed up in a timely manner
6889
+ */
6890
+ const response = await racePromise;
6891
+ return response.ok;
6892
+ }
6893
+ catch (_a) {
6894
+ return false;
6895
+ }
6896
+ }
6897
+ /**
6898
+ * Extracts and decodes a URL from a base64-encoded query parameter.
6899
+ *
6900
+ * @param {string} url - The URL containing the base64-encoded query parameter.
6901
+ * @returns {string | null} - The decoded URL or null if not found or invalid.
6902
+ */
6903
+ function getRedirectUrlFromPayload(url) {
6904
+ try {
6905
+ const base64String = new URL(url).searchParams.get('e');
6906
+ if (!base64String) {
6907
+ return null;
6908
+ }
6909
+ const data = JSON.parse(atob(base64String));
6910
+ return data.ur || null;
6911
+ }
6912
+ catch (_a) {
6913
+ return null;
6914
+ }
6915
+ }
6916
+ /**
6917
+ * Fires an event using the navigator.sendBeacon method or a fallback method if sendBeacon is not available.
6918
+ * If the event is a click event and a redirect URL is found, it redirects the user to that URL.
6919
+ *
6920
+ * @param {IFireEventParams} params - The parameters for firing the event.
6921
+ * @param {RMN_SPOT_EVENT} params.event - The event type.
6922
+ * @param {string} params.eventUrl - The URL to which the event is sent.
6923
+ * @returns {Promise<void>} - A promise that resolves when the event is fired.
6924
+ */
6925
+ async function fireEvent({ event, eventUrl }) {
6926
+ var _a;
6927
+ try {
6928
+ const didFireEvent = ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) === null || _a === void 0 ? void 0 : _a.call(navigator, eventUrl)) || (await fallbackEventFire(eventUrl));
6929
+ if (!didFireEvent) {
6930
+ return;
6931
+ }
6932
+ if (event === RMN_SPOT_EVENT.CLICK) {
6933
+ const redirectUrl = getRedirectUrlFromPayload(eventUrl);
6934
+ if (redirectUrl) {
6935
+ window.location.href = redirectUrl;
6936
+ }
6937
+ }
6938
+ }
6939
+ catch (_b) {
6940
+ // Handle errors silently
6941
+ }
6942
+ }
6943
+ function calculateScaleFactor(elementScale) {
6944
+ // Step 1: Apply square root for non-linear scaling
6945
+ // This creates a more gradual scaling effect, especially for larger changes
6946
+ // For example:
6947
+ // - elementScale of 0.25 (1/4 size) becomes 0.5
6948
+ // - elementScale of 1 (unchanged) remains 1
6949
+ // - elementScale of 4 (4x size) becomes 2
6950
+ const baseFactor = Math.sqrt(elementScale);
6951
+ // Step 2: Apply additional dampening to further soften the scaling effect
6952
+ // The dampening factor (0.5) can be adjusted:
6953
+ // - Lower values (closer to 0) make scaling more subtle
6954
+ // - Higher values (closer to 1) make scaling more pronounced
6955
+ const dampening = 0.35;
6956
+ // Calculate the scaleFactor:
6957
+ // 1. (baseFactor - 1) represents the change from the original size
6958
+ // 2. Multiply by dampening to reduce the effect
6959
+ // 3. Add 1 to center the scaling around the original size
6960
+ // For example, if baseFactor is 2:
6961
+ // scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
6962
+ const scaleFactor = 1 + (baseFactor - 1) * dampening;
6963
+ // Step 3: Define the allowed range for the scale factor
6964
+ // This ensures that the font size never changes too drastically
6965
+ const minScale = 0.35; // Font will never be smaller than 50% of original
6966
+ const maxScale = 1.5; // Font will never be larger than 150% of original
6967
+ // Step 4: Clamp the scale factor to the defined range
6968
+ // Math.min ensures the value doesn't exceed maxScale
6969
+ // Math.max ensures the value isn't less than minScale
6970
+ return Math.max(minScale, Math.min(maxScale, scaleFactor));
6971
+ }
6972
+
6973
+ class UniqueIdGenerator {
6974
+ /**
6975
+ * Initialize the generator with a node ID
6976
+ * @param nodeId Number between 0-1023 to identify this instance
6096
6977
  */
6097
- includes(source, key) {
6098
- return key in source;
6978
+ static initialize(nodeId = Math.floor(Math.random() * 1024)) {
6979
+ if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
6980
+ throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
6981
+ }
6982
+ this.nodeId = nodeId;
6099
6983
  }
6100
6984
  /**
6101
- * Checks if the given value is included in the values of a source object.
6102
- *
6103
- * @param {Record<string, any>} source - The source object to check the values from.
6104
- * @param {string} value - The value to search for in the source object values.
6105
- * @returns {boolean} - True if the value is found in the source object values, false otherwise.
6985
+ * Convert a number to base32 string with specified length
6106
6986
  */
6107
- valuesIncludes(source, value) {
6108
- const sourceValues = Object.values(source);
6109
- return sourceValues.includes(value);
6987
+ static toBase32(num, length) {
6988
+ let result = '';
6989
+ while (num > 0) {
6990
+ result = this.base32Chars[Number(num % BigInt(32))] + result;
6991
+ // @ts-expect-error - TS doesn't support bigint division
6992
+ num = num / 32n;
6993
+ }
6994
+ return result.padStart(length, '0');
6110
6995
  }
6111
6996
  /**
6112
- * Checks if all keys from the given 'keys' array are present in the 'source' object.
6113
- *
6114
- * @param {Record<string, any>} source - The object to be checked.
6115
- * @param {string[]} keys - The array of keys to be checked in the 'source' object.
6116
- * @return {boolean} - Returns true if all keys are present in the 'source' object,
6117
- * false otherwise.
6997
+ * Generate a cryptographically secure random number
6118
6998
  */
6119
- hasAllValues(source, keys) {
6120
- const sourceKeys = Object.keys(source);
6121
- return keys.every((key) => sourceKeys.includes(key));
6999
+ static getSecureRandom() {
7000
+ if (typeof crypto !== 'undefined') {
7001
+ const buffer = new Uint32Array(1);
7002
+ crypto.getRandomValues(buffer);
7003
+ return buffer[0];
7004
+ }
7005
+ return Math.floor(Math.random() * 0xffffffff);
6122
7006
  }
6123
7007
  /**
6124
- * Checks if the given object is an array.
6125
- *
6126
- * @param {any} obj - The object to check.
6127
- * @return {boolean} - Returns true if the object is an array, otherwise returns false.
7008
+ * Wait until next millisecond
6128
7009
  */
6129
- isArray(obj) {
6130
- return Object.prototype.toString.call(obj) === '[object Array]';
7010
+ static waitNextMillis(lastTimestamp) {
7011
+ let timestamp = Date.now();
7012
+ while (timestamp <= lastTimestamp) {
7013
+ timestamp = Date.now();
7014
+ }
7015
+ return timestamp;
6131
7016
  }
6132
7017
  /**
6133
- * Merges the value with the target value.
7018
+ * Generates a highly unique ID with the following format:
7019
+ * TTTTTTTTTTCCCCNNNNNRRRR
7020
+ * T: Timestamp (10 chars)
7021
+ * C: Counter (4 chars)
7022
+ * N: Node ID (5 chars)
7023
+ * R: Random (4 chars)
6134
7024
  *
6135
- * @param {any[] | Record<string, T>} targetValue - The target value to merge with.
6136
- * @param {Record<string, any>} value - The value to merge.
6137
- * @returns {Record<string, any>} - The merged value.
7025
+ * Total length: 23 characters, always uppercase alphanumeric
6138
7026
  */
6139
- mergeValue(targetValue, value) {
6140
- var _a;
6141
- if (this.isArray(value)) {
6142
- return this.mergeArrayValues(targetValue, value);
7027
+ static generate() {
7028
+ if (this.nodeId === undefined) {
7029
+ this.initialize();
6143
7030
  }
6144
- else if (typeof value === 'object') {
6145
- return this.mergeObjectValues(targetValue, value);
7031
+ let timestamp = Date.now() - this.epoch;
7032
+ // Handle clock moving backwards or same millisecond
7033
+ if (timestamp < this.lastTimestamp) {
7034
+ throw new Error('Clock moved backwards. Refusing to generate ID.');
6146
7035
  }
6147
- return (_a = value !== null && value !== void 0 ? value : targetValue) !== null && _a !== void 0 ? _a : undefined;
7036
+ if (timestamp === this.lastTimestamp) {
7037
+ this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
7038
+ if (this.sequence === 0) {
7039
+ timestamp = this.waitNextMillis(this.lastTimestamp);
7040
+ }
7041
+ }
7042
+ else {
7043
+ this.sequence = 0;
7044
+ }
7045
+ this.lastTimestamp = timestamp;
7046
+ // Generate random component
7047
+ const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
7048
+ // Combine all components into a BigInt
7049
+ // const id =
7050
+ // (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
7051
+ // (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
7052
+ // (BigInt(this.sequence) << BigInt(16)) |
7053
+ // BigInt(random);
7054
+ // Convert to base32 representation
7055
+ const timeComponent = this.toBase32(BigInt(timestamp), 10);
7056
+ const counterComponent = this.toBase32(BigInt(this.sequence), 4);
7057
+ const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
7058
+ const randomComponent = this.toBase32(BigInt(random), 4);
7059
+ return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
6148
7060
  }
6149
7061
  /**
6150
- * Merges the values of an array or object with a given array of objects and returns the merged result as an object.
6151
- * If the targetValue is not an array, it returns a copy of the value array.
6152
- *
6153
- * @param targetValue - The target array or object to merge values into.
6154
- * @param value - The array of objects containing values to merge into the targetValue.
6155
- * @returns The merged result as an object.
7062
+ * Validates if a string matches the expected ID format
6156
7063
  */
6157
- mergeArrayValues(targetValue, value) {
6158
- if (!this.isArray(targetValue)) {
6159
- return [...value];
7064
+ static isValid(id) {
7065
+ if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
7066
+ return false;
7067
+ try {
7068
+ const timeComponent = id.slice(0, 10);
7069
+ const timestamp = this.decodeBase32(timeComponent);
7070
+ const now = Date.now() - this.epoch;
7071
+ return timestamp >= 0 && timestamp <= now;
6160
7072
  }
6161
- // make TypeScript understand that targetValue is an array
6162
- const targetArray = targetValue;
6163
- for (let i = 0, l = value.length; i < l; i++) {
6164
- targetArray[i] = this.mergeValue(targetArray[i], value[i]);
7073
+ catch (_a) {
7074
+ return false;
6165
7075
  }
6166
- return targetArray;
6167
7076
  }
6168
7077
  /**
6169
- * Merges the values of two objects or arrays into a single object.
6170
- * If the target value is an array or a record, the method merges the values into the target value.
6171
- * If the target value is not an array or a record, it returns the new value.
6172
- *
6173
- * @template T - The type of the values in the target object.
6174
- * @param {object[]|Record<string, T>} targetValue - The target object or array to merge the values into.
6175
- * @param {Record<string, any>} value - The new values to merge into the target object or array.
6176
- * @returns {Record<string, any>} - The merged object or array.
7078
+ * Decode base32 string to number
6177
7079
  */
6178
- mergeObjectValues(targetValue, value) {
6179
- if (targetValue && typeof targetValue === 'object') {
6180
- this.innerMerge(targetValue, value);
6181
- return targetValue;
7080
+ static decodeBase32(str) {
7081
+ let result = 0;
7082
+ for (const char of str) {
7083
+ result = result * 32 + this.base32Chars.indexOf(char);
6182
7084
  }
6183
- return value ? { ...value } : value;
7085
+ return result;
6184
7086
  }
6185
7087
  /**
6186
- * Merges the properties of the source object into the target object.
6187
- *
6188
- * @param {Record<string, any>} target - The target object to merge the properties into.
6189
- * @param {Record<string, any>} source - The source object containing the properties to merge.
6190
- *
6191
- * @return {void} - This method does not return any value.
7088
+ * Extract timestamp from ID
6192
7089
  */
6193
- innerMerge(target, source) {
6194
- for (const key of Object.keys(source)) {
6195
- target[key] = this.mergeValue(target[key], source[key]);
6196
- }
7090
+ static getTimestamp(id) {
7091
+ if (!this.isValid(id))
7092
+ throw new Error('Invalid ID format');
7093
+ const timeComponent = id.slice(0, 10);
7094
+ const timestamp = this.decodeBase32(timeComponent);
7095
+ return new Date(timestamp + this.epoch);
6197
7096
  }
6198
7097
  }
7098
+ // Constants for bit manipulation
7099
+ UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
7100
+ UniqueIdGenerator.nodeBits = 10;
7101
+ UniqueIdGenerator.sequenceBits = 12;
7102
+ // Instance variables
7103
+ UniqueIdGenerator.lastTimestamp = -1;
7104
+ UniqueIdGenerator.sequence = 0;
7105
+ // Character set for base32 encoding (excluding similar looking characters)
7106
+ UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
6199
7107
 
6200
7108
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
6201
7109
 
@@ -15203,8 +16111,21 @@ class IntersectionObserverService {
15203
16111
  }
15204
16112
  }
15205
16113
 
15206
- class LocalStorage {
16114
+ var ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX;
16115
+ (function (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX) {
16116
+ ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["PLACEMENT_ID"] = 0] = "PLACEMENT_ID";
16117
+ ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_ID"] = 1] = "SPOT_ID";
16118
+ ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["SPOT_TYPE"] = 2] = "SPOT_TYPE";
16119
+ ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["EVENTS"] = 3] = "EVENTS";
16120
+ ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["PRODUCT_IDS"] = 4] = "PRODUCT_IDS";
16121
+ ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX["CREATED_AT"] = 5] = "CREATED_AT";
16122
+ })(ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX || (ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX = {}));
16123
+ class LocalStorageService {
15207
16124
  constructor() {
16125
+ if (typeof window.localStorage === 'undefined') {
16126
+ console.warn('Local storage is not supported in this environment');
16127
+ return;
16128
+ }
15208
16129
  this.spots = new Map();
15209
16130
  // Sync local storage with the current state
15210
16131
  this.syncLocalStorage();
@@ -15212,19 +16133,23 @@ class LocalStorage {
15212
16133
  this.removeExpiredSpots();
15213
16134
  }
15214
16135
  static getInstance() {
15215
- if (!LocalStorage.instance) {
15216
- LocalStorage.instance = new LocalStorage();
16136
+ if (!LocalStorageService.instance) {
16137
+ LocalStorageService.instance = new LocalStorageService();
15217
16138
  }
15218
- return LocalStorage.instance;
16139
+ return LocalStorageService.instance;
15219
16140
  }
15220
16141
  syncLocalStorage() {
15221
- const localStorageData = localStorage.getItem(LocalStorage.localStorageKey);
15222
- // TODO: Encrypt the data before storing it in the local storage
16142
+ const localStorageData = window.localStorage.getItem(LocalStorageService.localStorageKey);
15223
16143
  if (localStorageData) {
15224
16144
  try {
15225
- const parsedData = JSON.parse(localStorageData);
16145
+ const decryptedData = this.decryptData(localStorageData);
16146
+ const parsedData = JSON.parse(decryptedData);
15226
16147
  if (parsedData && typeof parsedData === 'object') {
15227
- this.spots = this.objToMap(parsedData);
16148
+ const data = {};
16149
+ for (const [key, value] of Object.entries(parsedData)) {
16150
+ data[key] = this.arrayToObject(value);
16151
+ }
16152
+ this.spots = this.objectToMap(data);
15228
16153
  }
15229
16154
  else {
15230
16155
  this.clearLocalStorage();
@@ -15237,43 +16162,176 @@ class LocalStorage {
15237
16162
  }
15238
16163
  }
15239
16164
  setSpot(spotId, data) {
16165
+ var _a;
15240
16166
  data.createdAt = Date.now();
15241
- this.spots.set(spotId, data);
16167
+ (_a = this.spots) === null || _a === void 0 ? void 0 : _a.set(spotId, data);
15242
16168
  this.updateLocalStorage();
15243
16169
  }
15244
- getSpot(spotId) {
15245
- return this.spots.get(spotId);
15246
- }
15247
16170
  removeSpot(spotId) {
15248
- this.spots.delete(spotId);
16171
+ var _a;
16172
+ (_a = this.spots) === null || _a === void 0 ? void 0 : _a.delete(spotId);
15249
16173
  this.updateLocalStorage();
15250
16174
  }
16175
+ getSpot(spotId) {
16176
+ var _a;
16177
+ return (_a = this.spots) === null || _a === void 0 ? void 0 : _a.get(spotId);
16178
+ }
16179
+ getSpots() {
16180
+ if (!this.spots)
16181
+ return undefined;
16182
+ return this.mapToObject(this.spots);
16183
+ }
15251
16184
  updateLocalStorage() {
15252
- const data = this.mapToObj(this.spots);
15253
- localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(data));
16185
+ if (!this.spots)
16186
+ return undefined;
16187
+ const data = this.mapToObject(this.spots);
16188
+ const dataArray = {};
16189
+ for (const [key, value] of Object.entries(data)) {
16190
+ dataArray[key] = this.objectToArray(value);
16191
+ }
16192
+ try {
16193
+ const encryptedData = this.encryptData(JSON.stringify(dataArray));
16194
+ window.localStorage.setItem(LocalStorageService.localStorageKey, encryptedData);
16195
+ }
16196
+ catch (_a) {
16197
+ // If there is an error parsing the data, clear the local storage to prevent any issues
16198
+ this.clearLocalStorage();
16199
+ }
15254
16200
  }
15255
16201
  clearLocalStorage() {
15256
- localStorage.removeItem(LocalStorage.localStorageKey);
16202
+ window.localStorage.removeItem(LocalStorageService.localStorageKey);
15257
16203
  }
15258
16204
  removeExpiredSpots() {
16205
+ var _a;
15259
16206
  const currentTime = Date.now();
15260
- this.spots.forEach((spot, spotId) => {
15261
- var _a;
15262
- if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) > LocalStorage.spotExpirationTime) {
15263
- this.spots.delete(spotId);
16207
+ (_a = this.spots) === null || _a === void 0 ? void 0 : _a.forEach((spot, spotId) => {
16208
+ var _a, _b;
16209
+ if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) > LocalStorageService.spotExpirationTime) {
16210
+ (_b = this.spots) === null || _b === void 0 ? void 0 : _b.delete(spotId);
15264
16211
  }
15265
16212
  });
15266
16213
  this.updateLocalStorage();
15267
16214
  }
15268
- mapToObj(map) {
16215
+ mapToObject(map) {
15269
16216
  return Object.fromEntries(map);
15270
16217
  }
15271
- objToMap(obj) {
15272
- return new Map(Object.entries(obj));
16218
+ objectToMap(obj) {
16219
+ return new Map(Object.entries(obj));
16220
+ }
16221
+ objectToArray(obj) {
16222
+ return [obj.placementId, obj.spotId, obj.spotType, obj.events, obj.productIds, obj.createdAt];
16223
+ }
16224
+ arrayToObject(arr) {
16225
+ return {
16226
+ placementId: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.PLACEMENT_ID],
16227
+ spotId: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_ID],
16228
+ spotType: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.SPOT_TYPE],
16229
+ events: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.EVENTS],
16230
+ productIds: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.PRODUCT_IDS],
16231
+ createdAt: arr[ENUM_LOCAL_STORAGE_SPOT_ARRAY_INDEX.CREATED_AT],
16232
+ };
16233
+ }
16234
+ encryptData(data) {
16235
+ if (!LocalStorageService.encryptData)
16236
+ return data;
16237
+ // For now, we are using base64 encoding to encrypt the data
16238
+ // Later we will use Jose encryption
16239
+ const encryptedData = btoa(data);
16240
+ return encryptedData;
16241
+ }
16242
+ decryptData(data) {
16243
+ if (!LocalStorageService.encryptData)
16244
+ return data;
16245
+ // For now, we are using base64 encoding to encrypt
16246
+ // Later we will use Jose encryption
16247
+ const decryptedData = atob(data);
16248
+ return decryptedData;
16249
+ }
16250
+ }
16251
+ LocalStorageService.localStorageKey = 'lc_rmn';
16252
+ LocalStorageService.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
16253
+ LocalStorageService.encryptData = true;
16254
+
16255
+ /**
16256
+ * PubsubService class
16257
+ * Manages event subscriptions and publications
16258
+ * @template IRmnEventMap A record type defining the structure of events and their data
16259
+ */
16260
+ class PubsubService {
16261
+ constructor() {
16262
+ /**
16263
+ * Object to store subscribers for each event type
16264
+ */
16265
+ this.subscribers = {};
16266
+ }
16267
+ static getInstance() {
16268
+ if (!PubsubService.instance) {
16269
+ PubsubService.instance = new PubsubService();
16270
+ }
16271
+ return PubsubService.instance;
16272
+ }
16273
+ /**
16274
+ * Subscribe to an event
16275
+ * @param eventType - The type of event to subscribe to
16276
+ * @param callback - The function to be called when the event is published
16277
+ * @returns A function to unsubscribe from the event
16278
+ *
16279
+ * @Example:
16280
+ * const unsubscribe = pubSub.subscribe('userLogin', (data) => {
16281
+ * console.log(`User ${data.username} logged in`);
16282
+ * });
16283
+ */
16284
+ subscribe(eventType, callback) {
16285
+ if (!this.subscribers[eventType]) {
16286
+ this.subscribers[eventType] = [];
16287
+ }
16288
+ this.subscribers[eventType].push(callback);
16289
+ // Return an unsubscribe function
16290
+ return () => {
16291
+ this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
16292
+ };
16293
+ }
16294
+ /**
16295
+ * Publish an event
16296
+ * @param eventType - The type of event to publish
16297
+ * @param data - The data to be passed to the event subscribers
16298
+ *
16299
+ * @Example:
16300
+ * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
16301
+ */
16302
+ publish(eventType, data) {
16303
+ if (!this.subscribers[eventType]) {
16304
+ return;
16305
+ }
16306
+ this.subscribers[eventType].forEach((callback) => callback(data));
15273
16307
  }
15274
16308
  }
15275
- LocalStorage.localStorageKey = 'lc_rmn';
15276
- LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
16309
+ /**
16310
+ * Usage Example:
16311
+ *
16312
+ * interface IRmnEventMap {
16313
+ * userLogin: { username: string; timestamp: number };
16314
+ * pageView: { url: string; timestamp: number };
16315
+ * }
16316
+ *
16317
+ * const pubSub = new PubsubService<IRmnEventMap>();
16318
+ *
16319
+ * // Subscribe to events
16320
+ * const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
16321
+ * console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
16322
+ * });
16323
+ *
16324
+ * pubSub.subscribe('pageView', (data) => {
16325
+ * console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
16326
+ * });
16327
+ *
16328
+ * // Publish events
16329
+ * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
16330
+ * pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
16331
+ *
16332
+ * // Unsubscribe from an event
16333
+ * unsubscribeLogin();
16334
+ */
15277
16335
 
15278
16336
  class ResizeObserverService {
15279
16337
  constructor({ element, maxSize, minScale }) {
@@ -15343,36 +16401,6 @@ class ResizeObserverService {
15343
16401
  }
15344
16402
  }
15345
16403
 
15346
- function calculateScaleFactor(elementScale) {
15347
- // Step 1: Apply square root for non-linear scaling
15348
- // This creates a more gradual scaling effect, especially for larger changes
15349
- // For example:
15350
- // - elementScale of 0.25 (1/4 size) becomes 0.5
15351
- // - elementScale of 1 (unchanged) remains 1
15352
- // - elementScale of 4 (4x size) becomes 2
15353
- const baseFactor = Math.sqrt(elementScale);
15354
- // Step 2: Apply additional dampening to further soften the scaling effect
15355
- // The dampening factor (0.5) can be adjusted:
15356
- // - Lower values (closer to 0) make scaling more subtle
15357
- // - Higher values (closer to 1) make scaling more pronounced
15358
- const dampening = 0.35;
15359
- // Calculate the scaleFactor:
15360
- // 1. (baseFactor - 1) represents the change from the original size
15361
- // 2. Multiply by dampening to reduce the effect
15362
- // 3. Add 1 to center the scaling around the original size
15363
- // For example, if baseFactor is 2:
15364
- // scaleFactor = 1 + (2 - 1) * 0.5 = 1.5
15365
- const scaleFactor = 1 + (baseFactor - 1) * dampening;
15366
- // Step 3: Define the allowed range for the scale factor
15367
- // This ensures that the font size never changes too drastically
15368
- const minScale = 0.35; // Font will never be smaller than 50% of original
15369
- const maxScale = 1.5; // Font will never be larger than 150% of original
15370
- // Step 4: Clamp the scale factor to the defined range
15371
- // Math.min ensures the value doesn't exceed maxScale
15372
- // Math.max ensures the value isn't less than minScale
15373
- return Math.max(minScale, Math.min(maxScale, scaleFactor));
15374
- }
15375
-
15376
16404
  const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
15377
16405
  :host {
15378
16406
  position: relative;
@@ -15387,11 +16415,13 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
15387
16415
  position: relative;
15388
16416
  height: 100%;
15389
16417
  width: 100%;
16418
+ display: flex;
16419
+ transition: transform 0.5s ease-in-out;
15390
16420
  }
15391
16421
 
15392
16422
  .slide {
15393
- display: none;
15394
-
16423
+ flex: 0 0 100%;
16424
+ display: flex;
15395
16425
  justify-content: center;
15396
16426
  align-items: center;
15397
16427
  height: 100%;
@@ -15696,9 +16726,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15696
16726
  renderSlides() {
15697
16727
  const slidesContainer = document.createElement('div');
15698
16728
  slidesContainer.className = 'slides';
15699
- this.slides.forEach((slide, index) => {
16729
+ this.slides.forEach((slide) => {
15700
16730
  const slideElement = document.createElement('div');
15701
- slideElement.className = `slide ${index === this.currentSlide ? 'active' : ''}`;
16731
+ slideElement.className = 'slide';
15702
16732
  if (slide instanceof HTMLElement) {
15703
16733
  slideElement.appendChild(slide);
15704
16734
  }
@@ -15777,10 +16807,9 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
15777
16807
  updateCarousel() {
15778
16808
  if (!this.slidesContainer)
15779
16809
  return;
15780
- const slides = Array.from(this.slidesContainer.children);
15781
- slides.forEach((slide, index) => {
15782
- slide.classList.toggle('active', index === this.currentSlide);
15783
- });
16810
+ // Calculate the translation distance based on current slide
16811
+ const translateX = -this.currentSlide * 100;
16812
+ this.slidesContainer.style.transform = `translateX(${translateX}%)`;
15784
16813
  this.updateDots();
15785
16814
  }
15786
16815
  updateDots() {
@@ -16032,141 +17061,6 @@ class ElementService {
16032
17061
  }
16033
17062
  }
16034
17063
 
16035
- class UniqueIdGenerator {
16036
- /**
16037
- * Initialize the generator with a node ID
16038
- * @param nodeId Number between 0-1023 to identify this instance
16039
- */
16040
- static initialize(nodeId = Math.floor(Math.random() * 1024)) {
16041
- if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
16042
- throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
16043
- }
16044
- this.nodeId = nodeId;
16045
- }
16046
- /**
16047
- * Convert a number to base32 string with specified length
16048
- */
16049
- static toBase32(num, length) {
16050
- let result = '';
16051
- while (num > 0) {
16052
- result = this.base32Chars[Number(num % BigInt(32))] + result;
16053
- // @ts-expect-error - TS doesn't support bigint division
16054
- num = num / 32n;
16055
- }
16056
- return result.padStart(length, '0');
16057
- }
16058
- /**
16059
- * Generate a cryptographically secure random number
16060
- */
16061
- static getSecureRandom() {
16062
- if (typeof crypto !== 'undefined') {
16063
- const buffer = new Uint32Array(1);
16064
- crypto.getRandomValues(buffer);
16065
- return buffer[0];
16066
- }
16067
- return Math.floor(Math.random() * 0xffffffff);
16068
- }
16069
- /**
16070
- * Wait until next millisecond
16071
- */
16072
- static waitNextMillis(lastTimestamp) {
16073
- let timestamp = Date.now();
16074
- while (timestamp <= lastTimestamp) {
16075
- timestamp = Date.now();
16076
- }
16077
- return timestamp;
16078
- }
16079
- /**
16080
- * Generates a highly unique ID with the following format:
16081
- * TTTTTTTTTTCCCCNNNNNRRRR
16082
- * T: Timestamp (10 chars)
16083
- * C: Counter (4 chars)
16084
- * N: Node ID (5 chars)
16085
- * R: Random (4 chars)
16086
- *
16087
- * Total length: 23 characters, always uppercase alphanumeric
16088
- */
16089
- static generate() {
16090
- if (this.nodeId === undefined) {
16091
- this.initialize();
16092
- }
16093
- let timestamp = Date.now() - this.epoch;
16094
- // Handle clock moving backwards or same millisecond
16095
- if (timestamp < this.lastTimestamp) {
16096
- throw new Error('Clock moved backwards. Refusing to generate ID.');
16097
- }
16098
- if (timestamp === this.lastTimestamp) {
16099
- this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
16100
- if (this.sequence === 0) {
16101
- timestamp = this.waitNextMillis(this.lastTimestamp);
16102
- }
16103
- }
16104
- else {
16105
- this.sequence = 0;
16106
- }
16107
- this.lastTimestamp = timestamp;
16108
- // Generate random component
16109
- const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
16110
- // Combine all components into a BigInt
16111
- // const id =
16112
- // (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
16113
- // (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
16114
- // (BigInt(this.sequence) << BigInt(16)) |
16115
- // BigInt(random);
16116
- // Convert to base32 representation
16117
- const timeComponent = this.toBase32(BigInt(timestamp), 10);
16118
- const counterComponent = this.toBase32(BigInt(this.sequence), 4);
16119
- const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
16120
- const randomComponent = this.toBase32(BigInt(random), 4);
16121
- return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
16122
- }
16123
- /**
16124
- * Validates if a string matches the expected ID format
16125
- */
16126
- static isValid(id) {
16127
- if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
16128
- return false;
16129
- try {
16130
- const timeComponent = id.slice(0, 10);
16131
- const timestamp = this.decodeBase32(timeComponent);
16132
- const now = Date.now() - this.epoch;
16133
- return timestamp >= 0 && timestamp <= now;
16134
- }
16135
- catch (_a) {
16136
- return false;
16137
- }
16138
- }
16139
- /**
16140
- * Decode base32 string to number
16141
- */
16142
- static decodeBase32(str) {
16143
- let result = 0;
16144
- for (const char of str) {
16145
- result = result * 32 + this.base32Chars.indexOf(char);
16146
- }
16147
- return result;
16148
- }
16149
- /**
16150
- * Extract timestamp from ID
16151
- */
16152
- static getTimestamp(id) {
16153
- if (!this.isValid(id))
16154
- throw new Error('Invalid ID format');
16155
- const timeComponent = id.slice(0, 10);
16156
- const timestamp = this.decodeBase32(timeComponent);
16157
- return new Date(timestamp + this.epoch);
16158
- }
16159
- }
16160
- // Constants for bit manipulation
16161
- UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
16162
- UniqueIdGenerator.nodeBits = 10;
16163
- UniqueIdGenerator.sequenceBits = 12;
16164
- // Instance variables
16165
- UniqueIdGenerator.lastTimestamp = -1;
16166
- UniqueIdGenerator.sequence = 0;
16167
- // Character set for base32 encoding (excluding similar looking characters)
16168
- UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
16169
-
16170
17064
  function convertHexToRgba(hex, opacity = 1) {
16171
17065
  // Remove # if present
16172
17066
  const cleanHex = hex.replace('#', '');
@@ -16204,12 +17098,13 @@ function spotHtmlStringToElement(htmlString) {
16204
17098
  spot.className = 'spot';
16205
17099
  spot.innerHTML = htmlString;
16206
17100
  Object.assign(spot.style, {
16207
- position: 'relative',
16208
17101
  display: 'block',
16209
17102
  width: '100%',
16210
17103
  height: '100%',
16211
17104
  margin: '0',
16212
17105
  padding: '0',
17106
+ containerType: 'inline-size',
17107
+ position: 'relative',
16213
17108
  });
16214
17109
  return spot;
16215
17110
  }
@@ -17079,7 +17974,6 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
17079
17974
  box-sizing: border-box;
17080
17975
  color: ${textColor};
17081
17976
  cursor: pointer;
17082
- container-type: inline-size;
17083
17977
  }
17084
17978
 
17085
17979
  .${prefix}__text {
@@ -17095,7 +17989,7 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
17095
17989
  .${prefix}__header {
17096
17990
  font-size: 24px;
17097
17991
  margin: 0;
17098
- font-family: "Cormorant";
17992
+ font-family: "Cormorant", system-ui;
17099
17993
  font-style: normal;
17100
17994
  font-weight: 300;
17101
17995
  line-height: normal;
@@ -17214,7 +18108,6 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
17214
18108
  height: 100%;
17215
18109
  display: block;
17216
18110
  position: relative;
17217
- container-type: inline-size;
17218
18111
  }
17219
18112
 
17220
18113
  .${prefix}__content {
@@ -17405,15 +18298,20 @@ function rbHomepageHeroThreeTileTemplate(spot, config) {
17405
18298
  const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextColor = textColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
17406
18299
  <style>
17407
18300
  .${prefix} {
18301
+ width: 100%;
18302
+ height: 100%;
18303
+ background-color: transparent;
18304
+ cursor: pointer;
18305
+ position: relative;
18306
+ }
18307
+
18308
+ .${prefix}__content {
17408
18309
  width: 100%;
17409
18310
  height: 100%;
17410
18311
  display: flex;
17411
18312
  flex-direction: column-reverse;
17412
18313
  background-color: transparent;
17413
18314
  gap: 6px;
17414
- cursor: pointer;
17415
- container-type: inline-size;
17416
- position: relative;
17417
18315
  }
17418
18316
 
17419
18317
  .${prefix}__image {
@@ -17444,7 +18342,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
17444
18342
  font-size: 18px;
17445
18343
  margin: 0;
17446
18344
  color: inherit;
17447
- font-family: "Cormorant";
18345
+ font-family: "Cormorant", system-ui;
17448
18346
  font-style: normal;
17449
18347
  font-weight: 700;
17450
18348
  line-height: normal;
@@ -17486,7 +18384,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
17486
18384
  }
17487
18385
 
17488
18386
  @container (min-width: 768px) {
17489
- .${prefix} {
18387
+ .${prefix}__content {
17490
18388
  flex-direction: row;
17491
18389
  }
17492
18390
  .${prefix}__image {
@@ -17541,12 +18439,14 @@ function rbHomepageHeroTwoTileTemplate(spot, config) {
17541
18439
  ${GFONT_CORMORANT}
17542
18440
  ${STYLES$4(spot, config)}
17543
18441
  <div class="${prefix}">
17544
- <div class="${prefix}__text">
17545
- ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17546
- ${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
17547
- ${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
17548
- </div>
17549
- <div class="${prefix}__image"></div>
18442
+ <div class="${prefix}__content">
18443
+ <div class="${prefix}__text">
18444
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
18445
+ ${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
18446
+ ${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
18447
+ </div>
18448
+ <div class="${prefix}__image"></div>
18449
+ </div>
17550
18450
  </div>
17551
18451
  `;
17552
18452
  }
@@ -17569,12 +18469,10 @@ const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
17569
18469
  overflow: hidden;
17570
18470
  cursor: pointer;
17571
18471
  color: ${textColor};
17572
- container-type: inline-size;
17573
18472
  }
17574
18473
 
17575
18474
  .${prefix}__text {
17576
18475
  padding: 20px;
17577
- width: 70%;
17578
18476
  display: flex;
17579
18477
  flex-direction: column;
17580
18478
  justify-content: center;
@@ -17586,7 +18484,7 @@ const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
17586
18484
  color: inherit;
17587
18485
  margin: 0;
17588
18486
  font-size: 20px;
17589
- font-family: "Cormorant";
18487
+ font-family: "Cormorant", system-ui;
17590
18488
  font-style: normal;
17591
18489
  font-weight: 300;
17592
18490
  line-height: normal;
@@ -17705,7 +18603,6 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
17705
18603
  background-size: cover;
17706
18604
  background-position: center;
17707
18605
  background-repeat: no-repeat;
17708
- container-type: inline-size;
17709
18606
  position: relative;
17710
18607
  }
17711
18608
 
@@ -17775,12 +18672,7 @@ const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
17775
18672
  border-radius: 5px;
17776
18673
  overflow: hidden;
17777
18674
  cursor: pointer;
17778
- container-type: inline-size;
17779
- }
17780
-
17781
- .${prefix}__text {
17782
- padding: 10px;
17783
- width: 70%;
18675
+ position: relative;
17784
18676
  }
17785
18677
 
17786
18678
  .${prefix}__header {
@@ -17791,6 +18683,7 @@ const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
17791
18683
  font-style: normal;
17792
18684
  font-weight: 400;
17793
18685
  margin: 0;
18686
+ padding: 10px;
17794
18687
  }
17795
18688
 
17796
18689
  @container (min-width: 640px) {
@@ -17808,9 +18701,7 @@ function rbSmallCategoryImageToutTemplate(spot, config) {
17808
18701
  ${GFONT_CORMORANT}
17809
18702
  ${STYLES$1(spot, config)}
17810
18703
  <div class="${prefix}">
17811
- <div class="${prefix}__text">
17812
- ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17813
- </div>
18704
+ ${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
17814
18705
  </div>
17815
18706
  `;
17816
18707
  }
@@ -17825,7 +18716,6 @@ const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primar
17825
18716
  display: flex;
17826
18717
  flex-direction: column;
17827
18718
  border-radius: 5px;
17828
- container-type: inline-size;
17829
18719
  }
17830
18720
 
17831
18721
  .${prefix}__image {
@@ -17961,94 +18851,164 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
17961
18851
  return spotHtmlStringToElement(spotHtmlString);
17962
18852
  };
17963
18853
 
17964
- /**
17965
- * PubSub class
17966
- * Manages event subscriptions and publications
17967
- * @template IEventMap A record type defining the structure of events and their data
17968
- */
17969
- class PubSub {
18854
+ // For the moment, we will only focus on sites that use Google Analytics,
18855
+ // but we will add support for other analytics tools in the future.
18856
+ var AnalyticsTool;
18857
+ (function (AnalyticsTool) {
18858
+ AnalyticsTool["GoogleAnalytics"] = "google-analytics";
18859
+ AnalyticsTool["Other"] = "Other";
18860
+ })(AnalyticsTool || (AnalyticsTool = {}));
18861
+
18862
+ class DataLayerMonitor {
18863
+ constructor() {
18864
+ if (!window.dataLayer) {
18865
+ return;
18866
+ }
18867
+ this.originalPush = window.dataLayer.push;
18868
+ }
18869
+ static getInstance() {
18870
+ if (!DataLayerMonitor.instance) {
18871
+ DataLayerMonitor.instance = new DataLayerMonitor();
18872
+ }
18873
+ return DataLayerMonitor.instance;
18874
+ }
18875
+ setListener(listener) {
18876
+ this.listener = listener;
18877
+ }
18878
+ start() {
18879
+ window.dataLayer.push = (...args) => {
18880
+ const result = this.originalPush.apply(window.dataLayer, args);
18881
+ const pushedEvent = args[0];
18882
+ if (this.listener) {
18883
+ const normalizedData = this.cleanEventData(pushedEvent);
18884
+ if (normalizedData) {
18885
+ this.listener(normalizedData);
18886
+ }
18887
+ }
18888
+ return result;
18889
+ };
18890
+ }
18891
+ cleanEventData(data) {
18892
+ const eventName = getEventTypeFromRawEvent(data.event);
18893
+ if (!eventName) {
18894
+ return null;
18895
+ }
18896
+ const productIds = extractDeepIds(data.value);
18897
+ return {
18898
+ event: eventName,
18899
+ productIds,
18900
+ };
18901
+ }
18902
+ stop() {
18903
+ if (this.originalPush) {
18904
+ window.dataLayer.push = this.originalPush;
18905
+ }
18906
+ this.listener = undefined;
18907
+ }
18908
+ }
18909
+
18910
+ // @TODO: Add support for user to push events to our own data layer, if they don't use any analytics tool.
18911
+ // window.rmnDataLayer = window.rmnDataLayer || [];
18912
+ class MonitorService {
17970
18913
  constructor() {
17971
- /**
17972
- * Object to store subscribers for each event type
17973
- */
17974
- this.subscribers = {};
18914
+ const analyticsTool = this.detectAnalyticsTool();
18915
+ switch (analyticsTool) {
18916
+ case AnalyticsTool.GoogleAnalytics:
18917
+ this.implementedMonitor = DataLayerMonitor.getInstance();
18918
+ break;
18919
+ case AnalyticsTool.Other:
18920
+ default:
18921
+ console.warn('This site uses an unsupported analytics tool.');
18922
+ break;
18923
+ }
18924
+ if (analyticsTool === AnalyticsTool.Other) {
18925
+ return;
18926
+ }
18927
+ this.pubSubService = PubsubService.getInstance();
18928
+ this.localStorageService = LocalStorageService.getInstance();
17975
18929
  }
17976
18930
  static getInstance() {
17977
- if (!PubSub.instance) {
17978
- PubSub.instance = new PubSub();
18931
+ if (!MonitorService.instance) {
18932
+ MonitorService.instance = new MonitorService();
17979
18933
  }
17980
- return PubSub.instance;
18934
+ return MonitorService.instance;
17981
18935
  }
17982
- /**
17983
- * Subscribe to an event
17984
- * @param eventType - The type of event to subscribe to
17985
- * @param callback - The function to be called when the event is published
17986
- * @returns A function to unsubscribe from the event
17987
- *
17988
- * @Example:
17989
- * const unsubscribe = pubSub.subscribe('userLogin', (data) => {
17990
- * console.log(`User ${data.username} logged in`);
17991
- * });
17992
- */
17993
- subscribe(eventType, callback) {
17994
- if (!this.subscribers[eventType]) {
17995
- this.subscribers[eventType] = [];
18936
+ start() {
18937
+ if (!this.implementedMonitor)
18938
+ return;
18939
+ this.implementedMonitor.setListener(async (eventData) => {
18940
+ var _a;
18941
+ await this.matchAndFireEvent(eventData, (_a = this.localStorageService) === null || _a === void 0 ? void 0 : _a.getSpots());
18942
+ });
18943
+ this.implementedMonitor.start();
18944
+ }
18945
+ async matchAndFireEvent(eventData, spots) {
18946
+ var _a, _b;
18947
+ if (!spots)
18948
+ return;
18949
+ const eventProductIds = new Set(eventData.productIds);
18950
+ for (const spot of Object.values(spots)) {
18951
+ if (!spot.productIds.length)
18952
+ continue;
18953
+ const hasCommonProductIds = spot.productIds.find((productId) => eventProductIds.has(productId));
18954
+ if (hasCommonProductIds) {
18955
+ if (Object.values(RMN_SPOT_EVENT).includes(eventData.event)) {
18956
+ await this.fireAndPublishSpotEvent({
18957
+ spotEvent: eventData.event,
18958
+ eventUrl: (_b = (_a = spot.events.find((event) => event.event === eventData.event)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
18959
+ placementId: spot.placementId,
18960
+ spotId: spot.spotId,
18961
+ });
18962
+ }
18963
+ }
17996
18964
  }
17997
- this.subscribers[eventType].push(callback);
17998
- // Return an unsubscribe function
17999
- return () => {
18000
- this.subscribers[eventType] = this.subscribers[eventType].filter((cb) => cb !== callback);
18001
- };
18002
18965
  }
18003
- /**
18004
- * Publish an event
18005
- * @param eventType - The type of event to publish
18006
- * @param data - The data to be passed to the event subscribers
18007
- *
18008
- * @Example:
18009
- * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
18010
- */
18011
- publish(eventType, data) {
18012
- if (!this.subscribers[eventType]) {
18966
+ async fireAndPublishSpotEvent({ spotEvent, eventUrl, placementId, spotId, }) {
18967
+ await fireEvent({
18968
+ event: spotEvent,
18969
+ eventUrl,
18970
+ });
18971
+ if (!this.pubSubService)
18013
18972
  return;
18973
+ this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
18974
+ eventType: spotEvent,
18975
+ placementId,
18976
+ spotId,
18977
+ });
18978
+ }
18979
+ detectAnalyticsTool() {
18980
+ let analyticsTool = AnalyticsTool.Other;
18981
+ // Check for Google Analytics
18982
+ if (typeof window.ga !== 'undefined') {
18983
+ analyticsTool = AnalyticsTool.GoogleAnalytics;
18014
18984
  }
18015
- this.subscribers[eventType].forEach((callback) => callback(data));
18985
+ // Check for Google Analytics 4
18986
+ if (typeof window.gtag !== 'undefined') {
18987
+ analyticsTool = AnalyticsTool.GoogleAnalytics;
18988
+ }
18989
+ // Check for Google Tag Manager
18990
+ if (typeof window.google_tag_manager !== 'undefined') {
18991
+ analyticsTool = AnalyticsTool.GoogleAnalytics;
18992
+ }
18993
+ // @TODO: Add support for other analytics tools
18994
+ // Check for Heap Analytics
18995
+ // Check for Mixpanel
18996
+ // Check for Woopra
18997
+ // Check for Segment
18998
+ // Check for Amplitude
18999
+ return analyticsTool;
18016
19000
  }
18017
19001
  }
18018
- /**
18019
- * Usage Example:
18020
- *
18021
- * interface IEventMap {
18022
- * userLogin: { username: string; timestamp: number };
18023
- * pageView: { url: string; timestamp: number };
18024
- * }
18025
- *
18026
- * const pubSub = new PubSub<IEventMap>();
18027
- *
18028
- * // Subscribe to events
18029
- * const unsubscribeLogin = pubSub.subscribe('userLogin', (data) => {
18030
- * console.log(`User ${data.username} logged in at ${new Date(data.timestamp)}`);
18031
- * });
18032
- *
18033
- * pubSub.subscribe('pageView', (data) => {
18034
- * console.log(`Page ${data.url} viewed at ${new Date(data.timestamp)}`);
18035
- * });
18036
- *
18037
- * // Publish events
18038
- * pubSub.publish('userLogin', { username: 'john_doe', timestamp: Date.now() });
18039
- * pubSub.publish('pageView', { url: '/home', timestamp: Date.now() });
18040
- *
18041
- * // Unsubscribe from an event
18042
- * unsubscribeLogin();
18043
- */
18044
19002
 
18045
19003
  class EventService {
18046
19004
  constructor() {
18047
- this.pubSub = PubSub.getInstance();
18048
- this.localStorage = LocalStorage.getInstance();
19005
+ this.pubSubService = PubsubService.getInstance();
19006
+ this.localStorageService = LocalStorageService.getInstance();
18049
19007
  this.activeSpots = new Map();
18050
19008
  this.spotStates = new Map();
18051
19009
  this.intersectionObserver = new IntersectionObserverService();
19010
+ // Start the user monitor, which will track and check user interactions
19011
+ MonitorService.getInstance().start();
18052
19012
  }
18053
19013
  static getInstance() {
18054
19014
  if (!EventService.instance) {
@@ -18057,16 +19017,16 @@ class EventService {
18057
19017
  return EventService.instance;
18058
19018
  }
18059
19019
  subscribe(eventType, callback) {
18060
- return this.pubSub.subscribe(eventType, callback);
19020
+ return this.pubSubService.subscribe(eventType, callback);
18061
19021
  }
18062
19022
  publish(eventType, data) {
18063
- this.pubSub.publish(eventType, data);
19023
+ this.pubSubService.publish(eventType, data);
18064
19024
  }
18065
19025
  registerSpot(params) {
18066
19026
  const { placementId, spot, spotElement } = params;
18067
19027
  this.activeSpots.set(placementId, { spotElement });
18068
19028
  // Fire impression event
18069
- this.fireImpressionEvent(placementId, spot, spotElement);
19029
+ this.fireImpressionEvent(placementId, spot);
18070
19030
  // Handle intersection observer
18071
19031
  this.handleIntersectionObserver(placementId, spot, spotElement);
18072
19032
  // Attach click event listener
@@ -18141,30 +19101,42 @@ class EventService {
18141
19101
  },
18142
19102
  };
18143
19103
  }
18144
- this.spotStates.set(placementId, { ...currentState, ...updates });
19104
+ const merged = this.deepMerge(currentState, updates);
19105
+ this.spotStates.set(placementId, merged);
18145
19106
  if (publish) {
18146
- this.pubSub.publish(RMN_SPOT_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
19107
+ this.pubSubService.publish(RMN_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
18147
19108
  }
18148
19109
  }
18149
- async handleClick({ placementId, spot, spotElement, }) {
19110
+ deepMerge(current, updates) {
19111
+ return {
19112
+ identifier: updates.identifier
19113
+ ? { ...current.identifier, ...updates.identifier }
19114
+ : current.identifier,
19115
+ dom: updates.dom ? { ...current.dom, ...updates.dom } : current.dom,
19116
+ state: updates.state ? { ...current.state, ...updates.state } : current.state,
19117
+ displayConfig: updates.displayConfig
19118
+ ? { ...current.displayConfig, ...updates.displayConfig }
19119
+ : current.displayConfig,
19120
+ };
19121
+ }
19122
+ async handleClick({ placementId, spot }) {
18150
19123
  var _a, _b, _c;
18151
- // Publish click event
18152
- this.pubSub.publish(RMN_SPOT_EVENT.CLICK, {
19124
+ this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
19125
+ eventType: RMN_SPOT_EVENT.CLICK,
18153
19126
  placementId,
18154
19127
  spotId: spot.id,
18155
- spotElement,
18156
19128
  });
18157
- // Fire click event
18158
- await this.fireEvent({
19129
+ await fireEvent({
18159
19130
  event: RMN_SPOT_EVENT.CLICK,
18160
19131
  eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
18161
19132
  });
18162
19133
  // Save spot to local storage for event tracking
18163
- this.localStorage.setSpot(spot.id, {
19134
+ this.localStorageService.setSpot(spot.id, {
19135
+ placementId,
18164
19136
  spotId: spot.id,
18165
19137
  spotType: spot.spot,
18166
19138
  events: spot.events,
18167
- productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 'GROUPING-12345', 'DAN-12345', 131398103],
19139
+ productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 2, 3],
18168
19140
  });
18169
19141
  }
18170
19142
  handleIntersectionObserver(placementId, _spot, spotElement) {
@@ -18179,51 +19151,20 @@ class EventService {
18179
19151
  };
18180
19152
  this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
18181
19153
  }
18182
- fireImpressionEvent(placementId, spot, spotElement) {
18183
- this.pubSub.publish(RMN_SPOT_EVENT.IMPRESSION, {
19154
+ fireImpressionEvent(placementId, spot) {
19155
+ this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
19156
+ eventType: RMN_SPOT_EVENT.IMPRESSION,
18184
19157
  placementId,
18185
19158
  spotId: spot.id,
18186
- spotElement,
18187
19159
  });
18188
19160
  (async () => {
18189
19161
  var _a, _b;
18190
- await this.fireEvent({
19162
+ await fireEvent({
18191
19163
  event: RMN_SPOT_EVENT.IMPRESSION,
18192
19164
  eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
18193
19165
  });
18194
19166
  })();
18195
19167
  }
18196
- /**
18197
- * Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
18198
- *
18199
- * @param {IFireEventParams} params - The parameters for firing the event.
18200
- * @param {RMN_SPOT_EVENT} params.event - The event type.
18201
- * @param {string} params.eventUrl - The URL to which the event is sent.
18202
- * @returns {Promise<void>} - A promise that resolves when the event is fired.
18203
- */
18204
- async fireEvent({ event, eventUrl }) {
18205
- const didFireEvent = navigator.sendBeacon(eventUrl);
18206
- if (didFireEvent && event === RMN_SPOT_EVENT.CLICK) {
18207
- window.location.href = this.getRedirectUrlFromPayload(eventUrl);
18208
- }
18209
- }
18210
- /**
18211
- * Extracts and decodes a URL from a base64-encoded query parameter.
18212
- *
18213
- * @param {string} url - The URL containing the base64-encoded query parameter.
18214
- * @returns {string} - The decoded URL or an empty string if decoding fails.
18215
- */
18216
- getRedirectUrlFromPayload(url) {
18217
- var _a, _b;
18218
- const base64String = (_a = new URL(url).searchParams.get('e')) !== null && _a !== void 0 ? _a : '';
18219
- try {
18220
- const data = JSON.parse(atob(base64String));
18221
- return (_b = data.ur) !== null && _b !== void 0 ? _b : '';
18222
- }
18223
- catch (_c) {
18224
- return '';
18225
- }
18226
- }
18227
19168
  }
18228
19169
 
18229
19170
  const SELECTION_API_PATH = '/spots/selection';
@@ -18256,176 +19197,6 @@ class SelectionService extends BaseApi {
18256
19197
  }
18257
19198
  }
18258
19199
 
18259
- const SPOT_EVENTS_EXAMPLE = [
18260
- {
18261
- event: RMN_SPOT_EVENT.CLICK,
18262
- url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
18263
- },
18264
- {
18265
- event: RMN_SPOT_EVENT.IMPRESSION,
18266
- url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
18267
- },
18268
- {
18269
- event: RMN_SPOT_EVENT.PURCHASE,
18270
- url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
18271
- },
18272
- {
18273
- event: RMN_SPOT_EVENT.ADD_TO_CART,
18274
- url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
18275
- },
18276
- {
18277
- event: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
18278
- url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
18279
- },
18280
- {
18281
- event: RMN_SPOT_EVENT.BUY_NOW,
18282
- url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
18283
- },
18284
- ];
18285
- const RB_SPOTS_SELECTION_EXAMPLE = {
18286
- rbHomepageHeroFullImage: [
18287
- {
18288
- id: '111111_111111',
18289
- spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18290
- variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18291
- width: 1140,
18292
- height: 640,
18293
- header: 'Artisanal Craft Beer Collection',
18294
- description: 'Discover our curated selection of small-batch, flavor-packed craft beers.',
18295
- ctaText: 'Explore the Collection',
18296
- textColor: '#ffffff',
18297
- ctaTextColor: '#ffffff',
18298
- primaryImage: 'https://placehold.co/1140x640/png?text=Craft+Beer+Collection',
18299
- mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Craft+Beer',
18300
- events: SPOT_EVENTS_EXAMPLE,
18301
- },
18302
- {
18303
- id: '222222_222222',
18304
- spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18305
- variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
18306
- width: 1140,
18307
- height: 640,
18308
- header: 'Summer Wine Spectacular',
18309
- description: 'Refresh your palate with our handpicked selection of crisp, summer wines.',
18310
- ctaText: 'Shop Summer Wines',
18311
- textColor: '#000000',
18312
- ctaTextColor: '#ffffff',
18313
- primaryImage: 'https://placehold.co/1140x640/png?text=Summer+Wines',
18314
- mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Summer+Wines',
18315
- events: SPOT_EVENTS_EXAMPLE,
18316
- },
18317
- ],
18318
- rbHomepageHeroTwoTile: [
18319
- {
18320
- id: '333333_333333',
18321
- spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
18322
- variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
18323
- width: 1140,
18324
- height: 640,
18325
- header: 'Whiskey Wonderland',
18326
- description: 'Embark on a journey through our premium whiskey selection.',
18327
- ctaText: 'Discover Whiskeys',
18328
- textColor: '#ffffff',
18329
- backgroundColor: '#2c1a05',
18330
- ctaTextColor: '#2c1a05',
18331
- primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey+Collection',
18332
- mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
18333
- events: SPOT_EVENTS_EXAMPLE,
18334
- },
18335
- ],
18336
- rbHomepageHeroThreeTile: [
18337
- {
18338
- id: '444444_444444',
18339
- spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
18340
- variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
18341
- width: 1140,
18342
- height: 640,
18343
- header: 'Cocktail Essentials',
18344
- description: 'Stock your bar with premium spirits and mixers for the perfect cocktail.',
18345
- ctaText: 'Build Your Bar',
18346
- textColor: '#ffffff',
18347
- backgroundColor: '#1a3c4d',
18348
- ctaTextColor: '#1a3c4d',
18349
- primaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Spirits',
18350
- secondaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Mixers',
18351
- mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktail+Kit',
18352
- mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Cocktail+Mixers',
18353
- events: SPOT_EVENTS_EXAMPLE,
18354
- },
18355
- ],
18356
- rbLargeCategoryImageTout: [
18357
- {
18358
- id: '555555_555555',
18359
- spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
18360
- variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
18361
- width: 468,
18362
- height: 410,
18363
- header: 'Rare & Limited Edition',
18364
- description: 'Discover our collection of hard-to-find and limited release spirits.',
18365
- textColor: '#ffffff',
18366
- ctaTextColor: '#ffffff',
18367
- primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
18368
- mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
18369
- ctaText: 'Shop Rare Spirits',
18370
- events: SPOT_EVENTS_EXAMPLE,
18371
- },
18372
- ],
18373
- rbSmallDiscoverTout: [
18374
- {
18375
- id: '666666_666666',
18376
- spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
18377
- variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
18378
- width: 224,
18379
- height: 378,
18380
- header: 'Château Margaux 2015 Bordeaux',
18381
- textColor: '#ffffff',
18382
- primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
18383
- mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
18384
- events: SPOT_EVENTS_EXAMPLE,
18385
- },
18386
- ],
18387
- rbSmallCategoryImageTout: [
18388
- {
18389
- id: '777777_777777',
18390
- spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
18391
- variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
18392
- width: 224,
18393
- height: 410,
18394
- header: 'Japanese Sake',
18395
- textColor: '#ffffff',
18396
- primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
18397
- mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
18398
- events: SPOT_EVENTS_EXAMPLE,
18399
- },
18400
- ],
18401
- rbCollectionBannerWithoutTextBlock: [
18402
- {
18403
- id: '888888_888888',
18404
- spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
18405
- variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
18406
- width: 887,
18407
- height: 344,
18408
- primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
18409
- mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
18410
- events: SPOT_EVENTS_EXAMPLE,
18411
- },
18412
- ],
18413
- rbNavigationBanner: [
18414
- {
18415
- id: '999999_999999',
18416
- spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
18417
- variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
18418
- width: 440,
18419
- height: 220,
18420
- header: 'Explore Tequilas',
18421
- textColor: '#ffffff',
18422
- primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
18423
- mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
18424
- events: SPOT_EVENTS_EXAMPLE,
18425
- },
18426
- ],
18427
- };
18428
-
18429
19200
  class LiquidCommerceRmnClient {
18430
19201
  constructor(auth) {
18431
19202
  this.selectionService = SelectionService.getInstance(auth);
@@ -18439,7 +19210,7 @@ class LiquidCommerceRmnClient {
18439
19210
  *
18440
19211
  * @param {ISpotSelectionParams} params - Spots selection parameters.
18441
19212
  *
18442
- * @return {Promise<ISpots | {error : string}>} - The spots response object.
19213
+ * @return {Promise<ISpots | { error : string }>} - The spots response object.
18443
19214
  */
18444
19215
  async spotSelection(params) {
18445
19216
  return this.selectionService.spotSelection(params);
@@ -18453,13 +19224,19 @@ class LiquidCommerceRmnClient {
18453
19224
  */
18454
19225
  async injectSpotElement(params) {
18455
19226
  var _a;
19227
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
19228
+ console.warn('LiquidCommerce Rmn Sdk: Methods which create elements are only available in browser environments.');
19229
+ return;
19230
+ }
18456
19231
  const config = params.config;
18457
19232
  let inject = params.inject;
18458
19233
  if (!inject.length) {
19234
+ // Handle no spots error state
18459
19235
  this.eventService.handleSpotState('all', {
18460
19236
  state: {
18461
19237
  error: 'No spot elements provided for injection.',
18462
19238
  loading: false,
19239
+ mounted: false,
18463
19240
  },
18464
19241
  });
18465
19242
  return;
@@ -18478,9 +19255,12 @@ class LiquidCommerceRmnClient {
18478
19255
  // const response = await this.useSpotSelectionExample(inject);
18479
19256
  // Handle the response
18480
19257
  if (typeof response === 'object' && 'error' in response) {
19258
+ // Handle request error state
18481
19259
  this.eventService.handleSpotState('all', {
18482
19260
  state: {
18483
19261
  error: response.error,
19262
+ mounted: false,
19263
+ loading: false,
18484
19264
  },
18485
19265
  });
18486
19266
  return;
@@ -18489,9 +19269,11 @@ class LiquidCommerceRmnClient {
18489
19269
  const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
18490
19270
  const spots = response[item.placementId];
18491
19271
  if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
19272
+ // Handle no spots found error state
18492
19273
  this.eventService.handleSpotState(item.placementId, {
18493
19274
  state: {
18494
19275
  error: `No spots found for type "${item.spotType}".`,
19276
+ mounted: false,
18495
19277
  loading: false,
18496
19278
  },
18497
19279
  });
@@ -18500,9 +19282,11 @@ class LiquidCommerceRmnClient {
18500
19282
  const placementId = item.placementId.replace('#', '');
18501
19283
  const placement = document.getElementById(placementId);
18502
19284
  if (!placement) {
19285
+ // Handle placement not found error state
18503
19286
  this.eventService.handleSpotState(item.placementId, {
18504
19287
  state: {
18505
19288
  error: `Placement not found for id "${placementId}".`,
19289
+ mounted: false,
18506
19290
  loading: false,
18507
19291
  },
18508
19292
  });
@@ -18513,16 +19297,18 @@ class LiquidCommerceRmnClient {
18513
19297
  placement.removeAttribute('class');
18514
19298
  Object.assign(placement.style, {
18515
19299
  width: '100%',
18516
- height: 'auto',
19300
+ height: '100%',
18517
19301
  display: 'flex',
18518
19302
  justifyContent: 'center',
18519
19303
  });
19304
+ // Handle single spot
18520
19305
  if (spots.length === 1) {
18521
19306
  const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
18522
19307
  if (!isInjected) {
18523
19308
  continue;
18524
19309
  }
18525
19310
  }
19311
+ // Handle multiple spots (carousel)
18526
19312
  if (spots.length > 1) {
18527
19313
  const isInjected = this.injectCarouselSpotElement(placement, spots, itemConfig);
18528
19314
  if (!isInjected) {
@@ -18566,18 +19352,24 @@ class LiquidCommerceRmnClient {
18566
19352
  const carouselSlides = [];
18567
19353
  for (const spotItem of spots) {
18568
19354
  this.eventService.handleSpotState(placement.id, {
19355
+ identifier: {
19356
+ placementId: placement.id,
19357
+ spotType: spotItem.spot,
19358
+ spotId: spotItem.id,
19359
+ },
18569
19360
  displayConfig: {
19361
+ isSingleItem: false,
18570
19362
  isCarousel: true,
18571
19363
  isCarouselItem: true,
18572
- isSingleItem: false,
18573
19364
  },
18574
- }, false);
19365
+ });
18575
19366
  const spot = this.elementService.overrideSpotColors(spotItem, config === null || config === void 0 ? void 0 : config.colors);
18576
19367
  const content = SPOT_TEMPLATE_HTML_ELEMENT(spot, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
18577
19368
  if (!content) {
18578
19369
  this.eventService.handleSpotState(placement.id, {
18579
19370
  state: {
18580
19371
  error: `Failed to inject carousel spot item element. Could not create element for type "${spot.spot}".`,
19372
+ mounted: false,
18581
19373
  loading: false,
18582
19374
  },
18583
19375
  });
@@ -18610,6 +19402,7 @@ class LiquidCommerceRmnClient {
18610
19402
  this.eventService.handleSpotState(placement.id, {
18611
19403
  state: {
18612
19404
  error: `Failed to inject spot carousel element. Could not create spot carousel element.`,
19405
+ mounted: false,
18613
19406
  loading: false,
18614
19407
  },
18615
19408
  });
@@ -18619,10 +19412,12 @@ class LiquidCommerceRmnClient {
18619
19412
  this.eventService.handleSpotState(placement.id, {
18620
19413
  dom: {
18621
19414
  spotElement: carouselElement,
19415
+ visibleOnViewport: false,
18622
19416
  },
18623
19417
  state: {
18624
19418
  mounted: true,
18625
19419
  loading: false,
19420
+ error: undefined,
18626
19421
  },
18627
19422
  });
18628
19423
  return true;
@@ -18639,18 +19434,25 @@ class LiquidCommerceRmnClient {
18639
19434
  */
18640
19435
  injectOneSpotElement(injectItem, placement, spot, config) {
18641
19436
  var _a;
18642
- const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
18643
19437
  this.eventService.handleSpotState(injectItem.placementId, {
19438
+ identifier: {
19439
+ placementId: injectItem.placementId,
19440
+ spotType: injectItem.spotType,
19441
+ spotId: spot.id,
19442
+ },
18644
19443
  displayConfig: {
18645
19444
  isSingleItem: true,
19445
+ isCarousel: false,
19446
+ isCarouselItem: false,
18646
19447
  },
18647
- }, false);
18648
- // Create the spot template element
19448
+ });
19449
+ const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
18649
19450
  const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
18650
19451
  if (!content) {
18651
19452
  this.eventService.handleSpotState(injectItem.placementId, {
18652
19453
  state: {
18653
19454
  error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
19455
+ mounted: false,
18654
19456
  loading: false,
18655
19457
  },
18656
19458
  });
@@ -18671,6 +19473,7 @@ class LiquidCommerceRmnClient {
18671
19473
  this.eventService.handleSpotState(injectItem.placementId, {
18672
19474
  state: {
18673
19475
  error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
19476
+ mounted: false,
18674
19477
  loading: false,
18675
19478
  },
18676
19479
  });
@@ -18685,10 +19488,12 @@ class LiquidCommerceRmnClient {
18685
19488
  this.eventService.handleSpotState(injectItem.placementId, {
18686
19489
  dom: {
18687
19490
  spotElement,
19491
+ visibleOnViewport: false,
18688
19492
  },
18689
19493
  state: {
18690
19494
  mounted: true,
18691
19495
  loading: false,
19496
+ error: undefined,
18692
19497
  },
18693
19498
  });
18694
19499
  return true;
@@ -18709,6 +19514,8 @@ class LiquidCommerceRmnClient {
18709
19514
  this.eventService.handleSpotState(item.placementId, {
18710
19515
  state: {
18711
19516
  error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
19517
+ mounted: false,
19518
+ loading: false,
18712
19519
  },
18713
19520
  });
18714
19521
  return false;
@@ -18724,6 +19531,8 @@ class LiquidCommerceRmnClient {
18724
19531
  this.eventService.handleSpotState(item.placementId, {
18725
19532
  state: {
18726
19533
  error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
19534
+ mounted: false,
19535
+ loading: false,
18727
19536
  },
18728
19537
  });
18729
19538
  continue;
@@ -18732,6 +19541,7 @@ class LiquidCommerceRmnClient {
18732
19541
  }
18733
19542
  return newInject;
18734
19543
  }
19544
+ // Initialize spots with loading state and identifiers
18735
19545
  updateSpotsState(inject) {
18736
19546
  for (const item of inject) {
18737
19547
  this.eventService.handleSpotState(item.placementId, {
@@ -18741,6 +19551,8 @@ class LiquidCommerceRmnClient {
18741
19551
  },
18742
19552
  state: {
18743
19553
  loading: true,
19554
+ mounted: false,
19555
+ error: undefined,
18744
19556
  },
18745
19557
  });
18746
19558
  }
@@ -18832,4 +19644,4 @@ function RmnCreateSpotElement(spot, config) {
18832
19644
  });
18833
19645
  }
18834
19646
 
18835
- export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement, RmnEventManager };
19647
+ export { LiquidCommerceRmnClient, RMN_ENV, RMN_EVENT, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement, RmnEventManager };