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