@liquidcommercedev/rmn-sdk 1.5.0-beta.15 → 1.5.0-beta.17
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +1624 -1456
- package/dist/index.esm.js +1624 -1456
- package/dist/types/common/helpers/extract-deep.helper.d.ts +14 -0
- package/dist/types/common/helpers/index.d.ts +1 -0
- package/dist/types/common/helpers/utils.helper.d.ts +13 -16
- package/dist/types/modules/helper-service/localstorage.service.d.ts +9 -1
- package/dist/types/modules/monitor/monitor.interface.d.ts +1 -0
- package/dist/types/modules/selection/selection.interface.d.ts +7 -1
- package/dist/types/modules/selection/selection.service.d.ts +1 -0
- package/dist/types/rmn-client.d.ts +10 -34
- package/dist/types/rmn-client.helper.d.ts +41 -0
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.esm.js
CHANGED
@@ -78,574 +78,6 @@ var RMN_ENV;
|
|
78
78
|
RMN_ENV["PRODUCTION"] = "production";
|
79
79
|
})(RMN_ENV || (RMN_ENV = {}));
|
80
80
|
|
81
|
-
const SPOT_EVENTS_EXAMPLE = [
|
82
|
-
{
|
83
|
-
event: RMN_SPOT_EVENT.CLICK,
|
84
|
-
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
|
85
|
-
},
|
86
|
-
{
|
87
|
-
event: RMN_SPOT_EVENT.IMPRESSION,
|
88
|
-
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
|
89
|
-
},
|
90
|
-
{
|
91
|
-
event: RMN_SPOT_EVENT.PURCHASE,
|
92
|
-
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
|
93
|
-
},
|
94
|
-
{
|
95
|
-
event: RMN_SPOT_EVENT.ADD_TO_CART,
|
96
|
-
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
|
97
|
-
},
|
98
|
-
{
|
99
|
-
event: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
|
100
|
-
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
|
101
|
-
},
|
102
|
-
{
|
103
|
-
event: RMN_SPOT_EVENT.BUY_NOW,
|
104
|
-
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
|
105
|
-
},
|
106
|
-
];
|
107
|
-
const RB_SPOTS_SELECTION_EXAMPLE = {
|
108
|
-
rbHomepageHero: [
|
109
|
-
{
|
110
|
-
id: 'abc123',
|
111
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
112
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
113
|
-
width: 1140,
|
114
|
-
height: 640,
|
115
|
-
header: 'Premium Wine Collection',
|
116
|
-
description: 'Discover our exclusive selection of vintage wines',
|
117
|
-
ctaText: 'Shop Wines',
|
118
|
-
textColor: '#ffffff',
|
119
|
-
ctaTextColor: '#ffffff',
|
120
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Collection',
|
121
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Wine',
|
122
|
-
events: SPOT_EVENTS_EXAMPLE,
|
123
|
-
productIds: [1, 2, 3],
|
124
|
-
},
|
125
|
-
{
|
126
|
-
id: 'jkl012',
|
127
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
128
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
129
|
-
width: 1140,
|
130
|
-
height: 640,
|
131
|
-
header: 'Whiskey Collection',
|
132
|
-
description: 'Premium whiskeys from around the world',
|
133
|
-
ctaText: 'Shop Whiskeys',
|
134
|
-
textColor: '#ffffff',
|
135
|
-
backgroundColor: '#2c1810',
|
136
|
-
ctaTextColor: '#2c1810',
|
137
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey',
|
138
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
|
139
|
-
events: SPOT_EVENTS_EXAMPLE,
|
140
|
-
productIds: [10, 11],
|
141
|
-
},
|
142
|
-
{
|
143
|
-
id: 'stu901',
|
144
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
145
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
146
|
-
width: 1140,
|
147
|
-
height: 640,
|
148
|
-
header: 'Summer Cocktails',
|
149
|
-
description: 'Essential spirits for summer mixing',
|
150
|
-
ctaText: 'Mix It Up',
|
151
|
-
textColor: '#ffffff',
|
152
|
-
backgroundColor: '#4d3a0a',
|
153
|
-
ctaTextColor: '#4d3a0a',
|
154
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Cocktails',
|
155
|
-
secondaryImage: 'https://placehold.co/1140x640/png?text=Mixers',
|
156
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktails',
|
157
|
-
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Mixers',
|
158
|
-
events: SPOT_EVENTS_EXAMPLE,
|
159
|
-
productIds: [16, 17, 18],
|
160
|
-
},
|
161
|
-
{
|
162
|
-
id: 'def456',
|
163
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
164
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
165
|
-
width: 1140,
|
166
|
-
height: 640,
|
167
|
-
header: 'Craft Beer Festival',
|
168
|
-
description: 'Local breweries and exclusive releases',
|
169
|
-
ctaText: 'Explore Beers',
|
170
|
-
textColor: '#ffffff',
|
171
|
-
ctaTextColor: '#ffffff',
|
172
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Beer+Festival',
|
173
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Beer',
|
174
|
-
events: SPOT_EVENTS_EXAMPLE,
|
175
|
-
productIds: [4, 5, 6],
|
176
|
-
},
|
177
|
-
{
|
178
|
-
id: 'mno345',
|
179
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
180
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
181
|
-
width: 1140,
|
182
|
-
height: 640,
|
183
|
-
header: 'Champagne Selection',
|
184
|
-
description: 'Finest champagnes for every occasion',
|
185
|
-
ctaText: 'View Champagnes',
|
186
|
-
textColor: '#ffffff',
|
187
|
-
backgroundColor: '#1a1a1a',
|
188
|
-
ctaTextColor: '#1a1a1a',
|
189
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Champagne',
|
190
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Champagne',
|
191
|
-
events: SPOT_EVENTS_EXAMPLE,
|
192
|
-
productIds: [12, 13],
|
193
|
-
},
|
194
|
-
{
|
195
|
-
id: 'vwx234',
|
196
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
197
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
198
|
-
width: 1140,
|
199
|
-
height: 640,
|
200
|
-
header: 'Wine Regions',
|
201
|
-
description: 'Explore wines from top regions',
|
202
|
-
ctaText: 'Tour Regions',
|
203
|
-
textColor: '#ffffff',
|
204
|
-
backgroundColor: '#4d0a0a',
|
205
|
-
ctaTextColor: '#4d0a0a',
|
206
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Regions',
|
207
|
-
secondaryImage: 'https://placehold.co/1140x640/png?text=Vineyards',
|
208
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Regions',
|
209
|
-
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Vineyards',
|
210
|
-
events: SPOT_EVENTS_EXAMPLE,
|
211
|
-
productIds: [19, 20, 21],
|
212
|
-
},
|
213
|
-
{
|
214
|
-
id: 'ghi789',
|
215
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
216
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
217
|
-
width: 1140,
|
218
|
-
height: 640,
|
219
|
-
header: 'Rare Spirits',
|
220
|
-
description: 'Limited edition spirits collection',
|
221
|
-
ctaText: 'View Collection',
|
222
|
-
textColor: '#ffffff',
|
223
|
-
ctaTextColor: '#ffffff',
|
224
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Rare+Spirits',
|
225
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Spirits',
|
226
|
-
events: SPOT_EVENTS_EXAMPLE,
|
227
|
-
productIds: [7, 8, 9],
|
228
|
-
},
|
229
|
-
{
|
230
|
-
id: 'pqr678',
|
231
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
232
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
233
|
-
width: 1140,
|
234
|
-
height: 640,
|
235
|
-
header: 'Gin Collection',
|
236
|
-
description: 'Artisanal gins and botanicals',
|
237
|
-
ctaText: 'Explore Gins',
|
238
|
-
textColor: '#ffffff',
|
239
|
-
backgroundColor: '#0a4d4d',
|
240
|
-
ctaTextColor: '#0a4d4d',
|
241
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Gin',
|
242
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gin',
|
243
|
-
events: SPOT_EVENTS_EXAMPLE,
|
244
|
-
productIds: [14, 15],
|
245
|
-
},
|
246
|
-
{
|
247
|
-
id: 'yz5678',
|
248
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
249
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
250
|
-
width: 1140,
|
251
|
-
height: 640,
|
252
|
-
header: 'Tequila Collection',
|
253
|
-
description: 'Premium tequilas and mezcals',
|
254
|
-
ctaText: 'Shop Tequila',
|
255
|
-
textColor: '#ffffff',
|
256
|
-
backgroundColor: '#0a4d2b',
|
257
|
-
ctaTextColor: '#0a4d2b',
|
258
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Tequila',
|
259
|
-
secondaryImage: 'https://placehold.co/1140x640/png?text=Mezcal',
|
260
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Tequila',
|
261
|
-
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Mezcal',
|
262
|
-
events: SPOT_EVENTS_EXAMPLE,
|
263
|
-
productIds: [22, 23, 24],
|
264
|
-
},
|
265
|
-
],
|
266
|
-
rbHomepageHeroFullImage: [
|
267
|
-
{
|
268
|
-
id: 'hjk567',
|
269
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
270
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
271
|
-
width: 1140,
|
272
|
-
height: 640,
|
273
|
-
header: 'Holiday Gift Guide',
|
274
|
-
description: 'Perfect spirits for every occasion',
|
275
|
-
ctaText: 'Shop Gifts',
|
276
|
-
textColor: '#ffffff',
|
277
|
-
ctaTextColor: '#ffffff',
|
278
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Gift+Guide',
|
279
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gifts',
|
280
|
-
events: SPOT_EVENTS_EXAMPLE,
|
281
|
-
productIds: [25, 26],
|
282
|
-
},
|
283
|
-
{
|
284
|
-
id: 'qwe890',
|
285
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
286
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
287
|
-
width: 1140,
|
288
|
-
height: 640,
|
289
|
-
header: 'Summer Wine Festival',
|
290
|
-
description: 'Refreshing wines for summer',
|
291
|
-
ctaText: 'Shop Festival',
|
292
|
-
textColor: '#ffffff',
|
293
|
-
ctaTextColor: '#ffffff',
|
294
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Festival',
|
295
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Festival',
|
296
|
-
events: SPOT_EVENTS_EXAMPLE,
|
297
|
-
productIds: [27, 28],
|
298
|
-
},
|
299
|
-
],
|
300
|
-
rbHomepageHeroTwoTile: [
|
301
|
-
{
|
302
|
-
id: 'iop987',
|
303
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
304
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
305
|
-
width: 1140,
|
306
|
-
height: 640,
|
307
|
-
header: 'Bourbon Selection',
|
308
|
-
description: "Kentucky's finest bourbons",
|
309
|
-
ctaText: 'Shop Bourbon',
|
310
|
-
textColor: '#ffffff',
|
311
|
-
backgroundColor: '#2c1810',
|
312
|
-
ctaTextColor: '#2c1810',
|
313
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Bourbon',
|
314
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Bourbon',
|
315
|
-
events: SPOT_EVENTS_EXAMPLE,
|
316
|
-
productIds: [29, 30],
|
317
|
-
},
|
318
|
-
{
|
319
|
-
id: 'lkj012',
|
320
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
321
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
322
|
-
width: 1140,
|
323
|
-
height: 640,
|
324
|
-
header: 'Vodka Collection',
|
325
|
-
description: 'Premium vodkas from around the world',
|
326
|
-
ctaText: 'Shop Vodka',
|
327
|
-
textColor: '#ffffff',
|
328
|
-
backgroundColor: '#1a1a1a',
|
329
|
-
ctaTextColor: '#1a1a1a',
|
330
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Vodka',
|
331
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Vodka',
|
332
|
-
events: SPOT_EVENTS_EXAMPLE,
|
333
|
-
productIds: [31, 32],
|
334
|
-
},
|
335
|
-
],
|
336
|
-
rbHomepageHeroThreeTile: [
|
337
|
-
{
|
338
|
-
id: 'bnm345',
|
339
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
340
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
341
|
-
width: 1140,
|
342
|
-
height: 640,
|
343
|
-
header: 'Rum Collection',
|
344
|
-
description: 'Caribbean and craft rums',
|
345
|
-
ctaText: 'Shop Rum',
|
346
|
-
textColor: '#ffffff',
|
347
|
-
backgroundColor: '#4d3a0a',
|
348
|
-
ctaTextColor: '#4d3a0a',
|
349
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Rum',
|
350
|
-
secondaryImage: 'https://placehold.co/1140x640/png?text=Craft+Rum',
|
351
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Rum',
|
352
|
-
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Craft',
|
353
|
-
events: SPOT_EVENTS_EXAMPLE,
|
354
|
-
productIds: [33, 34],
|
355
|
-
},
|
356
|
-
{
|
357
|
-
id: 'fgh678',
|
358
|
-
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
359
|
-
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
360
|
-
width: 1140,
|
361
|
-
height: 640,
|
362
|
-
header: 'Scotch Selection',
|
363
|
-
description: 'Single malts and blends',
|
364
|
-
ctaText: 'Shop Scotch',
|
365
|
-
textColor: '#ffffff',
|
366
|
-
backgroundColor: '#4d0a0a',
|
367
|
-
ctaTextColor: '#4d0a0a',
|
368
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Scotch',
|
369
|
-
secondaryImage: 'https://placehold.co/1140x640/png?text=Single+Malts',
|
370
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Scotch',
|
371
|
-
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Malts',
|
372
|
-
events: SPOT_EVENTS_EXAMPLE,
|
373
|
-
productIds: [35, 36],
|
374
|
-
},
|
375
|
-
],
|
376
|
-
rbLargeCategoryImageTout: [
|
377
|
-
{
|
378
|
-
id: 'cde567',
|
379
|
-
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
380
|
-
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
381
|
-
width: 468,
|
382
|
-
height: 410,
|
383
|
-
header: 'Rare & Limited Edition',
|
384
|
-
description: 'Discover our collection of hard-to-find and limited release spirits.',
|
385
|
-
textColor: '#ffffff',
|
386
|
-
ctaTextColor: '#ffffff',
|
387
|
-
primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
|
388
|
-
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
|
389
|
-
ctaText: 'Shop Rare Spirits',
|
390
|
-
events: SPOT_EVENTS_EXAMPLE,
|
391
|
-
productIds: [37, 38, 39, 40, 41],
|
392
|
-
},
|
393
|
-
{
|
394
|
-
id: 'efg789',
|
395
|
-
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
396
|
-
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
397
|
-
width: 468,
|
398
|
-
height: 410,
|
399
|
-
header: 'Vintage Champagnes',
|
400
|
-
description: 'Explore our prestigious collection of aged champagnes.',
|
401
|
-
textColor: '#ffffff',
|
402
|
-
ctaTextColor: '#ffffff',
|
403
|
-
primaryImage: 'https://placehold.co/468x410/png?text=Vintage+Champagne',
|
404
|
-
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Champagne',
|
405
|
-
ctaText: 'View Collection',
|
406
|
-
events: SPOT_EVENTS_EXAMPLE,
|
407
|
-
productIds: [42, 43, 44, 45, 46],
|
408
|
-
},
|
409
|
-
{
|
410
|
-
id: 'ghi012',
|
411
|
-
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
412
|
-
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
413
|
-
width: 468,
|
414
|
-
height: 410,
|
415
|
-
header: 'Small Batch Bourbon',
|
416
|
-
description: 'Hand-selected premium bourbon from craft distilleries.',
|
417
|
-
textColor: '#ffffff',
|
418
|
-
ctaTextColor: '#ffffff',
|
419
|
-
primaryImage: 'https://placehold.co/468x410/png?text=Craft+Bourbon',
|
420
|
-
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Bourbon',
|
421
|
-
ctaText: 'Explore Bourbon',
|
422
|
-
events: SPOT_EVENTS_EXAMPLE,
|
423
|
-
productIds: [47, 48, 49, 50, 51],
|
424
|
-
},
|
425
|
-
],
|
426
|
-
rbSmallDiscoverTout: [
|
427
|
-
{
|
428
|
-
id: 'jkl345',
|
429
|
-
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
430
|
-
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
431
|
-
width: 224,
|
432
|
-
height: 378,
|
433
|
-
header: 'Château Margaux 2015 Bordeaux',
|
434
|
-
textColor: '#ffffff',
|
435
|
-
primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
|
436
|
-
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
|
437
|
-
events: SPOT_EVENTS_EXAMPLE,
|
438
|
-
productIds: [52, 53, 54, 55, 56],
|
439
|
-
},
|
440
|
-
{
|
441
|
-
id: 'lmn678',
|
442
|
-
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
443
|
-
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
444
|
-
width: 224,
|
445
|
-
height: 378,
|
446
|
-
header: 'Macallan 25 Year',
|
447
|
-
textColor: '#ffffff',
|
448
|
-
primaryImage: 'https://placehold.co/224x378/png?text=Macallan+25',
|
449
|
-
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Macallan',
|
450
|
-
events: SPOT_EVENTS_EXAMPLE,
|
451
|
-
productIds: [57, 58, 59, 60, 61],
|
452
|
-
},
|
453
|
-
{
|
454
|
-
id: 'nop901',
|
455
|
-
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
456
|
-
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
457
|
-
width: 224,
|
458
|
-
height: 378,
|
459
|
-
header: 'Louis XIII Cognac',
|
460
|
-
textColor: '#ffffff',
|
461
|
-
primaryImage: 'https://placehold.co/224x378/png?text=Louis+XIII',
|
462
|
-
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Louis+XIII',
|
463
|
-
events: SPOT_EVENTS_EXAMPLE,
|
464
|
-
productIds: [62, 63, 64, 65, 66],
|
465
|
-
},
|
466
|
-
],
|
467
|
-
rbSmallCategoryImageTout: [
|
468
|
-
{
|
469
|
-
id: 'qrs234',
|
470
|
-
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
471
|
-
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
472
|
-
width: 224,
|
473
|
-
height: 410,
|
474
|
-
header: 'Japanese Sake',
|
475
|
-
textColor: '#ffffff',
|
476
|
-
primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
|
477
|
-
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
|
478
|
-
events: SPOT_EVENTS_EXAMPLE,
|
479
|
-
productIds: [67, 68, 69, 70, 71],
|
480
|
-
},
|
481
|
-
{
|
482
|
-
id: 'stu567',
|
483
|
-
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
484
|
-
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
485
|
-
width: 224,
|
486
|
-
height: 410,
|
487
|
-
header: 'Craft Vermouth',
|
488
|
-
textColor: '#ffffff',
|
489
|
-
primaryImage: 'https://placehold.co/224x410/png?text=Craft+Vermouth',
|
490
|
-
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Vermouth',
|
491
|
-
events: SPOT_EVENTS_EXAMPLE,
|
492
|
-
productIds: [72, 73, 74, 75, 76],
|
493
|
-
},
|
494
|
-
{
|
495
|
-
id: 'vwx890',
|
496
|
-
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
497
|
-
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
498
|
-
width: 224,
|
499
|
-
height: 410,
|
500
|
-
header: 'Premium Mezcal',
|
501
|
-
textColor: '#ffffff',
|
502
|
-
primaryImage: 'https://placehold.co/224x410/png?text=Premium+Mezcal',
|
503
|
-
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Mezcal',
|
504
|
-
events: SPOT_EVENTS_EXAMPLE,
|
505
|
-
productIds: [77, 78, 79, 80, 81],
|
506
|
-
},
|
507
|
-
],
|
508
|
-
rbCollectionBannerWithoutTextBlock: [
|
509
|
-
{
|
510
|
-
id: 'yz1234',
|
511
|
-
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
512
|
-
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
513
|
-
width: 887,
|
514
|
-
height: 344,
|
515
|
-
primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
|
516
|
-
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
|
517
|
-
events: SPOT_EVENTS_EXAMPLE,
|
518
|
-
productIds: [82, 83, 84, 85, 86],
|
519
|
-
},
|
520
|
-
{
|
521
|
-
id: 'abc567',
|
522
|
-
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
523
|
-
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
524
|
-
width: 887,
|
525
|
-
height: 344,
|
526
|
-
primaryImage: 'https://placehold.co/887x344/png?text=Holiday+Spirits',
|
527
|
-
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Holiday+Spirits',
|
528
|
-
events: SPOT_EVENTS_EXAMPLE,
|
529
|
-
productIds: [87, 88, 89, 90, 91],
|
530
|
-
},
|
531
|
-
{
|
532
|
-
id: 'def901',
|
533
|
-
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
534
|
-
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
535
|
-
width: 887,
|
536
|
-
height: 344,
|
537
|
-
primaryImage: 'https://placehold.co/887x344/png?text=Wine+Essentials',
|
538
|
-
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Wine+Essentials',
|
539
|
-
events: SPOT_EVENTS_EXAMPLE,
|
540
|
-
productIds: [92, 93, 94, 95, 96],
|
541
|
-
},
|
542
|
-
],
|
543
|
-
rbNavigationBanner: [
|
544
|
-
{
|
545
|
-
id: 'ghi234',
|
546
|
-
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
547
|
-
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
548
|
-
width: 440,
|
549
|
-
height: 220,
|
550
|
-
header: 'Explore Tequilas',
|
551
|
-
textColor: '#ffffff',
|
552
|
-
primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
|
553
|
-
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
|
554
|
-
events: SPOT_EVENTS_EXAMPLE,
|
555
|
-
productIds: [97, 98, 99, 100, 101],
|
556
|
-
},
|
557
|
-
{
|
558
|
-
id: 'jkl678',
|
559
|
-
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
560
|
-
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
561
|
-
width: 440,
|
562
|
-
height: 220,
|
563
|
-
header: 'Craft Gin Selection',
|
564
|
-
textColor: '#ffffff',
|
565
|
-
primaryImage: 'https://placehold.co/440x220/png?text=Gin+Selection',
|
566
|
-
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Gin+Selection',
|
567
|
-
events: SPOT_EVENTS_EXAMPLE,
|
568
|
-
productIds: [102, 103, 104, 105, 106],
|
569
|
-
},
|
570
|
-
{
|
571
|
-
id: 'mno012',
|
572
|
-
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
573
|
-
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
574
|
-
width: 440,
|
575
|
-
height: 220,
|
576
|
-
header: 'Premium Vodka',
|
577
|
-
textColor: '#ffffff',
|
578
|
-
primaryImage: 'https://placehold.co/440x220/png?text=Vodka+Premium',
|
579
|
-
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Vodka+Premium',
|
580
|
-
events: SPOT_EVENTS_EXAMPLE,
|
581
|
-
productIds: [107, 108, 109, 110, 111],
|
582
|
-
},
|
583
|
-
],
|
584
|
-
};
|
585
|
-
const IAB_SPOTS_SELECTION_EXAMPLE = {
|
586
|
-
banner: [],
|
587
|
-
billboard: [
|
588
|
-
{
|
589
|
-
id: 'kol567',
|
590
|
-
spot: RMN_SPOT_TYPE.BILLBOARD,
|
591
|
-
variant: `${RMN_SPOT_TYPE.BILLBOARD}V2`,
|
592
|
-
width: 1140,
|
593
|
-
height: 640,
|
594
|
-
header: 'Holiday Gift Guide',
|
595
|
-
description: 'Perfect spirits for every occasion',
|
596
|
-
ctaText: 'Shop Gifts',
|
597
|
-
textColor: '#ffffff',
|
598
|
-
ctaTextColor: '#ffffff',
|
599
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Gift+Guide',
|
600
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gifts',
|
601
|
-
events: SPOT_EVENTS_EXAMPLE,
|
602
|
-
productIds: [25, 26],
|
603
|
-
},
|
604
|
-
{
|
605
|
-
id: 'hpm390',
|
606
|
-
spot: RMN_SPOT_TYPE.BILLBOARD,
|
607
|
-
variant: `${RMN_SPOT_TYPE.BILLBOARD}V2`,
|
608
|
-
width: 1140,
|
609
|
-
height: 640,
|
610
|
-
header: 'Summer Wine Festival',
|
611
|
-
description: 'Refreshing wines for summer',
|
612
|
-
ctaText: 'Shop Festival',
|
613
|
-
textColor: '#ffffff',
|
614
|
-
ctaTextColor: '#ffffff',
|
615
|
-
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Festival',
|
616
|
-
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Festival',
|
617
|
-
events: SPOT_EVENTS_EXAMPLE,
|
618
|
-
productIds: [27, 28],
|
619
|
-
},
|
620
|
-
],
|
621
|
-
button2: [],
|
622
|
-
featurePhoneLargeBanner: [],
|
623
|
-
featurePhoneMediumBanner: [],
|
624
|
-
featurePhoneSmallBanner: [],
|
625
|
-
halfPage: [],
|
626
|
-
inText: [],
|
627
|
-
largeLeaderboard: [],
|
628
|
-
largeRectangle: [],
|
629
|
-
leaderboard: [],
|
630
|
-
mediumRectangle: [],
|
631
|
-
microBar: [],
|
632
|
-
mobilePhoneInterstitial1: [],
|
633
|
-
mobilePhoneInterstitial2: [],
|
634
|
-
mobilePhoneInterstitial3: [],
|
635
|
-
popUp: [],
|
636
|
-
portrait: [],
|
637
|
-
rbProductUpcs: [],
|
638
|
-
skyscraper: [],
|
639
|
-
smallRectangle: [],
|
640
|
-
smallSquare: [],
|
641
|
-
smartphoneBanner1: [],
|
642
|
-
smartphoneBanner2: [],
|
643
|
-
square: [],
|
644
|
-
verticalBanner: [],
|
645
|
-
verticalRectangle: [],
|
646
|
-
wideSkyscraper: [],
|
647
|
-
};
|
648
|
-
|
649
81
|
const REQUEST_CLOUD_PARTNER_SITE = 'X-Liquid-Partner-Site';
|
650
82
|
const REQUEST_CLOUD_PROTECTED_KEY = 'X-Liquid-Protected';
|
651
83
|
const REQUEST_CLOUD_PROTECTED_TIMESTAMP = 'X-Liquid-Timestamp';
|
@@ -6692,8 +6124,122 @@ function getEventTypeFromRawEvent(event) {
|
|
6692
6124
|
if (matchesKeywordPattern(words, required, optional)) {
|
6693
6125
|
return eventType;
|
6694
6126
|
}
|
6695
|
-
}
|
6696
|
-
return null;
|
6127
|
+
}
|
6128
|
+
return null;
|
6129
|
+
}
|
6130
|
+
|
6131
|
+
// Configuration object with target field names
|
6132
|
+
const extractorConfig = {
|
6133
|
+
ids: [
|
6134
|
+
// Universal product identifiers
|
6135
|
+
'gtin',
|
6136
|
+
'gtin8',
|
6137
|
+
'gtin12',
|
6138
|
+
'gtin13',
|
6139
|
+
'gtin14',
|
6140
|
+
'mpn',
|
6141
|
+
'sku',
|
6142
|
+
'upc',
|
6143
|
+
'ean',
|
6144
|
+
'isbn',
|
6145
|
+
'isbn10',
|
6146
|
+
'isbn13',
|
6147
|
+
'asin',
|
6148
|
+
// Product codes and references
|
6149
|
+
'coupon',
|
6150
|
+
'barcode',
|
6151
|
+
'product_code',
|
6152
|
+
'part_number',
|
6153
|
+
'model_number',
|
6154
|
+
'item_variant',
|
6155
|
+
'item_number',
|
6156
|
+
'article_number',
|
6157
|
+
'reference',
|
6158
|
+
'groupingId',
|
6159
|
+
],
|
6160
|
+
price: [
|
6161
|
+
'price',
|
6162
|
+
'unitPrice',
|
6163
|
+
'cost',
|
6164
|
+
'current_price',
|
6165
|
+
'sale_price',
|
6166
|
+
'price_value',
|
6167
|
+
'sale_price_value',
|
6168
|
+
'regular_price',
|
6169
|
+
'discount_price',
|
6170
|
+
'unit_price',
|
6171
|
+
'original_price',
|
6172
|
+
'final_price',
|
6173
|
+
'retail_price',
|
6174
|
+
],
|
6175
|
+
};
|
6176
|
+
/**
|
6177
|
+
* Extracts deep values from an object based on specified target type
|
6178
|
+
* @param data - The source data object to extract values from
|
6179
|
+
* @param target - The type of values to extract ('ids' or 'price')
|
6180
|
+
* @param options - Optional configuration for the extraction process
|
6181
|
+
* @returns Array of extracted values or a single value if onlyFirst is true
|
6182
|
+
*/
|
6183
|
+
function extractDeepValues(data, target, options = {}) {
|
6184
|
+
const {
|
6185
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
6186
|
+
onlyFirst = false, shouldIncludeZero = false, } = options;
|
6187
|
+
const values = [];
|
6188
|
+
const targetProperties = new Set(extractorConfig[target].map((name) => name.toLowerCase()));
|
6189
|
+
/**
|
6190
|
+
* Checks if a property name matches the target criteria
|
6191
|
+
*/
|
6192
|
+
const isTargetField = (key) => {
|
6193
|
+
const normalizedKey = key.toLowerCase();
|
6194
|
+
const hasTarget = targetProperties.has(normalizedKey);
|
6195
|
+
if (target === 'ids') {
|
6196
|
+
return normalizedKey.endsWith('id') || normalizedKey.endsWith('ids') || hasTarget;
|
6197
|
+
}
|
6198
|
+
return hasTarget;
|
6199
|
+
};
|
6200
|
+
/**
|
6201
|
+
* Validates and normalizes extracted values
|
6202
|
+
*/
|
6203
|
+
const validateValue = (value) => {
|
6204
|
+
if (typeof value === 'string') {
|
6205
|
+
return value.trim().length > 0;
|
6206
|
+
}
|
6207
|
+
if (typeof value === 'number') {
|
6208
|
+
return !isNaN(value) && (shouldIncludeZero || value !== 0);
|
6209
|
+
}
|
6210
|
+
return false;
|
6211
|
+
};
|
6212
|
+
/**
|
6213
|
+
* Processes a value and extracts matching fields
|
6214
|
+
*/
|
6215
|
+
const processValue = (value, currentKey) => {
|
6216
|
+
// Early exit conditions
|
6217
|
+
if (value == null || (onlyFirst && values.length > 0))
|
6218
|
+
return;
|
6219
|
+
// Process current value if it matches target criteria
|
6220
|
+
if (currentKey && isTargetField(currentKey)) {
|
6221
|
+
if (Array.isArray(value)) {
|
6222
|
+
const validValues = value.filter(validateValue);
|
6223
|
+
values.push(...validValues);
|
6224
|
+
}
|
6225
|
+
else if (validateValue(value)) {
|
6226
|
+
values.push(value);
|
6227
|
+
}
|
6228
|
+
return;
|
6229
|
+
}
|
6230
|
+
// Recursive processing for nested structures
|
6231
|
+
if (Array.isArray(value)) {
|
6232
|
+
value.forEach((item) => processValue(item));
|
6233
|
+
}
|
6234
|
+
else if (typeof value === 'object') {
|
6235
|
+
Object.entries(value).forEach(([key, val]) => processValue(val, key));
|
6236
|
+
}
|
6237
|
+
};
|
6238
|
+
processValue(data);
|
6239
|
+
// Return based on options
|
6240
|
+
if (values.length === 0)
|
6241
|
+
return undefined;
|
6242
|
+
return onlyFirst ? values[0] : values;
|
6697
6243
|
}
|
6698
6244
|
|
6699
6245
|
class SingletonManager {
|
@@ -6861,97 +6407,6 @@ class ObjectHelper {
|
|
6861
6407
|
}
|
6862
6408
|
}
|
6863
6409
|
|
6864
|
-
/**
|
6865
|
-
* Recursively extracts ID values from a nested data structure.
|
6866
|
-
* Searches for specified property names and collects their primitive values (strings/numbers).
|
6867
|
-
* Captures properties ending with 'id' and any additional specified property names.
|
6868
|
-
*
|
6869
|
-
* @param data - The data structure to search through (can be nested objects/arrays)
|
6870
|
-
* @param propertyNames - Array of additional property names to look for (optional)
|
6871
|
-
* @returns Array of extracted ID values (strings/numbers only)
|
6872
|
-
*
|
6873
|
-
* @example
|
6874
|
-
* const data = {
|
6875
|
-
* id: [1, 2, 3],
|
6876
|
-
* nested: { id: 'abc', userId: 123 },
|
6877
|
-
* items: [{ id: 456, productId: '789', sku: 'ABC123' }]
|
6878
|
-
* };
|
6879
|
-
* extractDeepIds(data); // Returns [1, 2, 3, 'abc', 123, 456, '789', 'ABC123']
|
6880
|
-
*/
|
6881
|
-
function extractDeepIds(data, propertyNames) {
|
6882
|
-
const ids = [];
|
6883
|
-
const defaultPropertyNames = [
|
6884
|
-
// Universal product identifiers
|
6885
|
-
'gtin', // Global Trade Item Number
|
6886
|
-
'gtin8', // 8-digit GTIN
|
6887
|
-
'gtin12', // 12-digit GTIN (UPC)
|
6888
|
-
'gtin13', // 13-digit GTIN (EAN)
|
6889
|
-
'gtin14', // 14-digit GTIN
|
6890
|
-
'mpn', // Manufacturer Part Number
|
6891
|
-
'sku', // Stock Keeping Unit
|
6892
|
-
'upc', // Universal Product Code
|
6893
|
-
'ean', // European Article Number
|
6894
|
-
'isbn', // International Standard Book Number
|
6895
|
-
'isbn10', // 10-digit ISBN
|
6896
|
-
'isbn13', // 13-digit ISBN
|
6897
|
-
'asin', // Amazon Standard Identification Number
|
6898
|
-
// Product codes and references
|
6899
|
-
'coupon',
|
6900
|
-
'barcode',
|
6901
|
-
'product_code',
|
6902
|
-
'part_number',
|
6903
|
-
'model_number',
|
6904
|
-
'item_variant',
|
6905
|
-
'item_number',
|
6906
|
-
'article_number',
|
6907
|
-
'reference',
|
6908
|
-
'groupingId',
|
6909
|
-
];
|
6910
|
-
// Convert property names to lowercase for consistent comparison
|
6911
|
-
const additionalProperties = new Set((defaultPropertyNames).map((name) => name.toLowerCase()));
|
6912
|
-
/**
|
6913
|
-
* Checks if a property name is an ID field
|
6914
|
-
* @param key - The property name to check
|
6915
|
-
* @returns boolean indicating if the key is an ID field
|
6916
|
-
*/
|
6917
|
-
const isIdField = (key) => {
|
6918
|
-
const lowercaseKey = key.toLowerCase();
|
6919
|
-
return lowercaseKey.endsWith('id') || additionalProperties.has(lowercaseKey);
|
6920
|
-
};
|
6921
|
-
/**
|
6922
|
-
* Processes a value and extracts IDs if it matches criteria
|
6923
|
-
* @param value - The value to process
|
6924
|
-
* @param currentKey - The property name of the current value
|
6925
|
-
*/
|
6926
|
-
const processValue = (value, currentKey) => {
|
6927
|
-
// Early exit for null/undefined values
|
6928
|
-
if (value == null)
|
6929
|
-
return;
|
6930
|
-
// If current key matches our target properties
|
6931
|
-
if (currentKey && isIdField(currentKey)) {
|
6932
|
-
if (Array.isArray(value)) {
|
6933
|
-
// Filter and push valid array values in one pass
|
6934
|
-
ids.push(...value.filter((item) => typeof item === 'string' || typeof item === 'number'));
|
6935
|
-
}
|
6936
|
-
else if (typeof value === 'string' || typeof value === 'number') {
|
6937
|
-
ids.push(value);
|
6938
|
-
}
|
6939
|
-
return; // Stop processing this branch after handling the ID
|
6940
|
-
}
|
6941
|
-
// Recursively process nested structures
|
6942
|
-
if (Array.isArray(value)) {
|
6943
|
-
value.forEach((item) => processValue(item));
|
6944
|
-
}
|
6945
|
-
else if (typeof value === 'object') {
|
6946
|
-
// Process all enumerable properties
|
6947
|
-
for (const [key, val] of Object.entries(value)) {
|
6948
|
-
processValue(val, key);
|
6949
|
-
}
|
6950
|
-
}
|
6951
|
-
};
|
6952
|
-
processValue(data);
|
6953
|
-
return ids;
|
6954
|
-
}
|
6955
6410
|
// Fallback method using fetch if sendBeacon isn't available
|
6956
6411
|
async function fallbackEventFire(url) {
|
6957
6412
|
try {
|
@@ -6977,22 +6432,49 @@ async function fallbackEventFire(url) {
|
|
6977
6432
|
return false;
|
6978
6433
|
}
|
6979
6434
|
}
|
6435
|
+
/**
|
6436
|
+
* Helper function to decode base64 string and parse JSON
|
6437
|
+
*
|
6438
|
+
* @param {string} base64String - The base64 encoded JSON string
|
6439
|
+
* @returns {T | null} - Decoded and parsed object or null if invalid
|
6440
|
+
*/
|
6441
|
+
function decodeBase64Json(base64String) {
|
6442
|
+
try {
|
6443
|
+
return JSON.parse(atob(base64String));
|
6444
|
+
}
|
6445
|
+
catch (_a) {
|
6446
|
+
return null;
|
6447
|
+
}
|
6448
|
+
}
|
6980
6449
|
/**
|
6981
6450
|
* Extracts and decodes a URL from a base64-encoded query parameter.
|
6982
6451
|
*
|
6983
6452
|
* @param {string} url - The URL containing the base64-encoded query parameter.
|
6984
6453
|
* @returns {string | null} - The decoded URL or null if not found or invalid.
|
6454
|
+
* @throws {Error} - If URL is malformed or payload is invalid.
|
6985
6455
|
*/
|
6986
6456
|
function getRedirectUrlFromPayload(url) {
|
6457
|
+
if (!url)
|
6458
|
+
return null;
|
6987
6459
|
try {
|
6988
|
-
|
6989
|
-
|
6460
|
+
// Extract initial payload
|
6461
|
+
const payload = new URL(url).searchParams.get('p');
|
6462
|
+
if (!payload)
|
6990
6463
|
return null;
|
6991
|
-
|
6992
|
-
const
|
6993
|
-
|
6464
|
+
// Decode first layer
|
6465
|
+
const decodedData = decodeBase64Json(payload);
|
6466
|
+
if (!(decodedData === null || decodedData === void 0 ? void 0 : decodedData.u))
|
6467
|
+
return null;
|
6468
|
+
// Extract URL from nested query
|
6469
|
+
const eventPayload = new URLSearchParams(decodedData.u).get('e');
|
6470
|
+
if (!eventPayload)
|
6471
|
+
return null;
|
6472
|
+
// Decode second layer
|
6473
|
+
const eventData = decodeBase64Json(eventPayload);
|
6474
|
+
return (eventData === null || eventData === void 0 ? void 0 : eventData.ur) || null;
|
6994
6475
|
}
|
6995
6476
|
catch (_a) {
|
6477
|
+
console.warn('RmnSdk: Failed to extract redirect URL from payload.');
|
6996
6478
|
return null;
|
6997
6479
|
}
|
6998
6480
|
}
|
@@ -7052,6 +6534,23 @@ function calculateScaleFactor(elementScale) {
|
|
7052
6534
|
// Math.max ensures the value isn't less than minScale
|
7053
6535
|
return Math.max(minScale, Math.min(maxScale, scaleFactor));
|
7054
6536
|
}
|
6537
|
+
/**
|
6538
|
+
* Converts an object to a query string.
|
6539
|
+
*
|
6540
|
+
* @param {Record<string, string|number|undefined|null>} obj - The object to be converted to a query string.
|
6541
|
+
* @returns {string} - The query string.
|
6542
|
+
*/
|
6543
|
+
function objectToQueryParams(obj) {
|
6544
|
+
return Object.entries(obj !== null && obj !== void 0 ? obj : {})
|
6545
|
+
.map(([key, value]) => {
|
6546
|
+
if (value == null) {
|
6547
|
+
return '';
|
6548
|
+
}
|
6549
|
+
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
6550
|
+
})
|
6551
|
+
.filter(Boolean)
|
6552
|
+
.join('&');
|
6553
|
+
}
|
7055
6554
|
|
7056
6555
|
class UniqueIdGenerator {
|
7057
6556
|
/**
|
@@ -16260,6 +15759,7 @@ class LocalStorageService {
|
|
16260
15759
|
console.warn('Local storage is not supported in this environment');
|
16261
15760
|
return;
|
16262
15761
|
}
|
15762
|
+
this.setUserId();
|
16263
15763
|
this.spots = new Map();
|
16264
15764
|
// Sync local storage with the current state
|
16265
15765
|
this.syncLocalStorage();
|
@@ -16346,6 +15846,49 @@ class LocalStorageService {
|
|
16346
15846
|
});
|
16347
15847
|
this.updateLocalStorage();
|
16348
15848
|
}
|
15849
|
+
// ======================== Utility functions ======================== //
|
15850
|
+
getUserId() {
|
15851
|
+
const key = LocalStorageService.localStorageKey;
|
15852
|
+
if (!key) {
|
15853
|
+
this.setUserId();
|
15854
|
+
}
|
15855
|
+
return key.replace(`${LocalStorageService.localStorageKeyPrefix}_`, '');
|
15856
|
+
}
|
15857
|
+
/**
|
15858
|
+
* Sets the user ID in the local storage.
|
15859
|
+
* If no existing key is found,
|
15860
|
+
* it generates a new unique ID and sets it as the local storage key.
|
15861
|
+
*/
|
15862
|
+
setUserId() {
|
15863
|
+
const prefix = LocalStorageService.localStorageKeyPrefix;
|
15864
|
+
const existingKeys = Object.keys(window.localStorage).filter((key) => key.startsWith(prefix));
|
15865
|
+
const setNewKey = () => {
|
15866
|
+
const uniqueId = UniqueIdGenerator.generate();
|
15867
|
+
const newLocalStorageKey = `${prefix}_${uniqueId}`;
|
15868
|
+
window.localStorage.setItem(newLocalStorageKey, '');
|
15869
|
+
LocalStorageService.localStorageKey = newLocalStorageKey;
|
15870
|
+
};
|
15871
|
+
if (existingKeys.length === 0) {
|
15872
|
+
setNewKey();
|
15873
|
+
}
|
15874
|
+
else {
|
15875
|
+
const validKey = existingKeys.find((key) => UniqueIdGenerator.isValid(key.replace(`${prefix}_`, '')));
|
15876
|
+
// Delete all other keys except the valid one
|
15877
|
+
existingKeys.forEach((key) => {
|
15878
|
+
if (key !== validKey) {
|
15879
|
+
window.localStorage.removeItem(key);
|
15880
|
+
}
|
15881
|
+
});
|
15882
|
+
if (validKey) {
|
15883
|
+
// Found a valid key, assign it to localStorageKey
|
15884
|
+
LocalStorageService.localStorageKey = validKey;
|
15885
|
+
}
|
15886
|
+
else {
|
15887
|
+
// No valid key found, generate a new key
|
15888
|
+
setNewKey();
|
15889
|
+
}
|
15890
|
+
}
|
15891
|
+
}
|
16349
15892
|
mapToObject(map) {
|
16350
15893
|
return Object.fromEntries(map);
|
16351
15894
|
}
|
@@ -16399,7 +15942,8 @@ class LocalStorageService {
|
|
16399
15942
|
return atob(data);
|
16400
15943
|
}
|
16401
15944
|
}
|
16402
|
-
LocalStorageService.
|
15945
|
+
LocalStorageService.localStorageKeyPrefix = 'lc_rmn';
|
15946
|
+
LocalStorageService.localStorageKey = '';
|
16403
15947
|
LocalStorageService.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
16404
15948
|
LocalStorageService.encryptData = true;
|
16405
15949
|
|
@@ -18838,651 +18382,1357 @@ const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
18838
18382
|
font-size: 28px;
|
18839
18383
|
}
|
18840
18384
|
|
18841
|
-
.${prefix}__description {
|
18842
|
-
font-size: 14px;
|
18843
|
-
}
|
18385
|
+
.${prefix}__description {
|
18386
|
+
font-size: 14px;
|
18387
|
+
}
|
18388
|
+
|
18389
|
+
.${prefix}__cta-button {
|
18390
|
+
font-size: 13px;
|
18391
|
+
}
|
18392
|
+
}
|
18393
|
+
|
18394
|
+
@container (min-width: 1280px) {
|
18395
|
+
.${prefix}__cta-button {
|
18396
|
+
font-size: 14px;
|
18397
|
+
}
|
18398
|
+
}
|
18399
|
+
</style>
|
18400
|
+
`;
|
18401
|
+
};
|
18402
|
+
function rbLargeCategoryImageToutTemplate(spot, config) {
|
18403
|
+
const { prefix = '' } = config;
|
18404
|
+
return `
|
18405
|
+
${GFONT_PRECONNECT}
|
18406
|
+
${GFONT_SOURCE_SANS_3}
|
18407
|
+
${GFONT_CORMORANT}
|
18408
|
+
${STYLES$3(spot, config)}
|
18409
|
+
<div class="${prefix}">
|
18410
|
+
<div class="${prefix}__text">
|
18411
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
18412
|
+
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
18413
|
+
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
18414
|
+
</div>
|
18415
|
+
</div>
|
18416
|
+
`;
|
18417
|
+
}
|
18418
|
+
|
18419
|
+
const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
|
18420
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
18421
|
+
return `
|
18422
|
+
<style>
|
18423
|
+
.${prefix} {
|
18424
|
+
width: 100%;
|
18425
|
+
height: 100%;
|
18426
|
+
display: flex;
|
18427
|
+
flex-direction: column;
|
18428
|
+
justify-content: flex-end;
|
18429
|
+
border-radius: 5px;
|
18430
|
+
overflow: hidden;
|
18431
|
+
cursor: pointer;
|
18432
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
|
18433
|
+
background-size: cover;
|
18434
|
+
background-position: center;
|
18435
|
+
background-repeat: no-repeat;
|
18436
|
+
position: relative;
|
18437
|
+
}
|
18438
|
+
|
18439
|
+
.${prefix}__header {
|
18440
|
+
font-size: 16px;
|
18441
|
+
color: ${textColor};
|
18442
|
+
line-height: 20px;
|
18443
|
+
font-weight: 400;
|
18444
|
+
font-family: "Source Sans 3", system-ui;
|
18445
|
+
font-style: normal;
|
18446
|
+
margin: 0;
|
18447
|
+
padding: 15px 10%;
|
18448
|
+
}
|
18449
|
+
|
18450
|
+
@container (min-width: 640px) {
|
18451
|
+
.${prefix} {
|
18452
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
18453
|
+
}
|
18454
|
+
}
|
18455
|
+
|
18456
|
+
@container (min-width: 768px) {
|
18457
|
+
.${prefix}__header {
|
18458
|
+
font-size: 22px;
|
18459
|
+
}
|
18460
|
+
}
|
18461
|
+
|
18462
|
+
@container (min-width: 1024px) {
|
18463
|
+
.${prefix}__header {
|
18464
|
+
font-size: 24px;
|
18465
|
+
}
|
18466
|
+
}
|
18467
|
+
|
18468
|
+
@container (min-width: 1280px) {
|
18469
|
+
.${prefix}__header {
|
18470
|
+
font-size: 28px;
|
18471
|
+
}
|
18472
|
+
}
|
18473
|
+
</style>
|
18474
|
+
`;
|
18475
|
+
};
|
18476
|
+
function rbNavigationBannerTemplate(spot, config) {
|
18477
|
+
const { prefix = '' } = config;
|
18478
|
+
return `
|
18479
|
+
${GFONT_PRECONNECT}
|
18480
|
+
${GFONT_SOURCE_SANS_3}
|
18481
|
+
${STYLES$2(spot, config)}
|
18482
|
+
<div class="${prefix}">
|
18483
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
18484
|
+
</div>
|
18485
|
+
`;
|
18486
|
+
}
|
18487
|
+
|
18488
|
+
const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
|
18489
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
18490
|
+
return `
|
18491
|
+
<style>
|
18492
|
+
.${prefix} {
|
18493
|
+
width: 100%;
|
18494
|
+
height: 100%;
|
18495
|
+
display: flex;
|
18496
|
+
flex-direction: column;
|
18497
|
+
justify-content: flex-end;
|
18498
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${mobilePrimaryImage}");
|
18499
|
+
background-size: cover;
|
18500
|
+
background-repeat: no-repeat;
|
18501
|
+
background-position: center;
|
18502
|
+
border-radius: 5px;
|
18503
|
+
overflow: hidden;
|
18504
|
+
cursor: pointer;
|
18505
|
+
position: relative;
|
18506
|
+
}
|
18507
|
+
|
18508
|
+
.${prefix}__header {
|
18509
|
+
font-size: 12px;
|
18510
|
+
color: ${textColor};
|
18511
|
+
line-height: 16px;
|
18512
|
+
font-family: "Source Sans 3", system-ui;
|
18513
|
+
font-style: normal;
|
18514
|
+
font-weight: 400;
|
18515
|
+
margin: 0;
|
18516
|
+
padding: 10px;
|
18517
|
+
}
|
18518
|
+
|
18519
|
+
@container (min-width: 640px) {
|
18520
|
+
.${prefix} {
|
18521
|
+
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
18522
|
+
}
|
18523
|
+
}
|
18524
|
+
</style>
|
18525
|
+
`;
|
18526
|
+
};
|
18527
|
+
function rbSmallCategoryImageToutTemplate(spot, config) {
|
18528
|
+
const { prefix = '' } = config;
|
18529
|
+
return `
|
18530
|
+
${GFONT_PRECONNECT}
|
18531
|
+
${GFONT_CORMORANT}
|
18532
|
+
${STYLES$1(spot, config)}
|
18533
|
+
<div class="${prefix}">
|
18534
|
+
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
18535
|
+
</div>
|
18536
|
+
`;
|
18537
|
+
}
|
18538
|
+
|
18539
|
+
const STYLES = ({ textColor = '#000000', backgroundColor = 'transparent', primaryImage, mobilePrimaryImage = primaryImage, }, { prefix }) => `
|
18540
|
+
<style>
|
18541
|
+
.${prefix} {
|
18542
|
+
width: 100%;
|
18543
|
+
height: 100%;
|
18544
|
+
background-color: ${backgroundColor};
|
18545
|
+
cursor: pointer;
|
18546
|
+
display: flex;
|
18547
|
+
flex-direction: column;
|
18548
|
+
border-radius: 5px;
|
18549
|
+
}
|
18550
|
+
|
18551
|
+
.${prefix}__image {
|
18552
|
+
width: 100%;
|
18553
|
+
height: 100%;
|
18554
|
+
background-image: url("${mobilePrimaryImage}");
|
18555
|
+
background-size: cover;
|
18556
|
+
background-repeat: no-repeat;
|
18557
|
+
background-position: center;
|
18558
|
+
border-radius: 5px;
|
18559
|
+
}
|
18560
|
+
|
18561
|
+
.${prefix}__text {
|
18562
|
+
text-align: left;
|
18563
|
+
display: flex;
|
18564
|
+
flex-direction: row;
|
18565
|
+
align-items: flex-start;
|
18566
|
+
justify-content: flex-start;
|
18567
|
+
width: 100%;
|
18568
|
+
height: fit-content;
|
18569
|
+
position: relative;
|
18570
|
+
}
|
18844
18571
|
|
18845
|
-
|
18846
|
-
|
18847
|
-
|
18848
|
-
|
18572
|
+
.${prefix}__header {
|
18573
|
+
font-size: 12px;
|
18574
|
+
color: ${textColor};
|
18575
|
+
padding-top: 5px;
|
18576
|
+
line-height: 16px;
|
18577
|
+
font-family: "Source Sans 3", system-ui;
|
18578
|
+
font-style: normal;
|
18579
|
+
font-weight: 400;
|
18580
|
+
margin: 0;
|
18581
|
+
}
|
18849
18582
|
|
18850
|
-
|
18851
|
-
|
18852
|
-
|
18853
|
-
}
|
18583
|
+
@container (min-width: 640px) {
|
18584
|
+
.${prefix}__image {
|
18585
|
+
background-image: url("${primaryImage}");
|
18854
18586
|
}
|
18855
|
-
|
18856
|
-
|
18857
|
-
|
18858
|
-
function
|
18587
|
+
}
|
18588
|
+
</style>
|
18589
|
+
`;
|
18590
|
+
function rbSmallDiscoverToutTemplate(spot, config) {
|
18859
18591
|
const { prefix = '' } = config;
|
18860
18592
|
return `
|
18861
18593
|
${GFONT_PRECONNECT}
|
18862
|
-
${GFONT_SOURCE_SANS_3}
|
18863
18594
|
${GFONT_CORMORANT}
|
18864
|
-
${STYLES
|
18595
|
+
${STYLES(spot, config)}
|
18865
18596
|
<div class="${prefix}">
|
18597
|
+
<div class="${prefix}__image"></div>
|
18866
18598
|
<div class="${prefix}__text">
|
18867
18599
|
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
18868
|
-
${spot.description ? `<p class="${prefix}__description">${spot.description}</p>` : ''}
|
18869
|
-
${spot.ctaText ? `<span class="${prefix}__cta-button">${spot.ctaText}</span>` : ''}
|
18870
18600
|
</div>
|
18871
18601
|
</div>
|
18872
18602
|
`;
|
18873
18603
|
}
|
18874
18604
|
|
18875
|
-
|
18876
|
-
|
18877
|
-
|
18878
|
-
|
18879
|
-
|
18880
|
-
|
18881
|
-
|
18882
|
-
|
18883
|
-
|
18884
|
-
|
18885
|
-
|
18886
|
-
|
18887
|
-
|
18888
|
-
|
18889
|
-
|
18890
|
-
|
18891
|
-
|
18892
|
-
|
18605
|
+
/**
|
18606
|
+
* Returns the HTML element for the given spot.
|
18607
|
+
*
|
18608
|
+
* @param {ISpot} spot - The spot object.
|
18609
|
+
* @param {ISpotTemplateConfig} config - The spot template configuration.
|
18610
|
+
*
|
18611
|
+
* @return {HTMLElement | null} - The HTML element for the given spot or null if the spot template is not found.
|
18612
|
+
*/
|
18613
|
+
const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
18614
|
+
const templates = {
|
18615
|
+
// Reserve Bar Spot Templates
|
18616
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE]: {
|
18617
|
+
rbHomepageHeroThreeTile: rbHomepageHeroThreeTileTemplate,
|
18618
|
+
},
|
18619
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE]: {
|
18620
|
+
rbHomepageHeroTwoTile: rbHomepageHeroTwoTileTemplate,
|
18621
|
+
},
|
18622
|
+
[RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE]: {
|
18623
|
+
rbHomepageHeroFullImage: rbHomepageHeroFullImageTemplate,
|
18624
|
+
},
|
18625
|
+
[RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT]: {
|
18626
|
+
rbLargeCategoryImageTout: rbLargeCategoryImageToutTemplate,
|
18627
|
+
},
|
18628
|
+
[RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT]: {
|
18629
|
+
rbSmallDiscoverTout: rbSmallDiscoverToutTemplate,
|
18630
|
+
},
|
18631
|
+
[RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT]: {
|
18632
|
+
rbSmallCategoryImageTout: rbSmallCategoryImageToutTemplate,
|
18633
|
+
},
|
18634
|
+
[RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK]: {
|
18635
|
+
rbCollectionBannerWithoutTextBlock: rbCollectionBannerWithoutTextBlockTemplate,
|
18636
|
+
},
|
18637
|
+
[RMN_SPOT_TYPE.RB_NAVIGATION_BANNER]: {
|
18638
|
+
rbNavigationBanner: rbNavigationBannerTemplate,
|
18639
|
+
},
|
18640
|
+
[RMN_SPOT_TYPE.RB_PRODUCT_UPCS]: {
|
18641
|
+
rbProductUpcs: () => '', // No template for this spot type, it will be handled by ReserveBar App.
|
18642
|
+
},
|
18643
|
+
// IAB Standard Spot Templates
|
18644
|
+
[RMN_SPOT_TYPE.BILLBOARD]: {
|
18645
|
+
billboardV1: billboardV1Template,
|
18646
|
+
billboardV2: billboardV2Template,
|
18647
|
+
billboardV3: billboardV3Template,
|
18648
|
+
},
|
18649
|
+
[RMN_SPOT_TYPE.LARGE_RECTANGLE]: {
|
18650
|
+
largeRectangleV1: largeRectangleV1Template,
|
18651
|
+
},
|
18652
|
+
[RMN_SPOT_TYPE.VERTICAL_RECTANGLE]: {
|
18653
|
+
verticalRectangleV1: verticalRectangleV1Template,
|
18654
|
+
},
|
18655
|
+
[RMN_SPOT_TYPE.SQUARE]: {
|
18656
|
+
squareV1: squareV1Template,
|
18657
|
+
squareV2: squareV2Template,
|
18658
|
+
},
|
18659
|
+
[RMN_SPOT_TYPE.LARGE_LEADERBOARD]: {
|
18660
|
+
largeLeaderboardV1: largeLeaderboardV1Template,
|
18661
|
+
largeLeaderboardV2: largeLeaderboardV2Template,
|
18662
|
+
},
|
18663
|
+
[RMN_SPOT_TYPE.WIDE_SKYSCRAPER]: {
|
18664
|
+
wideSkyscraperV1: wideSkyscraperV1Template,
|
18665
|
+
},
|
18666
|
+
[RMN_SPOT_TYPE.IN_TEXT]: {
|
18667
|
+
inTextV1: inTextV1Template,
|
18668
|
+
},
|
18669
|
+
};
|
18670
|
+
const spotVariants = templates[spot.spot];
|
18671
|
+
if (!spotVariants) {
|
18672
|
+
return null;
|
18673
|
+
}
|
18674
|
+
const variantTemplate = spotVariants[spot.variant];
|
18675
|
+
if (!variantTemplate) {
|
18676
|
+
return null;
|
18677
|
+
}
|
18678
|
+
// Generate a highly unique prefix to avoid conflicts with other elements.
|
18679
|
+
const prefix = 's' + UniqueIdGenerator.generate().toLowerCase();
|
18680
|
+
const spotHtmlString = variantTemplate(spot, { ...config, prefix });
|
18681
|
+
return spotHtmlStringToElement(spotHtmlString);
|
18682
|
+
};
|
18683
|
+
|
18684
|
+
// For the moment, we will only focus on sites that use Google Analytics,
|
18685
|
+
// but we will add support for other analytics tools in the future.
|
18686
|
+
var AnalyticsTool;
|
18687
|
+
(function (AnalyticsTool) {
|
18688
|
+
AnalyticsTool["GoogleAnalytics"] = "google-analytics";
|
18689
|
+
AnalyticsTool["Other"] = "Other";
|
18690
|
+
})(AnalyticsTool || (AnalyticsTool = {}));
|
18691
|
+
|
18692
|
+
class DataLayerMonitor {
|
18693
|
+
constructor() {
|
18694
|
+
if (!window.dataLayer) {
|
18695
|
+
return;
|
18696
|
+
}
|
18697
|
+
this.originalPush = window.dataLayer.push;
|
18698
|
+
}
|
18699
|
+
static getInstance() {
|
18700
|
+
if (!DataLayerMonitor.instance) {
|
18701
|
+
DataLayerMonitor.instance = new DataLayerMonitor();
|
18702
|
+
}
|
18703
|
+
return DataLayerMonitor.instance;
|
18704
|
+
}
|
18705
|
+
setListener(listener) {
|
18706
|
+
this.listener = listener;
|
18707
|
+
}
|
18708
|
+
start() {
|
18709
|
+
window.dataLayer.push = (...args) => {
|
18710
|
+
const result = this.originalPush.apply(window.dataLayer, args);
|
18711
|
+
const pushedEvent = args[0];
|
18712
|
+
if (this.listener) {
|
18713
|
+
const normalizedData = this.cleanEventData(pushedEvent);
|
18714
|
+
if (normalizedData) {
|
18715
|
+
this.listener(normalizedData);
|
18716
|
+
}
|
18717
|
+
}
|
18718
|
+
return result;
|
18719
|
+
};
|
18720
|
+
}
|
18721
|
+
cleanEventData(data) {
|
18722
|
+
const eventName = getEventTypeFromRawEvent(data.event);
|
18723
|
+
if (!eventName) {
|
18724
|
+
return null;
|
18725
|
+
}
|
18726
|
+
const productIds = extractDeepValues(data, 'ids', {
|
18727
|
+
onlyFirst: false,
|
18728
|
+
shouldIncludeZero: true,
|
18729
|
+
});
|
18730
|
+
if (Array.isArray(productIds) && productIds.length === 0) {
|
18731
|
+
return null;
|
18732
|
+
}
|
18733
|
+
const normalizedData = {
|
18734
|
+
event: eventName,
|
18735
|
+
productIds,
|
18736
|
+
};
|
18737
|
+
if (eventName === RMN_SPOT_EVENT.PURCHASE) {
|
18738
|
+
const productPrice = extractDeepValues(data, 'price', {
|
18739
|
+
onlyFirst: true,
|
18740
|
+
shouldIncludeZero: true,
|
18741
|
+
});
|
18742
|
+
if (productPrice) {
|
18743
|
+
normalizedData.productPrice = productPrice;
|
18744
|
+
}
|
18745
|
+
}
|
18746
|
+
return normalizedData;
|
18747
|
+
}
|
18748
|
+
stop() {
|
18749
|
+
if (this.originalPush) {
|
18750
|
+
window.dataLayer.push = this.originalPush;
|
18751
|
+
}
|
18752
|
+
this.listener = undefined;
|
18753
|
+
}
|
18754
|
+
}
|
18755
|
+
|
18756
|
+
// @TODO: Add support for user to push events to our own data layer, if they don't use any analytics tool.
|
18757
|
+
// window.rmnDataLayer = window.rmnDataLayer || [];
|
18758
|
+
class MonitorService {
|
18759
|
+
constructor() {
|
18760
|
+
const analyticsTool = this.detectAnalyticsTool();
|
18761
|
+
switch (analyticsTool) {
|
18762
|
+
case AnalyticsTool.GoogleAnalytics:
|
18763
|
+
this.implementedMonitor = DataLayerMonitor.getInstance();
|
18764
|
+
break;
|
18765
|
+
case AnalyticsTool.Other:
|
18766
|
+
default:
|
18767
|
+
console.warn('This site uses an unsupported analytics tool.');
|
18768
|
+
break;
|
18769
|
+
}
|
18770
|
+
if (analyticsTool === AnalyticsTool.Other) {
|
18771
|
+
return;
|
18772
|
+
}
|
18773
|
+
this.pubSubService = PubsubService.getInstance();
|
18774
|
+
this.localStorageService = LocalStorageService.getInstance();
|
18775
|
+
}
|
18776
|
+
static getInstance() {
|
18777
|
+
if (!MonitorService.instance) {
|
18778
|
+
MonitorService.instance = new MonitorService();
|
18779
|
+
}
|
18780
|
+
return MonitorService.instance;
|
18781
|
+
}
|
18782
|
+
start() {
|
18783
|
+
if (!this.implementedMonitor)
|
18784
|
+
return;
|
18785
|
+
this.implementedMonitor.setListener(async (eventData) => {
|
18786
|
+
var _a;
|
18787
|
+
await this.matchAndFireEvent(eventData, (_a = this.localStorageService) === null || _a === void 0 ? void 0 : _a.getSpots());
|
18788
|
+
});
|
18789
|
+
this.implementedMonitor.start();
|
18790
|
+
}
|
18791
|
+
async matchAndFireEvent(eventData, spots) {
|
18792
|
+
var _a, _b;
|
18793
|
+
if (!spots)
|
18794
|
+
return;
|
18795
|
+
const eventProductIds = new Set(eventData.productIds.map((productId) => String(productId)));
|
18796
|
+
for (const spot of Object.values(spots)) {
|
18797
|
+
if (!spot.productIds.length)
|
18798
|
+
continue;
|
18799
|
+
const hasCommonProductIds = spot.productIds.find((productId) => eventProductIds.has(String(productId)));
|
18800
|
+
if (!hasCommonProductIds || !Object.values(RMN_SPOT_EVENT).includes(eventData.event)) {
|
18801
|
+
continue;
|
18802
|
+
}
|
18803
|
+
const eventUrl = (_b = (_a = spot.events.find((event) => event.event === eventData.event)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '';
|
18804
|
+
const additionalQueryParams = objectToQueryParams({
|
18805
|
+
override: eventData.productPrice,
|
18806
|
+
});
|
18807
|
+
await this.fireAndPublishSpotEvent({
|
18808
|
+
spotEvent: eventData.event,
|
18809
|
+
eventUrl: `${eventUrl}${additionalQueryParams ? `&${additionalQueryParams}` : ''}`,
|
18810
|
+
placementId: spot.placementId,
|
18811
|
+
spotId: spot.spotId,
|
18812
|
+
});
|
18813
|
+
}
|
18814
|
+
}
|
18815
|
+
async fireAndPublishSpotEvent({ spotEvent, eventUrl, placementId, spotId, }) {
|
18816
|
+
await fireEvent({
|
18817
|
+
event: spotEvent,
|
18818
|
+
eventUrl,
|
18819
|
+
});
|
18820
|
+
if (!this.pubSubService)
|
18821
|
+
return;
|
18822
|
+
this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
|
18823
|
+
eventType: spotEvent,
|
18824
|
+
placementId,
|
18825
|
+
spotId,
|
18826
|
+
});
|
18827
|
+
}
|
18828
|
+
detectAnalyticsTool() {
|
18829
|
+
let analyticsTool = AnalyticsTool.Other;
|
18830
|
+
// Check for Google Analytics
|
18831
|
+
if (typeof window.ga !== 'undefined') {
|
18832
|
+
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
18833
|
+
}
|
18834
|
+
// Check for Google Analytics 4
|
18835
|
+
if (typeof window.gtag !== 'undefined') {
|
18836
|
+
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
18837
|
+
}
|
18838
|
+
// Check for Google Tag Manager
|
18839
|
+
if (typeof window.google_tag_manager !== 'undefined') {
|
18840
|
+
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
18841
|
+
}
|
18842
|
+
// @TODO: Add support for other analytics tools
|
18843
|
+
// Check for Heap Analytics
|
18844
|
+
// Check for Mixpanel
|
18845
|
+
// Check for Woopra
|
18846
|
+
// Check for Segment
|
18847
|
+
// Check for Amplitude
|
18848
|
+
return analyticsTool;
|
18849
|
+
}
|
18850
|
+
}
|
18851
|
+
|
18852
|
+
class EventService {
|
18853
|
+
constructor() {
|
18854
|
+
this.pubSubService = PubsubService.getInstance();
|
18855
|
+
this.localStorageService = LocalStorageService.getInstance();
|
18856
|
+
this.activeSpots = new Map();
|
18857
|
+
this.spotStates = new Map();
|
18858
|
+
this.intersectionObserver = new IntersectionObserverService();
|
18859
|
+
// Start the user monitor, which will track and check user interactions
|
18860
|
+
MonitorService.getInstance().start();
|
18893
18861
|
}
|
18894
|
-
|
18895
|
-
|
18896
|
-
|
18897
|
-
|
18898
|
-
|
18899
|
-
font-weight: 400;
|
18900
|
-
font-family: "Source Sans 3", system-ui;
|
18901
|
-
font-style: normal;
|
18902
|
-
margin: 0;
|
18903
|
-
padding: 15px 10%;
|
18862
|
+
static getInstance() {
|
18863
|
+
if (!EventService.instance) {
|
18864
|
+
EventService.instance = new EventService();
|
18865
|
+
}
|
18866
|
+
return EventService.instance;
|
18904
18867
|
}
|
18905
|
-
|
18906
|
-
|
18907
|
-
.${prefix} {
|
18908
|
-
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
18909
|
-
}
|
18868
|
+
subscribe(eventType, callback) {
|
18869
|
+
return this.pubSubService.subscribe(eventType, callback);
|
18910
18870
|
}
|
18911
|
-
|
18912
|
-
|
18913
|
-
.${prefix}__header {
|
18914
|
-
font-size: 22px;
|
18915
|
-
}
|
18871
|
+
publish(eventType, data) {
|
18872
|
+
this.pubSubService.publish(eventType, data);
|
18916
18873
|
}
|
18917
|
-
|
18918
|
-
|
18919
|
-
|
18920
|
-
|
18921
|
-
|
18874
|
+
registerSpot(params) {
|
18875
|
+
const { placementId, spot, spotElement } = params;
|
18876
|
+
this.activeSpots.set(placementId, { spotElement });
|
18877
|
+
// Fire impression event
|
18878
|
+
this.fireImpressionEvent(placementId, spot);
|
18879
|
+
// Handle intersection observer
|
18880
|
+
this.handleIntersectionObserver(placementId, spot, spotElement);
|
18881
|
+
// Attach click event listener
|
18882
|
+
spotElement.addEventListener('click', async () => await this.handleClick(params));
|
18922
18883
|
}
|
18923
|
-
|
18924
|
-
|
18925
|
-
|
18926
|
-
|
18927
|
-
|
18884
|
+
unregisterSpot(placementId) {
|
18885
|
+
const placementIdClean = placementId.replace('#', '');
|
18886
|
+
const spotData = this.activeSpots.get(placementIdClean);
|
18887
|
+
if (!spotData) {
|
18888
|
+
this.handleSpotState(placementIdClean, {
|
18889
|
+
state: {
|
18890
|
+
error: `Active spot with placementId ${placementIdClean} not found.`,
|
18891
|
+
},
|
18892
|
+
});
|
18893
|
+
return;
|
18894
|
+
}
|
18895
|
+
this.intersectionObserver.unobserve(spotData.spotElement);
|
18896
|
+
this.handleSpotState(placementIdClean, {
|
18897
|
+
dom: {
|
18898
|
+
spotElement: undefined,
|
18899
|
+
visibleOnViewport: false,
|
18900
|
+
},
|
18901
|
+
state: {
|
18902
|
+
unmounted: true,
|
18903
|
+
mounted: false,
|
18904
|
+
},
|
18905
|
+
});
|
18906
|
+
this.activeSpots.delete(placementIdClean);
|
18907
|
+
const placementElement = document.getElementById(placementIdClean);
|
18908
|
+
if (!placementElement) {
|
18909
|
+
this.handleSpotState(placementIdClean, {
|
18910
|
+
state: {
|
18911
|
+
error: `Placement element with id ${placementIdClean} not found.`,
|
18912
|
+
},
|
18913
|
+
});
|
18914
|
+
return;
|
18915
|
+
}
|
18916
|
+
placementElement.innerHTML = '';
|
18928
18917
|
}
|
18929
|
-
|
18930
|
-
|
18931
|
-
|
18932
|
-
|
18933
|
-
|
18934
|
-
|
18935
|
-
|
18936
|
-
|
18937
|
-
|
18938
|
-
|
18939
|
-
|
18940
|
-
|
18941
|
-
|
18942
|
-
|
18943
|
-
|
18944
|
-
|
18945
|
-
|
18946
|
-
|
18947
|
-
|
18948
|
-
|
18949
|
-
|
18950
|
-
|
18951
|
-
|
18952
|
-
|
18953
|
-
|
18954
|
-
|
18955
|
-
|
18956
|
-
|
18957
|
-
|
18958
|
-
|
18959
|
-
|
18960
|
-
|
18961
|
-
|
18962
|
-
|
18963
|
-
|
18964
|
-
.${prefix}__header {
|
18965
|
-
font-size: 12px;
|
18966
|
-
color: ${textColor};
|
18967
|
-
line-height: 16px;
|
18968
|
-
font-family: "Source Sans 3", system-ui;
|
18969
|
-
font-style: normal;
|
18970
|
-
font-weight: 400;
|
18971
|
-
margin: 0;
|
18972
|
-
padding: 10px;
|
18973
|
-
}
|
18974
|
-
|
18975
|
-
@container (min-width: 640px) {
|
18976
|
-
.${prefix} {
|
18977
|
-
background-image: linear-gradient(to top, ${linearGradient}), url("${primaryImage}");
|
18918
|
+
/**
|
18919
|
+
* Updates the state of a spot.
|
18920
|
+
*
|
18921
|
+
* @param {string} placementId - The placement ID of the spot.
|
18922
|
+
* @param {Partial<ILifecycleState>} updates - The updates to apply to the spot state.
|
18923
|
+
* @param {boolean} publish - Whether to publish the updated state.
|
18924
|
+
*
|
18925
|
+
* @returns {void}
|
18926
|
+
*/
|
18927
|
+
handleSpotState(placementId, updates, publish = true) {
|
18928
|
+
let currentState = this.spotStates.get(placementId);
|
18929
|
+
if (!currentState) {
|
18930
|
+
currentState = {
|
18931
|
+
identifier: {
|
18932
|
+
placementId,
|
18933
|
+
spotId: '',
|
18934
|
+
spotType: '',
|
18935
|
+
},
|
18936
|
+
dom: {
|
18937
|
+
spotElement: undefined,
|
18938
|
+
visibleOnViewport: false,
|
18939
|
+
},
|
18940
|
+
state: {
|
18941
|
+
mounted: false,
|
18942
|
+
unmounted: false,
|
18943
|
+
loading: false,
|
18944
|
+
error: undefined,
|
18945
|
+
},
|
18946
|
+
displayConfig: {
|
18947
|
+
isCarousel: false,
|
18948
|
+
isCarouselItem: false,
|
18949
|
+
isSingleItem: false,
|
18950
|
+
},
|
18951
|
+
};
|
18978
18952
|
}
|
18979
|
-
|
18980
|
-
|
18981
|
-
|
18982
|
-
|
18983
|
-
|
18984
|
-
|
18985
|
-
|
18986
|
-
|
18987
|
-
|
18988
|
-
|
18989
|
-
|
18990
|
-
|
18991
|
-
|
18992
|
-
|
18953
|
+
const merged = this.deepMerge(currentState, updates);
|
18954
|
+
this.spotStates.set(placementId, merged);
|
18955
|
+
if (publish) {
|
18956
|
+
this.pubSubService.publish(RMN_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
|
18957
|
+
}
|
18958
|
+
}
|
18959
|
+
deepMerge(current, updates) {
|
18960
|
+
return {
|
18961
|
+
identifier: updates.identifier
|
18962
|
+
? { ...current.identifier, ...updates.identifier }
|
18963
|
+
: current.identifier,
|
18964
|
+
dom: updates.dom ? { ...current.dom, ...updates.dom } : current.dom,
|
18965
|
+
state: updates.state ? { ...current.state, ...updates.state } : current.state,
|
18966
|
+
displayConfig: updates.displayConfig
|
18967
|
+
? { ...current.displayConfig, ...updates.displayConfig }
|
18968
|
+
: current.displayConfig,
|
18969
|
+
};
|
18970
|
+
}
|
18971
|
+
async handleClick({ placementId, spot }) {
|
18972
|
+
var _a, _b, _c;
|
18973
|
+
this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
|
18974
|
+
eventType: RMN_SPOT_EVENT.CLICK,
|
18975
|
+
placementId,
|
18976
|
+
spotId: spot.id,
|
18977
|
+
});
|
18978
|
+
await fireEvent({
|
18979
|
+
event: RMN_SPOT_EVENT.CLICK,
|
18980
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
18981
|
+
});
|
18982
|
+
// Save spot to local storage for event tracking
|
18983
|
+
this.localStorageService.setSpot(spot.id, {
|
18984
|
+
placementId,
|
18985
|
+
spotId: spot.id,
|
18986
|
+
spotType: spot.spot,
|
18987
|
+
events: spot.events,
|
18988
|
+
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 2, 3],
|
18989
|
+
});
|
18990
|
+
}
|
18991
|
+
handleIntersectionObserver(placementId, _spot, spotElement) {
|
18992
|
+
const spotIsVisibleCallback = async () => {
|
18993
|
+
this.intersectionObserver.unobserve(spotElement);
|
18994
|
+
this.handleSpotState(placementId, {
|
18995
|
+
dom: {
|
18996
|
+
spotElement,
|
18997
|
+
visibleOnViewport: true,
|
18998
|
+
},
|
18999
|
+
});
|
19000
|
+
};
|
19001
|
+
this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
|
19002
|
+
}
|
19003
|
+
fireImpressionEvent(placementId, spot) {
|
19004
|
+
this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
|
19005
|
+
eventType: RMN_SPOT_EVENT.IMPRESSION,
|
19006
|
+
placementId,
|
19007
|
+
spotId: spot.id,
|
19008
|
+
});
|
19009
|
+
(async () => {
|
19010
|
+
var _a, _b;
|
19011
|
+
await fireEvent({
|
19012
|
+
event: RMN_SPOT_EVENT.IMPRESSION,
|
19013
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
19014
|
+
});
|
19015
|
+
})();
|
19016
|
+
}
|
18993
19017
|
}
|
18994
19018
|
|
18995
|
-
const
|
18996
|
-
<style>
|
18997
|
-
.${prefix} {
|
18998
|
-
width: 100%;
|
18999
|
-
height: 100%;
|
19000
|
-
background-color: ${backgroundColor};
|
19001
|
-
cursor: pointer;
|
19002
|
-
display: flex;
|
19003
|
-
flex-direction: column;
|
19004
|
-
border-radius: 5px;
|
19005
|
-
}
|
19019
|
+
const SELECTION_API_PATH = '/spots/selection';
|
19006
19020
|
|
19007
|
-
|
19008
|
-
|
19009
|
-
|
19010
|
-
background-image: url("${mobilePrimaryImage}");
|
19011
|
-
background-size: cover;
|
19012
|
-
background-repeat: no-repeat;
|
19013
|
-
background-position: center;
|
19014
|
-
border-radius: 5px;
|
19021
|
+
class SelectionService extends BaseApi {
|
19022
|
+
constructor(auth) {
|
19023
|
+
super(auth);
|
19015
19024
|
}
|
19016
|
-
|
19017
|
-
|
19018
|
-
text-align: left;
|
19019
|
-
display: flex;
|
19020
|
-
flex-direction: row;
|
19021
|
-
align-items: flex-start;
|
19022
|
-
justify-content: flex-start;
|
19023
|
-
width: 100%;
|
19024
|
-
height: fit-content;
|
19025
|
-
position: relative;
|
19025
|
+
static getInstance(auth) {
|
19026
|
+
return SingletonManager.getInstance('SelectionService', () => new SelectionService(auth));
|
19026
19027
|
}
|
19027
|
-
|
19028
|
-
|
19029
|
-
|
19030
|
-
|
19031
|
-
|
19032
|
-
|
19033
|
-
|
19034
|
-
|
19035
|
-
|
19036
|
-
|
19028
|
+
/**
|
19029
|
+
* Makes a selection request on our server based on the provided data.
|
19030
|
+
*
|
19031
|
+
* @param {ISpotSelectionParams} data - Spots selection parameters.
|
19032
|
+
*
|
19033
|
+
* @return {Promise<ISpots | { error: string }>} - The spots response object.
|
19034
|
+
*/
|
19035
|
+
async spotSelection(data) {
|
19036
|
+
if (data.userId === undefined) {
|
19037
|
+
data.userId = this.getUserId();
|
19038
|
+
}
|
19039
|
+
const { isOk, val, isErr } = await this.post(SELECTION_API_PATH, data, {});
|
19040
|
+
if (isErr) {
|
19041
|
+
return { error: `There was an error during spot selection: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})` };
|
19042
|
+
}
|
19043
|
+
if (isOk && val && val.data && (val === null || val === void 0 ? void 0 : val.refresh.token)) {
|
19044
|
+
this.authInfo.authenticated = true;
|
19045
|
+
this.authInfo.token = val.refresh.token;
|
19046
|
+
return val.data.spots;
|
19047
|
+
}
|
19048
|
+
return { error: 'Spot selection response was not successful' };
|
19037
19049
|
}
|
19038
|
-
|
19039
|
-
|
19040
|
-
|
19041
|
-
|
19042
|
-
|
19050
|
+
getUserId() {
|
19051
|
+
const isWeb = typeof window !== 'undefined';
|
19052
|
+
if (isWeb) {
|
19053
|
+
const localStorageService = LocalStorageService.getInstance();
|
19054
|
+
return localStorageService.getUserId();
|
19055
|
+
}
|
19056
|
+
return undefined;
|
19043
19057
|
}
|
19044
|
-
</style>
|
19045
|
-
`;
|
19046
|
-
function rbSmallDiscoverToutTemplate(spot, config) {
|
19047
|
-
const { prefix = '' } = config;
|
19048
|
-
return `
|
19049
|
-
${GFONT_PRECONNECT}
|
19050
|
-
${GFONT_CORMORANT}
|
19051
|
-
${STYLES(spot, config)}
|
19052
|
-
<div class="${prefix}">
|
19053
|
-
<div class="${prefix}__image"></div>
|
19054
|
-
<div class="${prefix}__text">
|
19055
|
-
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
19056
|
-
</div>
|
19057
|
-
</div>
|
19058
|
-
`;
|
19059
19058
|
}
|
19060
19059
|
|
19061
|
-
|
19062
|
-
|
19063
|
-
|
19064
|
-
|
19065
|
-
|
19066
|
-
|
19067
|
-
|
19068
|
-
|
19069
|
-
|
19070
|
-
|
19071
|
-
|
19072
|
-
|
19073
|
-
|
19060
|
+
const SPOT_EVENTS_EXAMPLE = [
|
19061
|
+
{
|
19062
|
+
event: RMN_SPOT_EVENT.CLICK,
|
19063
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
|
19064
|
+
},
|
19065
|
+
{
|
19066
|
+
event: RMN_SPOT_EVENT.IMPRESSION,
|
19067
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
|
19068
|
+
},
|
19069
|
+
{
|
19070
|
+
event: RMN_SPOT_EVENT.PURCHASE,
|
19071
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
|
19072
|
+
},
|
19073
|
+
{
|
19074
|
+
event: RMN_SPOT_EVENT.ADD_TO_CART,
|
19075
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
|
19076
|
+
},
|
19077
|
+
{
|
19078
|
+
event: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
|
19079
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
|
19080
|
+
},
|
19081
|
+
{
|
19082
|
+
event: RMN_SPOT_EVENT.BUY_NOW,
|
19083
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
|
19084
|
+
},
|
19085
|
+
];
|
19086
|
+
({
|
19087
|
+
rbHomepageHero: [
|
19088
|
+
{
|
19089
|
+
id: 'abc123',
|
19090
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19091
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19092
|
+
width: 1140,
|
19093
|
+
height: 640,
|
19094
|
+
header: 'Premium Wine Collection',
|
19095
|
+
description: 'Discover our exclusive selection of vintage wines',
|
19096
|
+
ctaText: 'Shop Wines',
|
19097
|
+
textColor: '#ffffff',
|
19098
|
+
ctaTextColor: '#ffffff',
|
19099
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Collection',
|
19100
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Wine',
|
19101
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19102
|
+
productIds: [1, 2, 3],
|
19103
|
+
},
|
19104
|
+
{
|
19105
|
+
id: 'jkl012',
|
19106
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19107
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19108
|
+
width: 1140,
|
19109
|
+
height: 640,
|
19110
|
+
header: 'Whiskey Collection',
|
19111
|
+
description: 'Premium whiskeys from around the world',
|
19112
|
+
ctaText: 'Shop Whiskeys',
|
19113
|
+
textColor: '#ffffff',
|
19114
|
+
backgroundColor: '#2c1810',
|
19115
|
+
ctaTextColor: '#2c1810',
|
19116
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey',
|
19117
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
|
19118
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19119
|
+
productIds: [10, 11],
|
19120
|
+
},
|
19121
|
+
{
|
19122
|
+
id: 'stu901',
|
19123
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19124
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19125
|
+
width: 1140,
|
19126
|
+
height: 640,
|
19127
|
+
header: 'Summer Cocktails',
|
19128
|
+
description: 'Essential spirits for summer mixing',
|
19129
|
+
ctaText: 'Mix It Up',
|
19130
|
+
textColor: '#ffffff',
|
19131
|
+
backgroundColor: '#4d3a0a',
|
19132
|
+
ctaTextColor: '#4d3a0a',
|
19133
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Cocktails',
|
19134
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Mixers',
|
19135
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktails',
|
19136
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Mixers',
|
19137
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19138
|
+
productIds: [16, 17, 18],
|
19139
|
+
},
|
19140
|
+
{
|
19141
|
+
id: 'def456',
|
19142
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19143
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19144
|
+
width: 1140,
|
19145
|
+
height: 640,
|
19146
|
+
header: 'Craft Beer Festival',
|
19147
|
+
description: 'Local breweries and exclusive releases',
|
19148
|
+
ctaText: 'Explore Beers',
|
19149
|
+
textColor: '#ffffff',
|
19150
|
+
ctaTextColor: '#ffffff',
|
19151
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Beer+Festival',
|
19152
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Beer',
|
19153
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19154
|
+
productIds: [4, 5, 6],
|
19155
|
+
},
|
19156
|
+
{
|
19157
|
+
id: 'mno345',
|
19158
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19159
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19160
|
+
width: 1140,
|
19161
|
+
height: 640,
|
19162
|
+
header: 'Champagne Selection',
|
19163
|
+
description: 'Finest champagnes for every occasion',
|
19164
|
+
ctaText: 'View Champagnes',
|
19165
|
+
textColor: '#ffffff',
|
19166
|
+
backgroundColor: '#1a1a1a',
|
19167
|
+
ctaTextColor: '#1a1a1a',
|
19168
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Champagne',
|
19169
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Champagne',
|
19170
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19171
|
+
productIds: [12, 13],
|
19172
|
+
},
|
19173
|
+
{
|
19174
|
+
id: 'vwx234',
|
19175
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19176
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19177
|
+
width: 1140,
|
19178
|
+
height: 640,
|
19179
|
+
header: 'Wine Regions',
|
19180
|
+
description: 'Explore wines from top regions',
|
19181
|
+
ctaText: 'Tour Regions',
|
19182
|
+
textColor: '#ffffff',
|
19183
|
+
backgroundColor: '#4d0a0a',
|
19184
|
+
ctaTextColor: '#4d0a0a',
|
19185
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Regions',
|
19186
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Vineyards',
|
19187
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Regions',
|
19188
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Vineyards',
|
19189
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19190
|
+
productIds: [19, 20, 21],
|
19074
19191
|
},
|
19075
|
-
|
19076
|
-
|
19192
|
+
{
|
19193
|
+
id: 'ghi789',
|
19194
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19195
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19196
|
+
width: 1140,
|
19197
|
+
height: 640,
|
19198
|
+
header: 'Rare Spirits',
|
19199
|
+
description: 'Limited edition spirits collection',
|
19200
|
+
ctaText: 'View Collection',
|
19201
|
+
textColor: '#ffffff',
|
19202
|
+
ctaTextColor: '#ffffff',
|
19203
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Rare+Spirits',
|
19204
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Spirits',
|
19205
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19206
|
+
productIds: [7, 8, 9],
|
19077
19207
|
},
|
19078
|
-
|
19079
|
-
|
19208
|
+
{
|
19209
|
+
id: 'pqr678',
|
19210
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19211
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19212
|
+
width: 1140,
|
19213
|
+
height: 640,
|
19214
|
+
header: 'Gin Collection',
|
19215
|
+
description: 'Artisanal gins and botanicals',
|
19216
|
+
ctaText: 'Explore Gins',
|
19217
|
+
textColor: '#ffffff',
|
19218
|
+
backgroundColor: '#0a4d4d',
|
19219
|
+
ctaTextColor: '#0a4d4d',
|
19220
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Gin',
|
19221
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gin',
|
19222
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19223
|
+
productIds: [14, 15],
|
19080
19224
|
},
|
19081
|
-
|
19082
|
-
|
19225
|
+
{
|
19226
|
+
id: 'yz5678',
|
19227
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19228
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19229
|
+
width: 1140,
|
19230
|
+
height: 640,
|
19231
|
+
header: 'Tequila Collection',
|
19232
|
+
description: 'Premium tequilas and mezcals',
|
19233
|
+
ctaText: 'Shop Tequila',
|
19234
|
+
textColor: '#ffffff',
|
19235
|
+
backgroundColor: '#0a4d2b',
|
19236
|
+
ctaTextColor: '#0a4d2b',
|
19237
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Tequila',
|
19238
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Mezcal',
|
19239
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Tequila',
|
19240
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Mezcal',
|
19241
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19242
|
+
productIds: [22, 23, 24],
|
19083
19243
|
},
|
19084
|
-
|
19085
|
-
|
19244
|
+
],
|
19245
|
+
rbHomepageHeroFullImage: [
|
19246
|
+
{
|
19247
|
+
id: 'hjk567',
|
19248
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19249
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19250
|
+
width: 1140,
|
19251
|
+
height: 640,
|
19252
|
+
header: 'Holiday Gift Guide',
|
19253
|
+
description: 'Perfect spirits for every occasion',
|
19254
|
+
ctaText: 'Shop Gifts',
|
19255
|
+
textColor: '#ffffff',
|
19256
|
+
ctaTextColor: '#ffffff',
|
19257
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Gift+Guide',
|
19258
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gifts',
|
19259
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19260
|
+
productIds: [25, 26],
|
19261
|
+
},
|
19262
|
+
{
|
19263
|
+
id: 'qwe890',
|
19264
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19265
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
19266
|
+
width: 1140,
|
19267
|
+
height: 640,
|
19268
|
+
header: 'Summer Wine Festival',
|
19269
|
+
description: 'Refreshing wines for summer',
|
19270
|
+
ctaText: 'Shop Festival',
|
19271
|
+
textColor: '#ffffff',
|
19272
|
+
ctaTextColor: '#ffffff',
|
19273
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Festival',
|
19274
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Festival',
|
19275
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19276
|
+
productIds: [27, 28],
|
19277
|
+
},
|
19278
|
+
],
|
19279
|
+
rbHomepageHeroTwoTile: [
|
19280
|
+
{
|
19281
|
+
id: 'iop987',
|
19282
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19283
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19284
|
+
width: 1140,
|
19285
|
+
height: 640,
|
19286
|
+
header: 'Bourbon Selection',
|
19287
|
+
description: "Kentucky's finest bourbons",
|
19288
|
+
ctaText: 'Shop Bourbon',
|
19289
|
+
textColor: '#ffffff',
|
19290
|
+
backgroundColor: '#2c1810',
|
19291
|
+
ctaTextColor: '#2c1810',
|
19292
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Bourbon',
|
19293
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Bourbon',
|
19294
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19295
|
+
productIds: [29, 30],
|
19296
|
+
},
|
19297
|
+
{
|
19298
|
+
id: 'lkj012',
|
19299
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19300
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
19301
|
+
width: 1140,
|
19302
|
+
height: 640,
|
19303
|
+
header: 'Vodka Collection',
|
19304
|
+
description: 'Premium vodkas from around the world',
|
19305
|
+
ctaText: 'Shop Vodka',
|
19306
|
+
textColor: '#ffffff',
|
19307
|
+
backgroundColor: '#1a1a1a',
|
19308
|
+
ctaTextColor: '#1a1a1a',
|
19309
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Vodka',
|
19310
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Vodka',
|
19311
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19312
|
+
productIds: [31, 32],
|
19313
|
+
},
|
19314
|
+
],
|
19315
|
+
rbHomepageHeroThreeTile: [
|
19316
|
+
{
|
19317
|
+
id: 'bnm345',
|
19318
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19319
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19320
|
+
width: 1140,
|
19321
|
+
height: 640,
|
19322
|
+
header: 'Rum Collection',
|
19323
|
+
description: 'Caribbean and craft rums',
|
19324
|
+
ctaText: 'Shop Rum',
|
19325
|
+
textColor: '#ffffff',
|
19326
|
+
backgroundColor: '#4d3a0a',
|
19327
|
+
ctaTextColor: '#4d3a0a',
|
19328
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Rum',
|
19329
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Craft+Rum',
|
19330
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Rum',
|
19331
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Craft',
|
19332
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19333
|
+
productIds: [33, 34],
|
19334
|
+
},
|
19335
|
+
{
|
19336
|
+
id: 'fgh678',
|
19337
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19338
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
19339
|
+
width: 1140,
|
19340
|
+
height: 640,
|
19341
|
+
header: 'Scotch Selection',
|
19342
|
+
description: 'Single malts and blends',
|
19343
|
+
ctaText: 'Shop Scotch',
|
19344
|
+
textColor: '#ffffff',
|
19345
|
+
backgroundColor: '#4d0a0a',
|
19346
|
+
ctaTextColor: '#4d0a0a',
|
19347
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Scotch',
|
19348
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Single+Malts',
|
19349
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Scotch',
|
19350
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Malts',
|
19351
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19352
|
+
productIds: [35, 36],
|
19353
|
+
},
|
19354
|
+
],
|
19355
|
+
rbLargeCategoryImageTout: [
|
19356
|
+
{
|
19357
|
+
id: 'cde567',
|
19358
|
+
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
19359
|
+
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
19360
|
+
width: 468,
|
19361
|
+
height: 410,
|
19362
|
+
header: 'Rare & Limited Edition',
|
19363
|
+
description: 'Discover our collection of hard-to-find and limited release spirits.',
|
19364
|
+
textColor: '#ffffff',
|
19365
|
+
ctaTextColor: '#ffffff',
|
19366
|
+
primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
|
19367
|
+
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
|
19368
|
+
ctaText: 'Shop Rare Spirits',
|
19369
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19370
|
+
productIds: [37, 38, 39, 40, 41],
|
19371
|
+
},
|
19372
|
+
{
|
19373
|
+
id: 'efg789',
|
19374
|
+
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
19375
|
+
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
19376
|
+
width: 468,
|
19377
|
+
height: 410,
|
19378
|
+
header: 'Vintage Champagnes',
|
19379
|
+
description: 'Explore our prestigious collection of aged champagnes.',
|
19380
|
+
textColor: '#ffffff',
|
19381
|
+
ctaTextColor: '#ffffff',
|
19382
|
+
primaryImage: 'https://placehold.co/468x410/png?text=Vintage+Champagne',
|
19383
|
+
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Champagne',
|
19384
|
+
ctaText: 'View Collection',
|
19385
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19386
|
+
productIds: [42, 43, 44, 45, 46],
|
19387
|
+
},
|
19388
|
+
{
|
19389
|
+
id: 'ghi012',
|
19390
|
+
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
19391
|
+
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
19392
|
+
width: 468,
|
19393
|
+
height: 410,
|
19394
|
+
header: 'Small Batch Bourbon',
|
19395
|
+
description: 'Hand-selected premium bourbon from craft distilleries.',
|
19396
|
+
textColor: '#ffffff',
|
19397
|
+
ctaTextColor: '#ffffff',
|
19398
|
+
primaryImage: 'https://placehold.co/468x410/png?text=Craft+Bourbon',
|
19399
|
+
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Bourbon',
|
19400
|
+
ctaText: 'Explore Bourbon',
|
19401
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19402
|
+
productIds: [47, 48, 49, 50, 51],
|
19403
|
+
},
|
19404
|
+
],
|
19405
|
+
rbSmallDiscoverTout: [
|
19406
|
+
{
|
19407
|
+
id: 'jkl345',
|
19408
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
19409
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
19410
|
+
width: 224,
|
19411
|
+
height: 378,
|
19412
|
+
header: 'Château Margaux 2015 Bordeaux',
|
19413
|
+
textColor: '#ffffff',
|
19414
|
+
primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
|
19415
|
+
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
|
19416
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19417
|
+
productIds: [52, 53, 54, 55, 56],
|
19418
|
+
},
|
19419
|
+
{
|
19420
|
+
id: 'lmn678',
|
19421
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
19422
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
19423
|
+
width: 224,
|
19424
|
+
height: 378,
|
19425
|
+
header: 'Macallan 25 Year',
|
19426
|
+
textColor: '#ffffff',
|
19427
|
+
primaryImage: 'https://placehold.co/224x378/png?text=Macallan+25',
|
19428
|
+
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Macallan',
|
19429
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19430
|
+
productIds: [57, 58, 59, 60, 61],
|
19431
|
+
},
|
19432
|
+
{
|
19433
|
+
id: 'nop901',
|
19434
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
19435
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
19436
|
+
width: 224,
|
19437
|
+
height: 378,
|
19438
|
+
header: 'Louis XIII Cognac',
|
19439
|
+
textColor: '#ffffff',
|
19440
|
+
primaryImage: 'https://placehold.co/224x378/png?text=Louis+XIII',
|
19441
|
+
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Louis+XIII',
|
19442
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19443
|
+
productIds: [62, 63, 64, 65, 66],
|
19086
19444
|
},
|
19087
|
-
|
19088
|
-
|
19445
|
+
],
|
19446
|
+
rbSmallCategoryImageTout: [
|
19447
|
+
{
|
19448
|
+
id: 'qrs234',
|
19449
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
19450
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
19451
|
+
width: 224,
|
19452
|
+
height: 410,
|
19453
|
+
header: 'Japanese Sake',
|
19454
|
+
textColor: '#ffffff',
|
19455
|
+
primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
|
19456
|
+
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
|
19457
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19458
|
+
productIds: [67, 68, 69, 70, 71],
|
19089
19459
|
},
|
19090
|
-
|
19091
|
-
|
19460
|
+
{
|
19461
|
+
id: 'stu567',
|
19462
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
19463
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
19464
|
+
width: 224,
|
19465
|
+
height: 410,
|
19466
|
+
header: 'Craft Vermouth',
|
19467
|
+
textColor: '#ffffff',
|
19468
|
+
primaryImage: 'https://placehold.co/224x410/png?text=Craft+Vermouth',
|
19469
|
+
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Vermouth',
|
19470
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19471
|
+
productIds: [72, 73, 74, 75, 76],
|
19092
19472
|
},
|
19093
|
-
|
19094
|
-
|
19473
|
+
{
|
19474
|
+
id: 'vwx890',
|
19475
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
19476
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
19477
|
+
width: 224,
|
19478
|
+
height: 410,
|
19479
|
+
header: 'Premium Mezcal',
|
19480
|
+
textColor: '#ffffff',
|
19481
|
+
primaryImage: 'https://placehold.co/224x410/png?text=Premium+Mezcal',
|
19482
|
+
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Mezcal',
|
19483
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19484
|
+
productIds: [77, 78, 79, 80, 81],
|
19095
19485
|
},
|
19096
|
-
|
19097
|
-
|
19486
|
+
],
|
19487
|
+
rbCollectionBannerWithoutTextBlock: [
|
19488
|
+
{
|
19489
|
+
id: 'yz1234',
|
19490
|
+
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
19491
|
+
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
19492
|
+
width: 887,
|
19493
|
+
height: 344,
|
19494
|
+
primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
|
19495
|
+
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
|
19496
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19497
|
+
productIds: [82, 83, 84, 85, 86],
|
19098
19498
|
},
|
19099
|
-
|
19100
|
-
|
19101
|
-
|
19102
|
-
|
19103
|
-
|
19499
|
+
{
|
19500
|
+
id: 'abc567',
|
19501
|
+
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
19502
|
+
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
19503
|
+
width: 887,
|
19504
|
+
height: 344,
|
19505
|
+
primaryImage: 'https://placehold.co/887x344/png?text=Holiday+Spirits',
|
19506
|
+
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Holiday+Spirits',
|
19507
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19508
|
+
productIds: [87, 88, 89, 90, 91],
|
19104
19509
|
},
|
19105
|
-
|
19106
|
-
|
19510
|
+
{
|
19511
|
+
id: 'def901',
|
19512
|
+
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
19513
|
+
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
19514
|
+
width: 887,
|
19515
|
+
height: 344,
|
19516
|
+
primaryImage: 'https://placehold.co/887x344/png?text=Wine+Essentials',
|
19517
|
+
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Wine+Essentials',
|
19518
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19519
|
+
productIds: [92, 93, 94, 95, 96],
|
19107
19520
|
},
|
19108
|
-
|
19109
|
-
|
19521
|
+
],
|
19522
|
+
rbNavigationBanner: [
|
19523
|
+
{
|
19524
|
+
id: 'ghi234',
|
19525
|
+
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
19526
|
+
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
19527
|
+
width: 440,
|
19528
|
+
height: 220,
|
19529
|
+
header: 'Explore Tequilas',
|
19530
|
+
textColor: '#ffffff',
|
19531
|
+
primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
|
19532
|
+
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
|
19533
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19534
|
+
productIds: [97, 98, 99, 100, 101],
|
19110
19535
|
},
|
19111
|
-
|
19112
|
-
|
19113
|
-
|
19536
|
+
{
|
19537
|
+
id: 'jkl678',
|
19538
|
+
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
19539
|
+
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
19540
|
+
width: 440,
|
19541
|
+
height: 220,
|
19542
|
+
header: 'Craft Gin Selection',
|
19543
|
+
textColor: '#ffffff',
|
19544
|
+
primaryImage: 'https://placehold.co/440x220/png?text=Gin+Selection',
|
19545
|
+
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Gin+Selection',
|
19546
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19547
|
+
productIds: [102, 103, 104, 105, 106],
|
19114
19548
|
},
|
19115
|
-
|
19116
|
-
|
19117
|
-
|
19549
|
+
{
|
19550
|
+
id: 'mno012',
|
19551
|
+
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
19552
|
+
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
19553
|
+
width: 440,
|
19554
|
+
height: 220,
|
19555
|
+
header: 'Premium Vodka',
|
19556
|
+
textColor: '#ffffff',
|
19557
|
+
primaryImage: 'https://placehold.co/440x220/png?text=Vodka+Premium',
|
19558
|
+
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Vodka+Premium',
|
19559
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19560
|
+
productIds: [107, 108, 109, 110, 111],
|
19118
19561
|
},
|
19119
|
-
|
19120
|
-
|
19562
|
+
],
|
19563
|
+
});
|
19564
|
+
({
|
19565
|
+
banner: [],
|
19566
|
+
billboard: [
|
19567
|
+
{
|
19568
|
+
id: 'kol567',
|
19569
|
+
spot: RMN_SPOT_TYPE.BILLBOARD,
|
19570
|
+
variant: `${RMN_SPOT_TYPE.BILLBOARD}V2`,
|
19571
|
+
width: 1140,
|
19572
|
+
height: 640,
|
19573
|
+
header: 'Holiday Gift Guide',
|
19574
|
+
description: 'Perfect spirits for every occasion',
|
19575
|
+
ctaText: 'Shop Gifts',
|
19576
|
+
textColor: '#ffffff',
|
19577
|
+
ctaTextColor: '#ffffff',
|
19578
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Gift+Guide',
|
19579
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Gifts',
|
19580
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19581
|
+
productIds: [25, 26],
|
19121
19582
|
},
|
19122
|
-
|
19123
|
-
|
19583
|
+
{
|
19584
|
+
id: 'hpm390',
|
19585
|
+
spot: RMN_SPOT_TYPE.BILLBOARD,
|
19586
|
+
variant: `${RMN_SPOT_TYPE.BILLBOARD}V2`,
|
19587
|
+
width: 1140,
|
19588
|
+
height: 640,
|
19589
|
+
header: 'Summer Wine Festival',
|
19590
|
+
description: 'Refreshing wines for summer',
|
19591
|
+
ctaText: 'Shop Festival',
|
19592
|
+
textColor: '#ffffff',
|
19593
|
+
ctaTextColor: '#ffffff',
|
19594
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Wine+Festival',
|
19595
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Festival',
|
19596
|
+
events: SPOT_EVENTS_EXAMPLE,
|
19597
|
+
productIds: [27, 28],
|
19124
19598
|
},
|
19125
|
-
|
19126
|
-
|
19127
|
-
|
19128
|
-
|
19129
|
-
|
19130
|
-
|
19131
|
-
|
19132
|
-
|
19133
|
-
|
19134
|
-
|
19135
|
-
|
19136
|
-
|
19137
|
-
|
19138
|
-
|
19139
|
-
|
19140
|
-
|
19141
|
-
|
19142
|
-
|
19143
|
-
|
19144
|
-
|
19145
|
-
|
19146
|
-
|
19147
|
-
|
19148
|
-
|
19149
|
-
|
19150
|
-
|
19151
|
-
|
19152
|
-
|
19153
|
-
this.originalPush = window.dataLayer.push;
|
19154
|
-
}
|
19155
|
-
static getInstance() {
|
19156
|
-
if (!DataLayerMonitor.instance) {
|
19157
|
-
DataLayerMonitor.instance = new DataLayerMonitor();
|
19158
|
-
}
|
19159
|
-
return DataLayerMonitor.instance;
|
19160
|
-
}
|
19161
|
-
setListener(listener) {
|
19162
|
-
this.listener = listener;
|
19163
|
-
}
|
19164
|
-
start() {
|
19165
|
-
window.dataLayer.push = (...args) => {
|
19166
|
-
const result = this.originalPush.apply(window.dataLayer, args);
|
19167
|
-
const pushedEvent = args[0];
|
19168
|
-
if (this.listener) {
|
19169
|
-
const normalizedData = this.cleanEventData(pushedEvent);
|
19170
|
-
if (normalizedData) {
|
19171
|
-
this.listener(normalizedData);
|
19172
|
-
}
|
19173
|
-
}
|
19174
|
-
return result;
|
19175
|
-
};
|
19176
|
-
}
|
19177
|
-
cleanEventData(data) {
|
19178
|
-
const eventName = getEventTypeFromRawEvent(data.event);
|
19179
|
-
if (!eventName) {
|
19180
|
-
return null;
|
19181
|
-
}
|
19182
|
-
const productIds = extractDeepIds(data);
|
19183
|
-
return {
|
19184
|
-
event: eventName,
|
19185
|
-
productIds,
|
19186
|
-
};
|
19187
|
-
}
|
19188
|
-
stop() {
|
19189
|
-
if (this.originalPush) {
|
19190
|
-
window.dataLayer.push = this.originalPush;
|
19191
|
-
}
|
19192
|
-
this.listener = undefined;
|
19193
|
-
}
|
19194
|
-
}
|
19599
|
+
],
|
19600
|
+
button2: [],
|
19601
|
+
featurePhoneLargeBanner: [],
|
19602
|
+
featurePhoneMediumBanner: [],
|
19603
|
+
featurePhoneSmallBanner: [],
|
19604
|
+
halfPage: [],
|
19605
|
+
inText: [],
|
19606
|
+
largeLeaderboard: [],
|
19607
|
+
largeRectangle: [],
|
19608
|
+
leaderboard: [],
|
19609
|
+
mediumRectangle: [],
|
19610
|
+
microBar: [],
|
19611
|
+
mobilePhoneInterstitial1: [],
|
19612
|
+
mobilePhoneInterstitial2: [],
|
19613
|
+
mobilePhoneInterstitial3: [],
|
19614
|
+
popUp: [],
|
19615
|
+
portrait: [],
|
19616
|
+
rbProductUpcs: [],
|
19617
|
+
skyscraper: [],
|
19618
|
+
smallRectangle: [],
|
19619
|
+
smallSquare: [],
|
19620
|
+
smartphoneBanner1: [],
|
19621
|
+
smartphoneBanner2: [],
|
19622
|
+
square: [],
|
19623
|
+
verticalBanner: [],
|
19624
|
+
verticalRectangle: [],
|
19625
|
+
wideSkyscraper: [],
|
19626
|
+
});
|
19195
19627
|
|
19196
|
-
|
19197
|
-
|
19198
|
-
|
19199
|
-
|
19200
|
-
|
19201
|
-
|
19202
|
-
|
19203
|
-
|
19204
|
-
|
19205
|
-
case AnalyticsTool.Other:
|
19206
|
-
default:
|
19207
|
-
console.warn('This site uses an unsupported analytics tool.');
|
19208
|
-
break;
|
19209
|
-
}
|
19210
|
-
if (analyticsTool === AnalyticsTool.Other) {
|
19211
|
-
return;
|
19212
|
-
}
|
19213
|
-
this.pubSubService = PubsubService.getInstance();
|
19214
|
-
this.localStorageService = LocalStorageService.getInstance();
|
19215
|
-
}
|
19216
|
-
static getInstance() {
|
19217
|
-
if (!MonitorService.instance) {
|
19218
|
-
MonitorService.instance = new MonitorService();
|
19219
|
-
}
|
19220
|
-
return MonitorService.instance;
|
19221
|
-
}
|
19222
|
-
start() {
|
19223
|
-
if (!this.implementedMonitor)
|
19224
|
-
return;
|
19225
|
-
this.implementedMonitor.setListener(async (eventData) => {
|
19226
|
-
var _a;
|
19227
|
-
await this.matchAndFireEvent(eventData, (_a = this.localStorageService) === null || _a === void 0 ? void 0 : _a.getSpots());
|
19228
|
-
});
|
19229
|
-
this.implementedMonitor.start();
|
19230
|
-
}
|
19231
|
-
async matchAndFireEvent(eventData, spots) {
|
19232
|
-
var _a, _b;
|
19233
|
-
if (!spots)
|
19234
|
-
return;
|
19235
|
-
const eventProductIds = new Set(eventData.productIds.map((productId) => String(productId)));
|
19236
|
-
for (const spot of Object.values(spots)) {
|
19237
|
-
if (!spot.productIds.length)
|
19238
|
-
continue;
|
19239
|
-
const hasCommonProductIds = spot.productIds.find((productId) => eventProductIds.has(String(productId)));
|
19240
|
-
if (hasCommonProductIds) {
|
19241
|
-
if (Object.values(RMN_SPOT_EVENT).includes(eventData.event)) {
|
19242
|
-
await this.fireAndPublishSpotEvent({
|
19243
|
-
spotEvent: eventData.event,
|
19244
|
-
eventUrl: (_b = (_a = spot.events.find((event) => event.event === eventData.event)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
19245
|
-
placementId: spot.placementId,
|
19246
|
-
spotId: spot.spotId,
|
19247
|
-
});
|
19248
|
-
}
|
19249
|
-
}
|
19250
|
-
}
|
19251
|
-
}
|
19252
|
-
async fireAndPublishSpotEvent({ spotEvent, eventUrl, placementId, spotId, }) {
|
19253
|
-
await fireEvent({
|
19254
|
-
event: spotEvent,
|
19255
|
-
eventUrl,
|
19256
|
-
});
|
19257
|
-
if (!this.pubSubService)
|
19258
|
-
return;
|
19259
|
-
this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
|
19260
|
-
eventType: spotEvent,
|
19261
|
-
placementId,
|
19262
|
-
spotId,
|
19263
|
-
});
|
19264
|
-
}
|
19265
|
-
detectAnalyticsTool() {
|
19266
|
-
let analyticsTool = AnalyticsTool.Other;
|
19267
|
-
// Check for Google Analytics
|
19268
|
-
if (typeof window.ga !== 'undefined') {
|
19269
|
-
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
19270
|
-
}
|
19271
|
-
// Check for Google Analytics 4
|
19272
|
-
if (typeof window.gtag !== 'undefined') {
|
19273
|
-
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
19274
|
-
}
|
19275
|
-
// Check for Google Tag Manager
|
19276
|
-
if (typeof window.google_tag_manager !== 'undefined') {
|
19277
|
-
analyticsTool = AnalyticsTool.GoogleAnalytics;
|
19278
|
-
}
|
19279
|
-
// @TODO: Add support for other analytics tools
|
19280
|
-
// Check for Heap Analytics
|
19281
|
-
// Check for Mixpanel
|
19282
|
-
// Check for Woopra
|
19283
|
-
// Check for Segment
|
19284
|
-
// Check for Amplitude
|
19285
|
-
return analyticsTool;
|
19628
|
+
/**
|
19629
|
+
* Checks if the current environment is a browser environment.
|
19630
|
+
*
|
19631
|
+
* @return {boolean} - Whether the current environment is a browser environment.
|
19632
|
+
*/
|
19633
|
+
function isBrowserEnvironment() {
|
19634
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
19635
|
+
console.warn('LiquidCommerce Rmn Sdk: Methods which create elements are only available in browser environments.');
|
19636
|
+
return false;
|
19286
19637
|
}
|
19638
|
+
return true;
|
19287
19639
|
}
|
19288
|
-
|
19289
|
-
|
19290
|
-
|
19291
|
-
|
19292
|
-
|
19293
|
-
|
19294
|
-
|
19295
|
-
|
19296
|
-
|
19297
|
-
|
19298
|
-
|
19299
|
-
|
19300
|
-
|
19301
|
-
|
19302
|
-
|
19303
|
-
|
19304
|
-
}
|
19305
|
-
subscribe(eventType, callback) {
|
19306
|
-
return this.pubSubService.subscribe(eventType, callback);
|
19307
|
-
}
|
19308
|
-
publish(eventType, data) {
|
19309
|
-
this.pubSubService.publish(eventType, data);
|
19310
|
-
}
|
19311
|
-
registerSpot(params) {
|
19312
|
-
const { placementId, spot, spotElement } = params;
|
19313
|
-
this.activeSpots.set(placementId, { spotElement });
|
19314
|
-
// Fire impression event
|
19315
|
-
this.fireImpressionEvent(placementId, spot);
|
19316
|
-
// Handle intersection observer
|
19317
|
-
this.handleIntersectionObserver(placementId, spot, spotElement);
|
19318
|
-
// Attach click event listener
|
19319
|
-
spotElement.addEventListener('click', async () => await this.handleClick(params));
|
19320
|
-
}
|
19321
|
-
unregisterSpot(placementId) {
|
19322
|
-
const placementIdClean = placementId.replace('#', '');
|
19323
|
-
const spotData = this.activeSpots.get(placementIdClean);
|
19324
|
-
if (!spotData) {
|
19325
|
-
this.handleSpotState(placementIdClean, {
|
19326
|
-
state: {
|
19327
|
-
error: `Active spot with placementId ${placementIdClean} not found.`,
|
19328
|
-
},
|
19329
|
-
});
|
19330
|
-
return;
|
19331
|
-
}
|
19332
|
-
this.intersectionObserver.unobserve(spotData.spotElement);
|
19333
|
-
this.handleSpotState(placementIdClean, {
|
19334
|
-
dom: {
|
19335
|
-
spotElement: undefined,
|
19336
|
-
visibleOnViewport: false,
|
19337
|
-
},
|
19338
|
-
state: {
|
19339
|
-
unmounted: true,
|
19340
|
-
mounted: false,
|
19341
|
-
},
|
19342
|
-
});
|
19343
|
-
this.activeSpots.delete(placementIdClean);
|
19344
|
-
const placementElement = document.getElementById(placementIdClean);
|
19345
|
-
if (!placementElement) {
|
19346
|
-
this.handleSpotState(placementIdClean, {
|
19640
|
+
/**
|
19641
|
+
* Validates the inject data by preventing duplicate placement ids and non-existent spot types.
|
19642
|
+
*
|
19643
|
+
* @param {IInjectSpotElement[]} inject - The inject data.
|
19644
|
+
* @return {IInjectSpotElement[]} - The validated inject data.
|
19645
|
+
*/
|
19646
|
+
function validateInjectData(inject) {
|
19647
|
+
const eventService = EventService.getInstance();
|
19648
|
+
const placementIds = new Set();
|
19649
|
+
const validSpotTypes = new Set(Object.values(RMN_SPOT_TYPE));
|
19650
|
+
const validatedInject = [];
|
19651
|
+
for (const item of inject) {
|
19652
|
+
const placementId = item.placementId.replace('#', '');
|
19653
|
+
// Check for duplicate placement ids
|
19654
|
+
if (placementIds.has(placementId)) {
|
19655
|
+
eventService.handleSpotState(placementId, {
|
19347
19656
|
state: {
|
19348
|
-
error: `
|
19657
|
+
error: `Duplicate placement id (${placementId}) found. Please provide a unique placement id for each spot element.`,
|
19349
19658
|
},
|
19350
19659
|
});
|
19351
|
-
|
19352
|
-
}
|
19353
|
-
|
19354
|
-
|
19355
|
-
|
19356
|
-
|
19357
|
-
|
19358
|
-
* @param {string} placementId - The placement ID of the spot.
|
19359
|
-
* @param {Partial<ILifecycleState>} updates - The updates to apply to the spot state.
|
19360
|
-
* @param {boolean} publish - Whether to publish the updated state.
|
19361
|
-
*
|
19362
|
-
* @returns {void}
|
19363
|
-
*/
|
19364
|
-
handleSpotState(placementId, updates, publish = true) {
|
19365
|
-
let currentState = this.spotStates.get(placementId);
|
19366
|
-
if (!currentState) {
|
19367
|
-
currentState = {
|
19368
|
-
identifier: {
|
19369
|
-
placementId,
|
19370
|
-
spotId: '',
|
19371
|
-
spotType: '',
|
19372
|
-
},
|
19373
|
-
dom: {
|
19374
|
-
spotElement: undefined,
|
19375
|
-
visibleOnViewport: false,
|
19376
|
-
},
|
19377
|
-
state: {
|
19378
|
-
mounted: false,
|
19379
|
-
unmounted: false,
|
19380
|
-
loading: false,
|
19381
|
-
error: undefined,
|
19382
|
-
},
|
19383
|
-
displayConfig: {
|
19384
|
-
isCarousel: false,
|
19385
|
-
isCarouselItem: false,
|
19386
|
-
isSingleItem: false,
|
19387
|
-
},
|
19388
|
-
};
|
19389
|
-
}
|
19390
|
-
const merged = this.deepMerge(currentState, updates);
|
19391
|
-
this.spotStates.set(placementId, merged);
|
19392
|
-
if (publish) {
|
19393
|
-
this.pubSubService.publish(RMN_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
|
19394
|
-
}
|
19395
|
-
}
|
19396
|
-
deepMerge(current, updates) {
|
19397
|
-
return {
|
19398
|
-
identifier: updates.identifier
|
19399
|
-
? { ...current.identifier, ...updates.identifier }
|
19400
|
-
: current.identifier,
|
19401
|
-
dom: updates.dom ? { ...current.dom, ...updates.dom } : current.dom,
|
19402
|
-
state: updates.state ? { ...current.state, ...updates.state } : current.state,
|
19403
|
-
displayConfig: updates.displayConfig
|
19404
|
-
? { ...current.displayConfig, ...updates.displayConfig }
|
19405
|
-
: current.displayConfig,
|
19406
|
-
};
|
19407
|
-
}
|
19408
|
-
async handleClick({ placementId, spot }) {
|
19409
|
-
var _a, _b, _c;
|
19410
|
-
this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
|
19411
|
-
eventType: RMN_SPOT_EVENT.CLICK,
|
19412
|
-
placementId,
|
19413
|
-
spotId: spot.id,
|
19414
|
-
});
|
19415
|
-
await fireEvent({
|
19416
|
-
event: RMN_SPOT_EVENT.CLICK,
|
19417
|
-
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
19418
|
-
});
|
19419
|
-
// Save spot to local storage for event tracking
|
19420
|
-
this.localStorageService.setSpot(spot.id, {
|
19421
|
-
placementId,
|
19422
|
-
spotId: spot.id,
|
19423
|
-
spotType: spot.spot,
|
19424
|
-
events: spot.events,
|
19425
|
-
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 2, 3],
|
19426
|
-
});
|
19427
|
-
}
|
19428
|
-
handleIntersectionObserver(placementId, _spot, spotElement) {
|
19429
|
-
const spotIsVisibleCallback = async () => {
|
19430
|
-
this.intersectionObserver.unobserve(spotElement);
|
19431
|
-
this.handleSpotState(placementId, {
|
19432
|
-
dom: {
|
19433
|
-
spotElement,
|
19434
|
-
visibleOnViewport: true,
|
19660
|
+
continue;
|
19661
|
+
}
|
19662
|
+
// Check for non-existent spot types
|
19663
|
+
if (!validSpotTypes.has(item.spotType)) {
|
19664
|
+
eventService.handleSpotState(placementId, {
|
19665
|
+
state: {
|
19666
|
+
error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
|
19435
19667
|
},
|
19436
19668
|
});
|
19437
|
-
|
19438
|
-
|
19439
|
-
|
19440
|
-
|
19441
|
-
this.pubSubService.publish(RMN_EVENT.SPOT_EVENT, {
|
19442
|
-
eventType: RMN_SPOT_EVENT.IMPRESSION,
|
19443
|
-
placementId,
|
19444
|
-
spotId: spot.id,
|
19445
|
-
});
|
19446
|
-
(async () => {
|
19447
|
-
var _a, _b;
|
19448
|
-
await fireEvent({
|
19449
|
-
event: RMN_SPOT_EVENT.IMPRESSION,
|
19450
|
-
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.IMPRESSION)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
19451
|
-
});
|
19452
|
-
})();
|
19669
|
+
continue;
|
19670
|
+
}
|
19671
|
+
placementIds.add(placementId);
|
19672
|
+
validatedInject.push(item);
|
19453
19673
|
}
|
19674
|
+
return validatedInject;
|
19454
19675
|
}
|
19455
|
-
|
19456
|
-
|
19457
|
-
|
19458
|
-
|
19459
|
-
|
19460
|
-
|
19676
|
+
/**
|
19677
|
+
* Clears the placement element by removing all its children.
|
19678
|
+
*
|
19679
|
+
* @param {string} placementId - The placement id.
|
19680
|
+
*
|
19681
|
+
* @return {void}
|
19682
|
+
*/
|
19683
|
+
function clearPlacement(placementId) {
|
19684
|
+
var _a;
|
19685
|
+
(_a = document.getElementById(placementId)) === null || _a === void 0 ? void 0 : _a.replaceChildren();
|
19686
|
+
}
|
19687
|
+
/**
|
19688
|
+
* Prepares the spot placement for rendering by taking care of its styling.
|
19689
|
+
*
|
19690
|
+
* @param {HTMLElement} placement - The placement element.
|
19691
|
+
*
|
19692
|
+
* @return {void}
|
19693
|
+
*/
|
19694
|
+
function prepareSpotPlacement(placement) {
|
19695
|
+
placement.removeAttribute('style');
|
19696
|
+
placement.removeAttribute('class');
|
19697
|
+
const styles = {
|
19698
|
+
width: '100%',
|
19699
|
+
height: '100%',
|
19700
|
+
display: 'flex',
|
19701
|
+
justifyContent: 'center',
|
19702
|
+
};
|
19703
|
+
Object.assign(placement.style, styles);
|
19704
|
+
}
|
19705
|
+
/**
|
19706
|
+
* Waits for the DOM to be ready before continuing.
|
19707
|
+
*
|
19708
|
+
* @return {Promise<void>} - A promise that resolves when the DOM is ready.
|
19709
|
+
*/
|
19710
|
+
async function waitForDOM() {
|
19711
|
+
if (!isBrowserEnvironment()) {
|
19712
|
+
return;
|
19461
19713
|
}
|
19462
|
-
|
19463
|
-
return
|
19714
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
19715
|
+
return;
|
19464
19716
|
}
|
19465
|
-
|
19466
|
-
|
19467
|
-
|
19468
|
-
|
19469
|
-
|
19470
|
-
|
19471
|
-
|
19472
|
-
|
19473
|
-
|
19474
|
-
|
19475
|
-
|
19476
|
-
|
19477
|
-
if (isOk && val && val.data && (val === null || val === void 0 ? void 0 : val.refresh.token)) {
|
19478
|
-
this.authInfo.authenticated = true;
|
19479
|
-
this.authInfo.token = val.refresh.token;
|
19480
|
-
return val.data.spots;
|
19481
|
-
}
|
19482
|
-
return { error: 'Spot selection response was not successful' };
|
19717
|
+
return new Promise((resolve) => {
|
19718
|
+
document.addEventListener('DOMContentLoaded', () => {
|
19719
|
+
resolve();
|
19720
|
+
});
|
19721
|
+
});
|
19722
|
+
}
|
19723
|
+
// Sets the id for the user who is browsing the website
|
19724
|
+
// This id is used to identify the user and provide personalized content
|
19725
|
+
function setUserId() {
|
19726
|
+
if (isBrowserEnvironment()) {
|
19727
|
+
const localStorageService = LocalStorageService.getInstance();
|
19728
|
+
localStorageService.setUserId();
|
19483
19729
|
}
|
19484
19730
|
}
|
19485
19731
|
|
19732
|
+
/**
|
19733
|
+
* LiquidCommerce Rmn Client
|
19734
|
+
* @class
|
19735
|
+
*/
|
19486
19736
|
class LiquidCommerceRmnClient {
|
19487
19737
|
constructor(auth) {
|
19488
19738
|
this.selectionService = SelectionService.getInstance(auth);
|
@@ -19511,14 +19761,11 @@ class LiquidCommerceRmnClient {
|
|
19511
19761
|
*/
|
19512
19762
|
async injectSpotElement(params) {
|
19513
19763
|
var _a;
|
19514
|
-
|
19515
|
-
|
19516
|
-
return;
|
19517
|
-
}
|
19764
|
+
// Wait for the DOM to be ready before continuing, to avoid issues with the spot placements
|
19765
|
+
await waitForDOM();
|
19518
19766
|
const config = params.config;
|
19519
|
-
let inject = params.inject;
|
19520
19767
|
// Handle no spots error state
|
19521
|
-
if (!inject.length) {
|
19768
|
+
if (!params.inject.length) {
|
19522
19769
|
this.eventService.handleSpotState('all', {
|
19523
19770
|
state: {
|
19524
19771
|
error: 'No spot elements provided for injection.',
|
@@ -19526,49 +19773,32 @@ class LiquidCommerceRmnClient {
|
|
19526
19773
|
});
|
19527
19774
|
return;
|
19528
19775
|
}
|
19529
|
-
//
|
19776
|
+
// Validate inject data
|
19777
|
+
const inject = validateInjectData(params.inject);
|
19530
19778
|
for (const item of inject) {
|
19779
|
+
// Identify the spot element
|
19531
19780
|
this.eventService.handleSpotState(item.placementId, {
|
19532
19781
|
identifier: {
|
19533
19782
|
placementId: item.placementId,
|
19534
19783
|
spotType: item.spotType,
|
19535
19784
|
},
|
19536
19785
|
}, false);
|
19537
|
-
|
19538
|
-
|
19539
|
-
const hasDuplicatePlacementIds = this.preventDuplicateSpotPlacementIds(inject);
|
19540
|
-
if (!hasDuplicatePlacementIds) {
|
19541
|
-
return;
|
19542
|
-
}
|
19543
|
-
// Prevent non-existent spot types
|
19544
|
-
inject = this.preventNonExistentSpotTypes(inject);
|
19545
|
-
// Add Intersection Observer to the spot elements to track visibility
|
19546
|
-
// This is useful for lazy loading the spot elements
|
19547
|
-
for (const item of inject) {
|
19548
|
-
const placementId = item.placementId.replace('#', '');
|
19549
|
-
const placement = document.getElementById(placementId);
|
19786
|
+
const placement = document.getElementById(item.placementId);
|
19787
|
+
// Handle placement not found error state
|
19550
19788
|
if (!placement) {
|
19551
|
-
// Handle placement not found error state
|
19552
19789
|
this.eventService.handleSpotState(item.placementId, {
|
19553
19790
|
state: {
|
19554
|
-
error: `Placement not found for id "${placementId}".`,
|
19791
|
+
error: `Placement not found for id "${item.placementId}".`,
|
19555
19792
|
},
|
19556
19793
|
});
|
19557
19794
|
continue;
|
19558
19795
|
}
|
19559
|
-
|
19560
|
-
placement.removeAttribute('style');
|
19561
|
-
placement.removeAttribute('class');
|
19562
|
-
Object.assign(placement.style, {
|
19563
|
-
width: '100%',
|
19564
|
-
height: '100%',
|
19565
|
-
display: 'flex',
|
19566
|
-
justifyContent: 'center',
|
19567
|
-
});
|
19796
|
+
prepareSpotPlacement(placement);
|
19568
19797
|
const skeletonElement = this.elementService.createSkeletonElement({
|
19569
19798
|
fluid: (_a = config === null || config === void 0 ? void 0 : config.fluid) !== null && _a !== void 0 ? _a : false,
|
19570
19799
|
spotType: item.spotType,
|
19571
19800
|
});
|
19801
|
+
// Handle skeleton loader error state
|
19572
19802
|
if (!skeletonElement) {
|
19573
19803
|
this.eventService.handleSpotState(item.placementId, {
|
19574
19804
|
state: {
|
@@ -19580,19 +19810,15 @@ class LiquidCommerceRmnClient {
|
|
19580
19810
|
continue;
|
19581
19811
|
}
|
19582
19812
|
placement.replaceChildren(skeletonElement);
|
19583
|
-
const
|
19813
|
+
const spotPlacementIsNearCallback = async () => {
|
19584
19814
|
var _a;
|
19585
|
-
//
|
19586
|
-
this.eventService.handleSpotState(item.placementId, {
|
19587
|
-
state: {
|
19588
|
-
loading: true,
|
19589
|
-
},
|
19590
|
-
});
|
19591
|
-
// Stop observing the placement
|
19815
|
+
// Stop observing the placement, as we only need to do this once
|
19592
19816
|
this.intersectionObserver.unobserve(placement);
|
19817
|
+
// Set the spot element to loading state
|
19818
|
+
this.eventService.handleSpotState(item.placementId, { state: { loading: true } });
|
19593
19819
|
// Make the spot selection request
|
19594
|
-
const response = await this.
|
19595
|
-
// const response = await
|
19820
|
+
const response = await this.injectSpotSelectionRequest({ ...params, inject: [item] });
|
19821
|
+
// const response = await useSpotSelectionExample(inject);
|
19596
19822
|
// Handle request error state
|
19597
19823
|
if (typeof response === 'object' && 'error' in response) {
|
19598
19824
|
this.eventService.handleSpotState(item.placementId, {
|
@@ -19602,13 +19828,13 @@ class LiquidCommerceRmnClient {
|
|
19602
19828
|
loading: false,
|
19603
19829
|
},
|
19604
19830
|
});
|
19605
|
-
|
19831
|
+
clearPlacement(item.placementId);
|
19606
19832
|
return;
|
19607
19833
|
}
|
19608
19834
|
const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
|
19609
19835
|
const spots = response[item.placementId];
|
19836
|
+
// Handle no spots found error state
|
19610
19837
|
if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
|
19611
|
-
// Handle no spots found error state
|
19612
19838
|
this.eventService.handleSpotState(item.placementId, {
|
19613
19839
|
state: {
|
19614
19840
|
error: `No spots found for type "${item.spotType}".`,
|
@@ -19616,22 +19842,106 @@ class LiquidCommerceRmnClient {
|
|
19616
19842
|
loading: false,
|
19617
19843
|
},
|
19618
19844
|
});
|
19619
|
-
|
19845
|
+
clearPlacement(item.placementId);
|
19620
19846
|
return;
|
19621
19847
|
}
|
19622
19848
|
// Handle single spot
|
19623
19849
|
if (spots.length === 1) {
|
19624
|
-
this.injectOneSpotElement(
|
19850
|
+
this.injectOneSpotElement(placement, spots[0], itemConfig);
|
19625
19851
|
}
|
19626
19852
|
// Handle multiple spots (carousel)
|
19627
19853
|
if (spots.length > 1) {
|
19628
19854
|
this.injectCarouselSpotElement(placement, spots, itemConfig);
|
19629
19855
|
}
|
19630
19856
|
};
|
19631
|
-
|
19857
|
+
/**
|
19858
|
+
* Observe the placement element to check if it is near the viewport.
|
19859
|
+
* If it is near, make the spot selection request.
|
19860
|
+
*/
|
19861
|
+
this.intersectionObserver.observe(placement, spotPlacementIsNearCallback, {
|
19862
|
+
rootMargin: '1000px',
|
19863
|
+
threshold: 0,
|
19864
|
+
});
|
19865
|
+
}
|
19866
|
+
}
|
19867
|
+
/**
|
19868
|
+
* Injects a single spot element into the provided placement.
|
19869
|
+
*
|
19870
|
+
* @param {HTMLElement} placement - The placement element.
|
19871
|
+
* @param {ISpot} spot - The spot data.
|
19872
|
+
* @param {IInjectSpotElementConfig} config - The configuration object.
|
19873
|
+
*
|
19874
|
+
* @return {void}
|
19875
|
+
*/
|
19876
|
+
injectOneSpotElement(placement, spot, config) {
|
19877
|
+
var _a;
|
19878
|
+
const placementId = placement.id;
|
19879
|
+
const spotType = spot.spot;
|
19880
|
+
this.eventService.handleSpotState(placementId, {
|
19881
|
+
identifier: {
|
19882
|
+
placementId,
|
19883
|
+
spotType,
|
19884
|
+
spotId: spot.id,
|
19885
|
+
},
|
19886
|
+
displayConfig: {
|
19887
|
+
isSingleItem: true,
|
19888
|
+
isCarousel: false,
|
19889
|
+
isCarouselItem: false,
|
19890
|
+
},
|
19891
|
+
});
|
19892
|
+
const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
|
19893
|
+
const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
19894
|
+
if (!content) {
|
19895
|
+
this.eventService.handleSpotState(placementId, {
|
19896
|
+
state: {
|
19897
|
+
error: `Failed to inject spot element. Could not create element for type "${spotType}".`,
|
19898
|
+
mounted: false,
|
19899
|
+
loading: false,
|
19900
|
+
},
|
19901
|
+
});
|
19902
|
+
clearPlacement(placementId);
|
19903
|
+
return;
|
19904
|
+
}
|
19905
|
+
// Create the spot element
|
19906
|
+
const spotElement = this.elementService.createSpotElement({
|
19907
|
+
content,
|
19908
|
+
config: {
|
19909
|
+
fluid: config === null || config === void 0 ? void 0 : config.fluid,
|
19910
|
+
spot: spot.spot,
|
19911
|
+
width: spot.width,
|
19912
|
+
height: spot.height,
|
19913
|
+
minScale: (_a = config === null || config === void 0 ? void 0 : config.minScale) !== null && _a !== void 0 ? _a : 0.25, // Scale down to 25% of the original size
|
19914
|
+
},
|
19915
|
+
});
|
19916
|
+
if (!spotElement) {
|
19917
|
+
this.eventService.handleSpotState(placementId, {
|
19918
|
+
state: {
|
19919
|
+
error: `Failed to inject spot element. Could not create element for type "${spotType}".`,
|
19920
|
+
mounted: false,
|
19921
|
+
loading: false,
|
19922
|
+
},
|
19923
|
+
});
|
19924
|
+
clearPlacement(placementId);
|
19925
|
+
return;
|
19632
19926
|
}
|
19927
|
+
this.eventService.registerSpot({
|
19928
|
+
spot: spotData,
|
19929
|
+
placementId,
|
19930
|
+
spotElement,
|
19931
|
+
});
|
19932
|
+
placement.replaceChildren(spotElement);
|
19933
|
+
this.eventService.handleSpotState(placementId, {
|
19934
|
+
dom: {
|
19935
|
+
spotElement,
|
19936
|
+
visibleOnViewport: false,
|
19937
|
+
},
|
19938
|
+
state: {
|
19939
|
+
mounted: true,
|
19940
|
+
loading: false,
|
19941
|
+
error: undefined,
|
19942
|
+
},
|
19943
|
+
});
|
19633
19944
|
}
|
19634
|
-
/** ========================= HELPER METHODS ========================= **/
|
19635
19945
|
/**
|
19636
19946
|
* Injects a carousel element with the provided spots into the placement.
|
19637
19947
|
*
|
@@ -19643,11 +19953,12 @@ class LiquidCommerceRmnClient {
|
|
19643
19953
|
*/
|
19644
19954
|
injectCarouselSpotElement(placement, spots, config) {
|
19645
19955
|
var _a;
|
19956
|
+
const placementId = placement.id;
|
19646
19957
|
const carouselSlides = [];
|
19647
19958
|
for (const spotItem of spots) {
|
19648
|
-
this.eventService.handleSpotState(
|
19959
|
+
this.eventService.handleSpotState(placementId, {
|
19649
19960
|
identifier: {
|
19650
|
-
placementId
|
19961
|
+
placementId,
|
19651
19962
|
spotType: spotItem.spot,
|
19652
19963
|
spotId: spotItem.id,
|
19653
19964
|
},
|
@@ -19660,7 +19971,7 @@ class LiquidCommerceRmnClient {
|
|
19660
19971
|
const spot = this.elementService.overrideSpotColors(spotItem, config === null || config === void 0 ? void 0 : config.colors);
|
19661
19972
|
const content = SPOT_TEMPLATE_HTML_ELEMENT(spot, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
19662
19973
|
if (!content) {
|
19663
|
-
this.eventService.handleSpotState(
|
19974
|
+
this.eventService.handleSpotState(placementId, {
|
19664
19975
|
state: {
|
19665
19976
|
error: `Failed to inject carousel spot item element. Could not create element for type "${spot.spot}".`,
|
19666
19977
|
mounted: false,
|
@@ -19671,7 +19982,7 @@ class LiquidCommerceRmnClient {
|
|
19671
19982
|
}
|
19672
19983
|
this.eventService.registerSpot({
|
19673
19984
|
spot,
|
19674
|
-
placementId
|
19985
|
+
placementId,
|
19675
19986
|
spotElement: content,
|
19676
19987
|
});
|
19677
19988
|
carouselSlides.push(content);
|
@@ -19693,18 +20004,18 @@ class LiquidCommerceRmnClient {
|
|
19693
20004
|
},
|
19694
20005
|
});
|
19695
20006
|
if (!carouselElement) {
|
19696
|
-
this.eventService.handleSpotState(
|
20007
|
+
this.eventService.handleSpotState(placementId, {
|
19697
20008
|
state: {
|
19698
20009
|
error: `Failed to inject spot carousel element. Could not create spot carousel element.`,
|
19699
20010
|
mounted: false,
|
19700
20011
|
loading: false,
|
19701
20012
|
},
|
19702
20013
|
});
|
19703
|
-
|
20014
|
+
clearPlacement(placementId);
|
19704
20015
|
return;
|
19705
20016
|
}
|
19706
20017
|
placement.replaceChildren(carouselElement);
|
19707
|
-
this.eventService.handleSpotState(
|
20018
|
+
this.eventService.handleSpotState(placementId, {
|
19708
20019
|
dom: {
|
19709
20020
|
spotElement: carouselElement,
|
19710
20021
|
visibleOnViewport: false,
|
@@ -19716,94 +20027,6 @@ class LiquidCommerceRmnClient {
|
|
19716
20027
|
},
|
19717
20028
|
});
|
19718
20029
|
}
|
19719
|
-
/**
|
19720
|
-
* Injects a single spot element into the provided placement.
|
19721
|
-
*
|
19722
|
-
* @param {IInjectSpotElement} injectItem - The inject item data.
|
19723
|
-
* @param {HTMLElement} placement - The placement element.
|
19724
|
-
* @param {ISpot} spot - The spot data.
|
19725
|
-
* @param {IInjectSpotElementConfig} config - The configuration object.
|
19726
|
-
*
|
19727
|
-
* @return {void}
|
19728
|
-
*/
|
19729
|
-
injectOneSpotElement(injectItem, placement, spot, config) {
|
19730
|
-
var _a;
|
19731
|
-
this.eventService.handleSpotState(injectItem.placementId, {
|
19732
|
-
identifier: {
|
19733
|
-
placementId: injectItem.placementId,
|
19734
|
-
spotType: injectItem.spotType,
|
19735
|
-
spotId: spot.id,
|
19736
|
-
},
|
19737
|
-
displayConfig: {
|
19738
|
-
isSingleItem: true,
|
19739
|
-
isCarousel: false,
|
19740
|
-
isCarouselItem: false,
|
19741
|
-
},
|
19742
|
-
});
|
19743
|
-
const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
|
19744
|
-
const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
19745
|
-
if (!content) {
|
19746
|
-
this.eventService.handleSpotState(injectItem.placementId, {
|
19747
|
-
state: {
|
19748
|
-
error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
|
19749
|
-
mounted: false,
|
19750
|
-
loading: false,
|
19751
|
-
},
|
19752
|
-
});
|
19753
|
-
this.clearPlacement(injectItem.placementId);
|
19754
|
-
return;
|
19755
|
-
}
|
19756
|
-
// Create the spot element
|
19757
|
-
const spotElement = this.elementService.createSpotElement({
|
19758
|
-
content,
|
19759
|
-
config: {
|
19760
|
-
fluid: config === null || config === void 0 ? void 0 : config.fluid,
|
19761
|
-
spot: spot.spot,
|
19762
|
-
width: spot.width,
|
19763
|
-
height: spot.height,
|
19764
|
-
minScale: (_a = config === null || config === void 0 ? void 0 : config.minScale) !== null && _a !== void 0 ? _a : 0.25, // Scale down to 25% of the original size
|
19765
|
-
},
|
19766
|
-
});
|
19767
|
-
if (!spotElement) {
|
19768
|
-
this.eventService.handleSpotState(injectItem.placementId, {
|
19769
|
-
state: {
|
19770
|
-
error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
|
19771
|
-
mounted: false,
|
19772
|
-
loading: false,
|
19773
|
-
},
|
19774
|
-
});
|
19775
|
-
this.clearPlacement(injectItem.placementId);
|
19776
|
-
return;
|
19777
|
-
}
|
19778
|
-
this.eventService.registerSpot({
|
19779
|
-
spot: spotData,
|
19780
|
-
placementId: injectItem.placementId,
|
19781
|
-
spotElement,
|
19782
|
-
});
|
19783
|
-
placement.replaceChildren(spotElement);
|
19784
|
-
this.eventService.handleSpotState(injectItem.placementId, {
|
19785
|
-
dom: {
|
19786
|
-
spotElement,
|
19787
|
-
visibleOnViewport: false,
|
19788
|
-
},
|
19789
|
-
state: {
|
19790
|
-
mounted: true,
|
19791
|
-
loading: false,
|
19792
|
-
error: undefined,
|
19793
|
-
},
|
19794
|
-
});
|
19795
|
-
}
|
19796
|
-
/**
|
19797
|
-
* Clears the placement element by removing all its children.
|
19798
|
-
*
|
19799
|
-
* @param {string} placementId - The placement id.
|
19800
|
-
*
|
19801
|
-
* @return {void}
|
19802
|
-
*/
|
19803
|
-
clearPlacement(placementId) {
|
19804
|
-
var _a;
|
19805
|
-
(_a = document.getElementById(placementId)) === null || _a === void 0 ? void 0 : _a.replaceChildren();
|
19806
|
-
}
|
19807
20030
|
/**
|
19808
20031
|
* Makes a selection request on our server based on the provided data.
|
19809
20032
|
*
|
@@ -19811,77 +20034,21 @@ class LiquidCommerceRmnClient {
|
|
19811
20034
|
*
|
19812
20035
|
* @return {Promise<ISpots | {error: string}>} - The spots response object.
|
19813
20036
|
*/
|
19814
|
-
async
|
20037
|
+
async injectSpotSelectionRequest(params) {
|
19815
20038
|
const { inject, filter, config } = params;
|
20039
|
+
const spots = inject.map((item) => ({
|
20040
|
+
placementId: item.placementId,
|
20041
|
+
spot: item.spotType,
|
20042
|
+
count: item === null || item === void 0 ? void 0 : item.count,
|
20043
|
+
...item === null || item === void 0 ? void 0 : item.filter,
|
20044
|
+
}));
|
19816
20045
|
const request = {
|
19817
20046
|
url: config === null || config === void 0 ? void 0 : config.url,
|
19818
20047
|
filter,
|
19819
|
-
spots
|
19820
|
-
placementId: item.placementId,
|
19821
|
-
spot: item.spotType,
|
19822
|
-
count: item === null || item === void 0 ? void 0 : item.count,
|
19823
|
-
...item === null || item === void 0 ? void 0 : item.filter,
|
19824
|
-
})),
|
20048
|
+
spots,
|
19825
20049
|
};
|
19826
20050
|
return this.spotSelection(request);
|
19827
20051
|
}
|
19828
|
-
/**
|
19829
|
-
* Prevents duplicate placement ids in the inject data.
|
19830
|
-
*
|
19831
|
-
* @param {IInjectSpotElement[]} inject - The inject data.
|
19832
|
-
*
|
19833
|
-
* @throws {Error} - If a duplicate placement id is found.
|
19834
|
-
*
|
19835
|
-
* @return {void}
|
19836
|
-
*/
|
19837
|
-
preventDuplicateSpotPlacementIds(inject) {
|
19838
|
-
const placementIds = new Set();
|
19839
|
-
for (const item of inject) {
|
19840
|
-
if (placementIds.has(item.placementId)) {
|
19841
|
-
this.eventService.handleSpotState(item.placementId, {
|
19842
|
-
state: {
|
19843
|
-
error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
|
19844
|
-
},
|
19845
|
-
});
|
19846
|
-
return false;
|
19847
|
-
}
|
19848
|
-
placementIds.add(item.placementId);
|
19849
|
-
}
|
19850
|
-
return true;
|
19851
|
-
}
|
19852
|
-
/**
|
19853
|
-
* Prevents non-existent spot types in the inject data.
|
19854
|
-
*
|
19855
|
-
* @param {IInjectSpotElement[]} inject - The inject data.
|
19856
|
-
* @return {IInjectSpotElement[]} - The filtered inject data.
|
19857
|
-
*/
|
19858
|
-
preventNonExistentSpotTypes(inject) {
|
19859
|
-
const newInject = [];
|
19860
|
-
for (const item of inject) {
|
19861
|
-
if (!Object.values(RMN_SPOT_TYPE).includes(item.spotType)) {
|
19862
|
-
this.eventService.handleSpotState(item.placementId, {
|
19863
|
-
state: {
|
19864
|
-
error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
|
19865
|
-
},
|
19866
|
-
});
|
19867
|
-
continue;
|
19868
|
-
}
|
19869
|
-
newInject.push(item);
|
19870
|
-
}
|
19871
|
-
return newInject;
|
19872
|
-
}
|
19873
|
-
// Use spot selection example data for private testing
|
19874
|
-
useSpotSelectionExample(inject) {
|
19875
|
-
const examples = { ...RB_SPOTS_SELECTION_EXAMPLE, ...IAB_SPOTS_SELECTION_EXAMPLE };
|
19876
|
-
const data = {};
|
19877
|
-
inject.map((item) => {
|
19878
|
-
var _a, _b, _c;
|
19879
|
-
data[item.placementId] = (_c = (_a = examples[item.spotType]) === null || _a === void 0 ? void 0 : _a.slice(0, (_b = item.count) !== null && _b !== void 0 ? _b : 1)) !== null && _c !== void 0 ? _c : [];
|
19880
|
-
});
|
19881
|
-
return new Promise((resolve) => {
|
19882
|
-
resolve(data);
|
19883
|
-
});
|
19884
|
-
}
|
19885
20052
|
}
|
19886
20053
|
/**
|
19887
20054
|
* Creates a new instance of the RmnClient.
|
@@ -19894,6 +20061,7 @@ class LiquidCommerceRmnClient {
|
|
19894
20061
|
async function RmnClient(apiKey, config) {
|
19895
20062
|
const authService = AuthService.getInstance(apiKey, config.env);
|
19896
20063
|
const credentials = await authService.initialize();
|
20064
|
+
setUserId();
|
19897
20065
|
return new LiquidCommerceRmnClient(credentials);
|
19898
20066
|
}
|
19899
20067
|
/**
|