@liquidcommercedev/rmn-sdk 1.4.6-beta.8 → 1.5.0-beta.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +620 -121
- package/dist/index.esm.js +620 -122
- package/dist/types/common/helpers/uuid.helper.d.ts +49 -0
- package/dist/types/index.umd.d.ts +2 -2
- package/dist/types/modules/element/component/carousel/carousel.interface.d.ts +4 -0
- package/dist/types/modules/element/element.interface.d.ts +4 -3
- package/dist/types/modules/element/template/helper.d.ts +2 -1
- package/dist/types/modules/element/template/template.type.d.ts +1 -1
- package/dist/types/modules/event/event.interface.d.ts +5 -5
- package/dist/types/modules/event/event.service.d.ts +14 -2
- package/dist/types/modules/event/helpers/index.d.ts +1 -0
- package/dist/types/modules/event/helpers/localstorage.service.d.ts +26 -0
- package/dist/types/modules/event/pubsub.d.ts +5 -3
- package/dist/types/modules/selection/selection.interface.d.ts +1 -0
- package/dist/types/rmn-client.d.ts +9 -13
- package/dist/types/static.constant.d.ts +1 -0
- package/dist/types/types.d.ts +5 -4
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.esm.js
CHANGED
@@ -14998,7 +14998,7 @@ class BaseApi extends BaseApiAbstract {
|
|
14998
14998
|
*/
|
14999
14999
|
async post(path, data, configOverrides) {
|
15000
15000
|
let requestData = data;
|
15001
|
-
if (this.authInfo.env
|
15001
|
+
if (![RMN_ENV.LOCAL, RMN_ENV.DEVELOPMENT].includes(this.authInfo.env)) {
|
15002
15002
|
const timestamp = new Date().getTime();
|
15003
15003
|
configOverrides = {
|
15004
15004
|
...configOverrides,
|
@@ -15203,6 +15203,78 @@ class IntersectionObserverService {
|
|
15203
15203
|
}
|
15204
15204
|
}
|
15205
15205
|
|
15206
|
+
class LocalStorage {
|
15207
|
+
constructor() {
|
15208
|
+
this.spots = new Map();
|
15209
|
+
// Sync local storage with the current state
|
15210
|
+
this.syncLocalStorage();
|
15211
|
+
// Remove expired spots
|
15212
|
+
this.removeExpiredSpots();
|
15213
|
+
}
|
15214
|
+
static getInstance() {
|
15215
|
+
if (!LocalStorage.instance) {
|
15216
|
+
LocalStorage.instance = new LocalStorage();
|
15217
|
+
}
|
15218
|
+
return LocalStorage.instance;
|
15219
|
+
}
|
15220
|
+
syncLocalStorage() {
|
15221
|
+
const localStorageData = localStorage.getItem(LocalStorage.localStorageKey);
|
15222
|
+
// TODO: Encrypt the data before storing it in the local storage
|
15223
|
+
if (localStorageData) {
|
15224
|
+
try {
|
15225
|
+
const parsedData = JSON.parse(localStorageData);
|
15226
|
+
if (parsedData && typeof parsedData === 'object') {
|
15227
|
+
this.spots = this.objToMap(parsedData);
|
15228
|
+
}
|
15229
|
+
else {
|
15230
|
+
this.clearLocalStorage();
|
15231
|
+
}
|
15232
|
+
}
|
15233
|
+
catch (_a) {
|
15234
|
+
// If there is an error parsing the data, clear the local storage to prevent any issues
|
15235
|
+
this.clearLocalStorage();
|
15236
|
+
}
|
15237
|
+
}
|
15238
|
+
}
|
15239
|
+
setSpot(spotId, data) {
|
15240
|
+
data.createdAt = Date.now();
|
15241
|
+
this.spots.set(spotId, data);
|
15242
|
+
this.updateLocalStorage();
|
15243
|
+
}
|
15244
|
+
getSpot(spotId) {
|
15245
|
+
return this.spots.get(spotId);
|
15246
|
+
}
|
15247
|
+
removeSpot(spotId) {
|
15248
|
+
this.spots.delete(spotId);
|
15249
|
+
this.updateLocalStorage();
|
15250
|
+
}
|
15251
|
+
updateLocalStorage() {
|
15252
|
+
const data = this.mapToObj(this.spots);
|
15253
|
+
localStorage.setItem(LocalStorage.localStorageKey, JSON.stringify(data));
|
15254
|
+
}
|
15255
|
+
clearLocalStorage() {
|
15256
|
+
localStorage.removeItem(LocalStorage.localStorageKey);
|
15257
|
+
}
|
15258
|
+
removeExpiredSpots() {
|
15259
|
+
const currentTime = Date.now();
|
15260
|
+
this.spots.forEach((spot, spotId) => {
|
15261
|
+
var _a;
|
15262
|
+
if (currentTime - ((_a = spot.createdAt) !== null && _a !== void 0 ? _a : 0) > LocalStorage.spotExpirationTime) {
|
15263
|
+
this.spots.delete(spotId);
|
15264
|
+
}
|
15265
|
+
});
|
15266
|
+
this.updateLocalStorage();
|
15267
|
+
}
|
15268
|
+
mapToObj(map) {
|
15269
|
+
return Object.fromEntries(map);
|
15270
|
+
}
|
15271
|
+
objToMap(obj) {
|
15272
|
+
return new Map(Object.entries(obj));
|
15273
|
+
}
|
15274
|
+
}
|
15275
|
+
LocalStorage.localStorageKey = 'lc_rmn';
|
15276
|
+
LocalStorage.spotExpirationTime = 1000 * 60 * 60 * 24 * 7; // 7 days
|
15277
|
+
|
15206
15278
|
class ResizeObserverService {
|
15207
15279
|
constructor({ element, maxSize, minScale }) {
|
15208
15280
|
this.element = element;
|
@@ -15335,11 +15407,25 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
|
15335
15407
|
display: flex;
|
15336
15408
|
align-items: center;
|
15337
15409
|
gap: 8px;
|
15410
|
+
opacity: var(--opacity, 1);
|
15338
15411
|
}
|
15339
15412
|
|
15340
|
-
.dots .dot {
|
15413
|
+
.dots.small .dot {
|
15414
|
+
width: 8px;
|
15415
|
+
height: 8px;
|
15416
|
+
}
|
15417
|
+
|
15418
|
+
.dots.base .dot {
|
15341
15419
|
width: 12px;
|
15342
15420
|
height: 12px;
|
15421
|
+
}
|
15422
|
+
|
15423
|
+
.dots.large .dot {
|
15424
|
+
width: 16px;
|
15425
|
+
height: 16px;
|
15426
|
+
}
|
15427
|
+
|
15428
|
+
.dots .dot {
|
15343
15429
|
border-radius: 50%;
|
15344
15430
|
cursor: pointer;
|
15345
15431
|
transition: all 0.3s ease;
|
@@ -15387,6 +15473,10 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
|
15387
15473
|
flex-direction: column;
|
15388
15474
|
}
|
15389
15475
|
|
15476
|
+
.buttons {
|
15477
|
+
opacity: var(--opacity, 1);
|
15478
|
+
}
|
15479
|
+
|
15390
15480
|
.buttons button {
|
15391
15481
|
background-color: #00000080;
|
15392
15482
|
color: #fff;
|
@@ -15396,6 +15486,18 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
|
15396
15486
|
transition: background-color 0.3s ease;
|
15397
15487
|
}
|
15398
15488
|
|
15489
|
+
.buttons.small button {
|
15490
|
+
padding: 6px;
|
15491
|
+
}
|
15492
|
+
|
15493
|
+
.buttons.base button {
|
15494
|
+
padding: 10px;
|
15495
|
+
}
|
15496
|
+
|
15497
|
+
.buttons.large button {
|
15498
|
+
padding: 14px;
|
15499
|
+
}
|
15500
|
+
|
15399
15501
|
.buttons button:hover {
|
15400
15502
|
background-color: #000000b3;
|
15401
15503
|
}
|
@@ -15468,11 +15570,6 @@ const CAROUSEL_COMPONENT_STYLE = ({ width, height, fluid }) => `
|
|
15468
15570
|
padding: 8px 12px;
|
15469
15571
|
font-size: 14px;
|
15470
15572
|
}
|
15471
|
-
|
15472
|
-
.dots .dot {
|
15473
|
-
width: 8px;
|
15474
|
-
height: 8px;
|
15475
|
-
}
|
15476
15573
|
}
|
15477
15574
|
`;
|
15478
15575
|
|
@@ -15512,6 +15609,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15512
15609
|
position: 'bottom-center',
|
15513
15610
|
color: '#d9d9d9',
|
15514
15611
|
activeColor: '#b5914a',
|
15612
|
+
size: 'base',
|
15613
|
+
opacity: 1,
|
15515
15614
|
...(typeof ((_j = this.data) === null || _j === void 0 ? void 0 : _j.useDots) === 'object' ? this.data.useDots : {}),
|
15516
15615
|
};
|
15517
15616
|
this.buttonsOptions = {
|
@@ -15522,6 +15621,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15522
15621
|
borderRadius: '50%',
|
15523
15622
|
prev: 'Prev',
|
15524
15623
|
next: 'Next',
|
15624
|
+
size: 'base',
|
15625
|
+
opacity: 1,
|
15525
15626
|
...(typeof ((_k = this.data) === null || _k === void 0 ? void 0 : _k.useButtons) === 'object' ? this.data.useButtons : {}),
|
15526
15627
|
};
|
15527
15628
|
this.validateOptions();
|
@@ -15607,7 +15708,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15607
15708
|
}
|
15608
15709
|
renderDots() {
|
15609
15710
|
const dotsContainer = document.createElement('div');
|
15610
|
-
dotsContainer.className = `dots ${this.dotsOptions.position}`;
|
15711
|
+
dotsContainer.className = `dots ${this.dotsOptions.position} ${this.dotsOptions.size}`;
|
15712
|
+
dotsContainer.style.cssText = `--opacity: ${this.dotsOptions.opacity}`;
|
15611
15713
|
this.slides.forEach((_, index) => {
|
15612
15714
|
const dot = document.createElement('span');
|
15613
15715
|
dot.className = `dot ${index === this.currentSlide ? 'active' : ''}`;
|
@@ -15621,7 +15723,8 @@ if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined
|
|
15621
15723
|
const buttonsClass = this.buttonsOptions.together
|
15622
15724
|
? `buttons-together ${this.buttonsOptions.position}`
|
15623
15725
|
: 'buttons-separate';
|
15624
|
-
buttonsContainer.className = `buttons ${buttonsClass}`;
|
15726
|
+
buttonsContainer.className = `buttons ${buttonsClass} ${this.buttonsOptions.size}`;
|
15727
|
+
buttonsContainer.style.cssText = `--opacity: ${this.buttonsOptions.opacity}`;
|
15625
15728
|
this.prevButton = this.createButton('prev-button', this.buttonsOptions.prev);
|
15626
15729
|
this.nextButton = this.createButton('next-button', this.buttonsOptions.next);
|
15627
15730
|
buttonsContainer.appendChild(this.prevButton);
|
@@ -15855,14 +15958,15 @@ class ElementService {
|
|
15855
15958
|
* @return {HTMLElement | null} - The html element or null if the browser environment is not available.
|
15856
15959
|
*/
|
15857
15960
|
createSpotElement({ content, config }) {
|
15858
|
-
var _a;
|
15961
|
+
var _a, _b;
|
15859
15962
|
if (!this.ensureBrowserEnvironmentAndDefineElement()) {
|
15860
15963
|
return null;
|
15861
15964
|
}
|
15862
15965
|
const spot = document.createElement(SPOT_ELEMENT_TAG);
|
15966
|
+
spot.setAttribute('type', (_a = config === null || config === void 0 ? void 0 : config.spot) !== null && _a !== void 0 ? _a : '');
|
15863
15967
|
spot.data = {
|
15864
15968
|
spot: config === null || config === void 0 ? void 0 : config.spot,
|
15865
|
-
fluid: (
|
15969
|
+
fluid: (_b = config === null || config === void 0 ? void 0 : config.fluid) !== null && _b !== void 0 ? _b : false,
|
15866
15970
|
...config,
|
15867
15971
|
};
|
15868
15972
|
spot.content = content;
|
@@ -15928,11 +16032,172 @@ class ElementService {
|
|
15928
16032
|
}
|
15929
16033
|
}
|
15930
16034
|
|
15931
|
-
|
15932
|
-
|
16035
|
+
class UniqueIdGenerator {
|
16036
|
+
/**
|
16037
|
+
* Initialize the generator with a node ID
|
16038
|
+
* @param nodeId Number between 0-1023 to identify this instance
|
16039
|
+
*/
|
16040
|
+
static initialize(nodeId = Math.floor(Math.random() * 1024)) {
|
16041
|
+
if (nodeId < 0 || nodeId >= 1 << this.nodeBits) {
|
16042
|
+
throw new Error(`Node ID must be between 0 and ${(1 << this.nodeBits) - 1}`);
|
16043
|
+
}
|
16044
|
+
this.nodeId = nodeId;
|
16045
|
+
}
|
16046
|
+
/**
|
16047
|
+
* Convert a number to base32 string with specified length
|
16048
|
+
*/
|
16049
|
+
static toBase32(num, length) {
|
16050
|
+
let result = '';
|
16051
|
+
while (num > 0) {
|
16052
|
+
result = this.base32Chars[Number(num % BigInt(32))] + result;
|
16053
|
+
// @ts-expect-error - TS doesn't support bigint division
|
16054
|
+
num = num / 32n;
|
16055
|
+
}
|
16056
|
+
return result.padStart(length, '0');
|
16057
|
+
}
|
16058
|
+
/**
|
16059
|
+
* Generate a cryptographically secure random number
|
16060
|
+
*/
|
16061
|
+
static getSecureRandom() {
|
16062
|
+
if (typeof crypto !== 'undefined') {
|
16063
|
+
const buffer = new Uint32Array(1);
|
16064
|
+
crypto.getRandomValues(buffer);
|
16065
|
+
return buffer[0];
|
16066
|
+
}
|
16067
|
+
return Math.floor(Math.random() * 0xffffffff);
|
16068
|
+
}
|
16069
|
+
/**
|
16070
|
+
* Wait until next millisecond
|
16071
|
+
*/
|
16072
|
+
static waitNextMillis(lastTimestamp) {
|
16073
|
+
let timestamp = Date.now();
|
16074
|
+
while (timestamp <= lastTimestamp) {
|
16075
|
+
timestamp = Date.now();
|
16076
|
+
}
|
16077
|
+
return timestamp;
|
16078
|
+
}
|
16079
|
+
/**
|
16080
|
+
* Generates a highly unique ID with the following format:
|
16081
|
+
* TTTTTTTTTTCCCCNNNNNRRRR
|
16082
|
+
* T: Timestamp (10 chars)
|
16083
|
+
* C: Counter (4 chars)
|
16084
|
+
* N: Node ID (5 chars)
|
16085
|
+
* R: Random (4 chars)
|
16086
|
+
*
|
16087
|
+
* Total length: 23 characters, always uppercase alphanumeric
|
16088
|
+
*/
|
16089
|
+
static generate() {
|
16090
|
+
if (this.nodeId === undefined) {
|
16091
|
+
this.initialize();
|
16092
|
+
}
|
16093
|
+
let timestamp = Date.now() - this.epoch;
|
16094
|
+
// Handle clock moving backwards or same millisecond
|
16095
|
+
if (timestamp < this.lastTimestamp) {
|
16096
|
+
throw new Error('Clock moved backwards. Refusing to generate ID.');
|
16097
|
+
}
|
16098
|
+
if (timestamp === this.lastTimestamp) {
|
16099
|
+
this.sequence = (this.sequence + 1) & ((1 << this.sequenceBits) - 1);
|
16100
|
+
if (this.sequence === 0) {
|
16101
|
+
timestamp = this.waitNextMillis(this.lastTimestamp);
|
16102
|
+
}
|
16103
|
+
}
|
16104
|
+
else {
|
16105
|
+
this.sequence = 0;
|
16106
|
+
}
|
16107
|
+
this.lastTimestamp = timestamp;
|
16108
|
+
// Generate random component
|
16109
|
+
const random = this.getSecureRandom() & 0xffff; // 16 bits of randomness
|
16110
|
+
// Combine all components into a BigInt
|
16111
|
+
// const id =
|
16112
|
+
// (BigInt(timestamp) << BigInt(this.nodeBits + this.sequenceBits + 16)) |
|
16113
|
+
// (BigInt(this.nodeId) << BigInt(this.sequenceBits + 16)) |
|
16114
|
+
// (BigInt(this.sequence) << BigInt(16)) |
|
16115
|
+
// BigInt(random);
|
16116
|
+
// Convert to base32 representation
|
16117
|
+
const timeComponent = this.toBase32(BigInt(timestamp), 10);
|
16118
|
+
const counterComponent = this.toBase32(BigInt(this.sequence), 4);
|
16119
|
+
const nodeComponent = this.toBase32(BigInt(this.nodeId), 5);
|
16120
|
+
const randomComponent = this.toBase32(BigInt(random), 4);
|
16121
|
+
return `${timeComponent}${counterComponent}${nodeComponent}${randomComponent}`;
|
16122
|
+
}
|
16123
|
+
/**
|
16124
|
+
* Validates if a string matches the expected ID format
|
16125
|
+
*/
|
16126
|
+
static isValid(id) {
|
16127
|
+
if (!/^[0-9A-HJ-NP-Z]{23}$/.test(id))
|
16128
|
+
return false;
|
16129
|
+
try {
|
16130
|
+
const timeComponent = id.slice(0, 10);
|
16131
|
+
const timestamp = this.decodeBase32(timeComponent);
|
16132
|
+
const now = Date.now() - this.epoch;
|
16133
|
+
return timestamp >= 0 && timestamp <= now;
|
16134
|
+
}
|
16135
|
+
catch (_a) {
|
16136
|
+
return false;
|
16137
|
+
}
|
16138
|
+
}
|
16139
|
+
/**
|
16140
|
+
* Decode base32 string to number
|
16141
|
+
*/
|
16142
|
+
static decodeBase32(str) {
|
16143
|
+
let result = 0;
|
16144
|
+
for (const char of str) {
|
16145
|
+
result = result * 32 + this.base32Chars.indexOf(char);
|
16146
|
+
}
|
16147
|
+
return result;
|
16148
|
+
}
|
16149
|
+
/**
|
16150
|
+
* Extract timestamp from ID
|
16151
|
+
*/
|
16152
|
+
static getTimestamp(id) {
|
16153
|
+
if (!this.isValid(id))
|
16154
|
+
throw new Error('Invalid ID format');
|
16155
|
+
const timeComponent = id.slice(0, 10);
|
16156
|
+
const timestamp = this.decodeBase32(timeComponent);
|
16157
|
+
return new Date(timestamp + this.epoch);
|
16158
|
+
}
|
16159
|
+
}
|
16160
|
+
// Constants for bit manipulation
|
16161
|
+
UniqueIdGenerator.epoch = 1577836800000; // 2020-01-01 as epoch
|
16162
|
+
UniqueIdGenerator.nodeBits = 10;
|
16163
|
+
UniqueIdGenerator.sequenceBits = 12;
|
16164
|
+
// Instance variables
|
16165
|
+
UniqueIdGenerator.lastTimestamp = -1;
|
16166
|
+
UniqueIdGenerator.sequence = 0;
|
16167
|
+
// Character set for base32 encoding (excluding similar looking characters)
|
16168
|
+
UniqueIdGenerator.base32Chars = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
|
16169
|
+
|
16170
|
+
function convertHexToRgba(hex, opacity = 1) {
|
16171
|
+
// Remove # if present
|
16172
|
+
const cleanHex = hex.replace('#', '');
|
16173
|
+
// Convert hex to RGB
|
16174
|
+
const r = parseInt(cleanHex.substring(0, 2), 16);
|
16175
|
+
const g = parseInt(cleanHex.substring(2, 4), 16);
|
16176
|
+
const b = parseInt(cleanHex.substring(4, 6), 16);
|
16177
|
+
// Return rgba string
|
16178
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
16179
|
+
}
|
16180
|
+
function generateGradientColor(overlay, fallback = '') {
|
16181
|
+
if (!overlay) {
|
15933
16182
|
return fallback;
|
15934
16183
|
}
|
15935
|
-
|
16184
|
+
const OVERLAY_SIZE = {
|
16185
|
+
small: 10,
|
16186
|
+
base: 30,
|
16187
|
+
large: 50,
|
16188
|
+
};
|
16189
|
+
const OVERLAY_OPACITY = {
|
16190
|
+
light: 0.1,
|
16191
|
+
medium: 0.4,
|
16192
|
+
dark: 0.6,
|
16193
|
+
};
|
16194
|
+
const { size, opacity, color } = overlay;
|
16195
|
+
const goTo = OVERLAY_SIZE[size];
|
16196
|
+
const overlayOpacity = OVERLAY_OPACITY[opacity];
|
16197
|
+
const fullColor = convertHexToRgba(color, 1);
|
16198
|
+
const transparentColor = convertHexToRgba(color, 0);
|
16199
|
+
const gradientColor = convertHexToRgba(color, overlayOpacity);
|
16200
|
+
return `${fullColor} 0%, ${gradientColor} ${goTo}%, ${transparentColor} 100%`;
|
15936
16201
|
}
|
15937
16202
|
function spotHtmlStringToElement(htmlString) {
|
15938
16203
|
const spot = document.createElement('div');
|
@@ -16796,7 +17061,7 @@ function rbCollectionBannerWithoutTextBlockTemplate(spot, config) {
|
|
16796
17061
|
}
|
16797
17062
|
|
16798
17063
|
const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
|
16799
|
-
const linearGradient =
|
17064
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 40%');
|
16800
17065
|
return `
|
16801
17066
|
<style>
|
16802
17067
|
.${prefix} {
|
@@ -17287,7 +17552,7 @@ function rbHomepageHeroTwoTileTemplate(spot, config) {
|
|
17287
17552
|
}
|
17288
17553
|
|
17289
17554
|
const STYLES$3 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderColor = ctaTextColor, primaryImage, mobilePrimaryImage = primaryImage, }, { prefix, overlay }) => {
|
17290
|
-
const linearGradient =
|
17555
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
17291
17556
|
return `
|
17292
17557
|
<style>
|
17293
17558
|
.${prefix} {
|
@@ -17424,7 +17689,7 @@ function rbLargeCategoryImageToutTemplate(spot, config) {
|
|
17424
17689
|
}
|
17425
17690
|
|
17426
17691
|
const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
|
17427
|
-
const linearGradient =
|
17692
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
17428
17693
|
return `
|
17429
17694
|
<style>
|
17430
17695
|
.${prefix} {
|
@@ -17441,11 +17706,7 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
17441
17706
|
background-position: center;
|
17442
17707
|
background-repeat: no-repeat;
|
17443
17708
|
container-type: inline-size;
|
17444
|
-
|
17445
|
-
|
17446
|
-
.${prefix}__text {
|
17447
|
-
padding: 15px 10%;
|
17448
|
-
width: fit-content;
|
17709
|
+
position: relative;
|
17449
17710
|
}
|
17450
17711
|
|
17451
17712
|
.${prefix}__header {
|
@@ -17456,6 +17717,7 @@ const STYLES$2 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = pr
|
|
17456
17717
|
font-family: "Source Sans 3", system-ui;
|
17457
17718
|
font-style: normal;
|
17458
17719
|
margin: 0;
|
17720
|
+
padding: 15px 10%;
|
17459
17721
|
}
|
17460
17722
|
|
17461
17723
|
@container (min-width: 640px) {
|
@@ -17491,15 +17753,13 @@ function rbNavigationBannerTemplate(spot, config) {
|
|
17491
17753
|
${GFONT_SOURCE_SANS_3}
|
17492
17754
|
${STYLES$2(spot, config)}
|
17493
17755
|
<div class="${prefix}">
|
17494
|
-
<div class="${prefix}__text">
|
17495
17756
|
${spot.header ? `<h2 class="${prefix}__header">${spot.header}</h2>` : ''}
|
17496
|
-
</div>
|
17497
17757
|
</div>
|
17498
17758
|
`;
|
17499
17759
|
}
|
17500
17760
|
|
17501
17761
|
const STYLES$1 = ({ textColor = '#ffffff', primaryImage, mobilePrimaryImage = primaryImage }, { prefix, overlay }) => {
|
17502
|
-
const linearGradient =
|
17762
|
+
const linearGradient = generateGradientColor(overlay, 'rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0) 30%');
|
17503
17763
|
return `
|
17504
17764
|
<style>
|
17505
17765
|
.${prefix} {
|
@@ -17695,8 +17955,8 @@ const SPOT_TEMPLATE_HTML_ELEMENT = (spot, config) => {
|
|
17695
17955
|
if (!variantTemplate) {
|
17696
17956
|
return null;
|
17697
17957
|
}
|
17698
|
-
// Generate a
|
17699
|
-
const prefix = 's' +
|
17958
|
+
// Generate a highly unique prefix to avoid conflicts with other elements.
|
17959
|
+
const prefix = 's' + UniqueIdGenerator.generate().toLowerCase();
|
17700
17960
|
const spotHtmlString = variantTemplate(spot, { ...config, prefix });
|
17701
17961
|
return spotHtmlStringToElement(spotHtmlString);
|
17702
17962
|
};
|
@@ -17713,6 +17973,12 @@ class PubSub {
|
|
17713
17973
|
*/
|
17714
17974
|
this.subscribers = {};
|
17715
17975
|
}
|
17976
|
+
static getInstance() {
|
17977
|
+
if (!PubSub.instance) {
|
17978
|
+
PubSub.instance = new PubSub();
|
17979
|
+
}
|
17980
|
+
return PubSub.instance;
|
17981
|
+
}
|
17716
17982
|
/**
|
17717
17983
|
* Subscribe to an event
|
17718
17984
|
* @param eventType - The type of event to subscribe to
|
@@ -17778,7 +18044,8 @@ class PubSub {
|
|
17778
18044
|
|
17779
18045
|
class EventService {
|
17780
18046
|
constructor() {
|
17781
|
-
this.pubSub =
|
18047
|
+
this.pubSub = PubSub.getInstance();
|
18048
|
+
this.localStorage = LocalStorage.getInstance();
|
17782
18049
|
this.activeSpots = new Map();
|
17783
18050
|
this.spotStates = new Map();
|
17784
18051
|
this.intersectionObserver = new IntersectionObserverService();
|
@@ -17795,6 +18062,59 @@ class EventService {
|
|
17795
18062
|
publish(eventType, data) {
|
17796
18063
|
this.pubSub.publish(eventType, data);
|
17797
18064
|
}
|
18065
|
+
registerSpot(params) {
|
18066
|
+
const { placementId, spot, spotElement } = params;
|
18067
|
+
this.activeSpots.set(placementId, { spotElement });
|
18068
|
+
// Fire impression event
|
18069
|
+
this.fireImpressionEvent(placementId, spot, spotElement);
|
18070
|
+
// Handle intersection observer
|
18071
|
+
this.handleIntersectionObserver(placementId, spot, spotElement);
|
18072
|
+
// Attach click event listener
|
18073
|
+
spotElement.addEventListener('click', async () => await this.handleClick(params));
|
18074
|
+
}
|
18075
|
+
unregisterSpot(placementId) {
|
18076
|
+
const placementIdClean = placementId.replace('#', '');
|
18077
|
+
const spotData = this.activeSpots.get(placementIdClean);
|
18078
|
+
if (!spotData) {
|
18079
|
+
this.handleSpotState(placementIdClean, {
|
18080
|
+
state: {
|
18081
|
+
error: `Active spot with placementId ${placementIdClean} not found.`,
|
18082
|
+
},
|
18083
|
+
});
|
18084
|
+
return;
|
18085
|
+
}
|
18086
|
+
this.intersectionObserver.unobserve(spotData.spotElement);
|
18087
|
+
this.handleSpotState(placementIdClean, {
|
18088
|
+
dom: {
|
18089
|
+
spotElement: undefined,
|
18090
|
+
visibleOnViewport: false,
|
18091
|
+
},
|
18092
|
+
state: {
|
18093
|
+
unmounted: true,
|
18094
|
+
mounted: false,
|
18095
|
+
},
|
18096
|
+
});
|
18097
|
+
this.activeSpots.delete(placementIdClean);
|
18098
|
+
const placementElement = document.getElementById(placementIdClean);
|
18099
|
+
if (!placementElement) {
|
18100
|
+
this.handleSpotState(placementIdClean, {
|
18101
|
+
state: {
|
18102
|
+
error: `Placement element with id ${placementIdClean} not found.`,
|
18103
|
+
},
|
18104
|
+
});
|
18105
|
+
return;
|
18106
|
+
}
|
18107
|
+
placementElement.innerHTML = '';
|
18108
|
+
}
|
18109
|
+
/**
|
18110
|
+
* Updates the state of a spot.
|
18111
|
+
*
|
18112
|
+
* @param {string} placementId - The placement ID of the spot.
|
18113
|
+
* @param {Partial<ILifecycleState>} updates - The updates to apply to the spot state.
|
18114
|
+
* @param {boolean} publish - Whether to publish the updated state.
|
18115
|
+
*
|
18116
|
+
* @returns {void}
|
18117
|
+
*/
|
17798
18118
|
handleSpotState(placementId, updates, publish = true) {
|
17799
18119
|
let currentState = this.spotStates.get(placementId);
|
17800
18120
|
if (!currentState) {
|
@@ -17805,8 +18125,8 @@ class EventService {
|
|
17805
18125
|
spotType: '',
|
17806
18126
|
},
|
17807
18127
|
dom: {
|
17808
|
-
|
17809
|
-
|
18128
|
+
spotElement: undefined,
|
18129
|
+
visibleOnViewport: false,
|
17810
18130
|
},
|
17811
18131
|
state: {
|
17812
18132
|
mounted: false,
|
@@ -17821,81 +18141,57 @@ class EventService {
|
|
17821
18141
|
},
|
17822
18142
|
};
|
17823
18143
|
}
|
17824
|
-
this.spotStates.set(placementId, {
|
17825
|
-
...currentState,
|
17826
|
-
...updates,
|
17827
|
-
});
|
18144
|
+
this.spotStates.set(placementId, { ...currentState, ...updates });
|
17828
18145
|
if (publish) {
|
17829
18146
|
this.pubSub.publish(RMN_SPOT_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
|
17830
18147
|
}
|
17831
18148
|
}
|
17832
|
-
|
17833
|
-
|
18149
|
+
async handleClick({ placementId, spot, spotElement, }) {
|
18150
|
+
var _a, _b, _c;
|
18151
|
+
// Publish click event
|
18152
|
+
this.pubSub.publish(RMN_SPOT_EVENT.CLICK, {
|
17834
18153
|
placementId,
|
17835
|
-
|
17836
|
-
|
18154
|
+
spotId: spot.id,
|
18155
|
+
spotElement,
|
17837
18156
|
});
|
17838
|
-
//
|
17839
|
-
this.
|
17840
|
-
|
17841
|
-
|
17842
|
-
|
17843
|
-
|
17844
|
-
|
17845
|
-
|
17846
|
-
|
17847
|
-
|
17848
|
-
|
17849
|
-
await this.fireEvent({
|
17850
|
-
event: RMN_SPOT_EVENT.CLICK,
|
17851
|
-
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 : '',
|
17852
|
-
});
|
18157
|
+
// Fire click event
|
18158
|
+
await this.fireEvent({
|
18159
|
+
event: RMN_SPOT_EVENT.CLICK,
|
18160
|
+
eventUrl: (_b = (_a = spot.events.find((event) => event.event === RMN_SPOT_EVENT.CLICK)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : '',
|
18161
|
+
});
|
18162
|
+
// Save spot to local storage for event tracking
|
18163
|
+
this.localStorage.setSpot(spot.id, {
|
18164
|
+
spotId: spot.id,
|
18165
|
+
spotType: spot.spot,
|
18166
|
+
events: spot.events,
|
18167
|
+
productIds: (_c = spot.productIds) !== null && _c !== void 0 ? _c : [1, 'GROUPING-12345', 'DAN-12345', 131398103],
|
17853
18168
|
});
|
17854
18169
|
}
|
17855
|
-
|
17856
|
-
const
|
17857
|
-
|
17858
|
-
this.
|
17859
|
-
this.handleSpotState(spotData.placementId, {
|
18170
|
+
handleIntersectionObserver(placementId, _spot, spotElement) {
|
18171
|
+
const spotIsVisibleCallback = async () => {
|
18172
|
+
this.intersectionObserver.unobserve(spotElement);
|
18173
|
+
this.handleSpotState(placementId, {
|
17860
18174
|
dom: {
|
17861
|
-
|
17862
|
-
|
17863
|
-
},
|
17864
|
-
state: {
|
17865
|
-
unmounted: true,
|
17866
|
-
mounted: false,
|
18175
|
+
spotElement,
|
18176
|
+
visibleOnViewport: true,
|
17867
18177
|
},
|
17868
18178
|
});
|
17869
|
-
|
17870
|
-
|
18179
|
+
};
|
18180
|
+
this.intersectionObserver.observe(spotElement, spotIsVisibleCallback);
|
17871
18181
|
}
|
17872
|
-
|
17873
|
-
|
18182
|
+
fireImpressionEvent(placementId, spot, spotElement) {
|
18183
|
+
this.pubSub.publish(RMN_SPOT_EVENT.IMPRESSION, {
|
18184
|
+
placementId,
|
18185
|
+
spotId: spot.id,
|
18186
|
+
spotElement,
|
18187
|
+
});
|
18188
|
+
(async () => {
|
17874
18189
|
var _a, _b;
|
17875
|
-
this.pubSub.publish(RMN_SPOT_EVENT.IMPRESSION, {
|
17876
|
-
placementId,
|
17877
|
-
spotId: spot.id,
|
17878
|
-
element,
|
17879
|
-
});
|
17880
|
-
this.intersectionObserver.unobserve(element);
|
17881
|
-
this.activeSpots.set(spot.id, {
|
17882
|
-
placementId,
|
17883
|
-
element,
|
17884
|
-
impressionTracked: true,
|
17885
|
-
});
|
17886
|
-
this.handleSpotState(placementId, {
|
17887
|
-
dom: {
|
17888
|
-
element,
|
17889
|
-
visible: true,
|
17890
|
-
},
|
17891
|
-
});
|
17892
|
-
// Fire impression event
|
17893
18190
|
await this.fireEvent({
|
17894
18191
|
event: RMN_SPOT_EVENT.IMPRESSION,
|
17895
18192
|
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 : '',
|
17896
18193
|
});
|
17897
|
-
};
|
17898
|
-
this.intersectionObserver.observe(element, spotIsVisibleCb);
|
18194
|
+
})();
|
17899
18195
|
}
|
17900
18196
|
/**
|
17901
18197
|
* Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
|
@@ -17960,23 +18256,178 @@ class SelectionService extends BaseApi {
|
|
17960
18256
|
}
|
17961
18257
|
}
|
17962
18258
|
|
18259
|
+
const SPOT_EVENTS_EXAMPLE = [
|
18260
|
+
{
|
18261
|
+
event: RMN_SPOT_EVENT.CLICK,
|
18262
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwidXIiOm51bGx9&s=hWz37kbxi_u95EVNn2aoQhc5Aas',
|
18263
|
+
},
|
18264
|
+
{
|
18265
|
+
event: RMN_SPOT_EVENT.IMPRESSION,
|
18266
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiYmEiOjEsImZxIjowfQ&s=djoysjCimurf-5T11AlNAwwLSS8',
|
18267
|
+
},
|
18268
|
+
{
|
18269
|
+
event: RMN_SPOT_EVENT.PURCHASE,
|
18270
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjU5fQ&s=AAPAw-3SfZ0JMzjEGFSwt9L-2S4',
|
18271
|
+
},
|
18272
|
+
{
|
18273
|
+
event: RMN_SPOT_EVENT.ADD_TO_CART,
|
18274
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYwfQ&s=uzQFcjgL7m9XqUG8FvTPVN5YkZY',
|
18275
|
+
},
|
18276
|
+
{
|
18277
|
+
event: RMN_SPOT_EVENT.ADD_TO_WISHLIST,
|
18278
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjYzfQ&s=m3ISU_iIy-OFtXrTKpI6cJAEC0k',
|
18279
|
+
},
|
18280
|
+
{
|
18281
|
+
event: RMN_SPOT_EVENT.BUY_NOW,
|
18282
|
+
url: 'https://dev.rmn.liquidcommerce.cloud/api/spots/event?e=eyJ2IjoiMS4xMiIsImF2IjozMDY1NzgzLCJhdCI6MTYzLCJidCI6MCwiY20iOjQ0MDE5MjQxOCwiY2giOjYzMTg0LCJjayI6e30sImNyIjo0ODE4NTUzNzUsImRpIjoiOWMxNGFhMGI3NWY4NDMxNTllMTAwYWQzNzA1NzQyYzMiLCJkaiI6MCwiaWkiOiIxZjU0MGM5NmQ1N2M0YmZjODFlZjRkNjhkMzFjNDVkOSIsImRtIjozLCJmYyI6NjU2NjgyNTQ5LCJmbCI6NjQzOTMxODIxLCJpcCI6IjM1LjIyMy4xOTguOTUiLCJudyI6MTE1MDAsInBjIjo1MDAwLCJvcCI6NTAwMCwibXAiOjUwMDAsImVjIjowLCJnbSI6MCwiZXAiOm51bGwsInByIjoyNDkzMTYsInJ0IjoxLCJycyI6NTAwLCJzYSI6IjU1Iiwic2IiOiJpLTA0MDI0ODg4ZDlkMWRjZWQ3Iiwic3AiOjI3MjI3Miwic3QiOjEyODcyOTYsInRyIjp0cnVlLCJ1ayI6IjNhZWRhMWMxLTZhYjItNDUwNy04Mzg5LTEwZTJmNDMxYjM5MSIsInRzIjoxNzI5MzU5MDU0OTI3LCJiZiI6dHJ1ZSwicG4iOiJyYlByb2R1Y3RVcGNzIiwiZ2MiOnRydWUsImdDIjp0cnVlLCJncyI6Im5vbmUiLCJkYyI6MSwidHoiOiJBbWVyaWNhL05ld19Zb3JrIiwiZXQiOjY5fQ&s=l6MOscQC-q-FkC2Ksd7w6jjySCQ',
|
18283
|
+
},
|
18284
|
+
];
|
18285
|
+
const RB_SPOTS_SELECTION_EXAMPLE = {
|
18286
|
+
rbHomepageHeroFullImage: [
|
18287
|
+
{
|
18288
|
+
id: '111111_111111',
|
18289
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
18290
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
18291
|
+
width: 1140,
|
18292
|
+
height: 640,
|
18293
|
+
header: 'Artisanal Craft Beer Collection',
|
18294
|
+
description: 'Discover our curated selection of small-batch, flavor-packed craft beers.',
|
18295
|
+
ctaText: 'Explore the Collection',
|
18296
|
+
textColor: '#ffffff',
|
18297
|
+
ctaTextColor: '#ffffff',
|
18298
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Craft+Beer+Collection',
|
18299
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Craft+Beer',
|
18300
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18301
|
+
},
|
18302
|
+
{
|
18303
|
+
id: '222222_222222',
|
18304
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
18305
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_FULL_IMAGE,
|
18306
|
+
width: 1140,
|
18307
|
+
height: 640,
|
18308
|
+
header: 'Summer Wine Spectacular',
|
18309
|
+
description: 'Refresh your palate with our handpicked selection of crisp, summer wines.',
|
18310
|
+
ctaText: 'Shop Summer Wines',
|
18311
|
+
textColor: '#000000',
|
18312
|
+
ctaTextColor: '#ffffff',
|
18313
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Summer+Wines',
|
18314
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Summer+Wines',
|
18315
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18316
|
+
},
|
18317
|
+
],
|
18318
|
+
rbHomepageHeroTwoTile: [
|
18319
|
+
{
|
18320
|
+
id: '333333_333333',
|
18321
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
18322
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_TWO_TILE,
|
18323
|
+
width: 1140,
|
18324
|
+
height: 640,
|
18325
|
+
header: 'Whiskey Wonderland',
|
18326
|
+
description: 'Embark on a journey through our premium whiskey selection.',
|
18327
|
+
ctaText: 'Discover Whiskeys',
|
18328
|
+
textColor: '#ffffff',
|
18329
|
+
backgroundColor: '#2c1a05',
|
18330
|
+
ctaTextColor: '#2c1a05',
|
18331
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Whiskey+Collection',
|
18332
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Whiskey',
|
18333
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18334
|
+
},
|
18335
|
+
],
|
18336
|
+
rbHomepageHeroThreeTile: [
|
18337
|
+
{
|
18338
|
+
id: '444444_444444',
|
18339
|
+
spot: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
18340
|
+
variant: RMN_SPOT_TYPE.RB_HOMEPAGE_HERO_THREE_TILE,
|
18341
|
+
width: 1140,
|
18342
|
+
height: 640,
|
18343
|
+
header: 'Cocktail Essentials',
|
18344
|
+
description: 'Stock your bar with premium spirits and mixers for the perfect cocktail.',
|
18345
|
+
ctaText: 'Build Your Bar',
|
18346
|
+
textColor: '#ffffff',
|
18347
|
+
backgroundColor: '#1a3c4d',
|
18348
|
+
ctaTextColor: '#1a3c4d',
|
18349
|
+
primaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Spirits',
|
18350
|
+
secondaryImage: 'https://placehold.co/1140x640/png?text=Cocktail+Mixers',
|
18351
|
+
mobilePrimaryImage: 'https://placehold.co/640x640/png?text=Mobile+Cocktail+Kit',
|
18352
|
+
mobileSecondaryImage: 'https://placehold.co/640x320/png?text=Mobile+Cocktail+Mixers',
|
18353
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18354
|
+
},
|
18355
|
+
],
|
18356
|
+
rbLargeCategoryImageTout: [
|
18357
|
+
{
|
18358
|
+
id: '555555_555555',
|
18359
|
+
spot: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
18360
|
+
variant: RMN_SPOT_TYPE.RB_LARGE_CATEGORY_IMAGE_TOUT,
|
18361
|
+
width: 468,
|
18362
|
+
height: 410,
|
18363
|
+
header: 'Rare & Limited Edition',
|
18364
|
+
description: 'Discover our collection of hard-to-find and limited release spirits.',
|
18365
|
+
textColor: '#ffffff',
|
18366
|
+
ctaTextColor: '#ffffff',
|
18367
|
+
primaryImage: 'https://placehold.co/468x410/png?text=Rare+Spirits',
|
18368
|
+
mobilePrimaryImage: 'https://placehold.co/468x410/png?text=Mobile+Rare+Spirits',
|
18369
|
+
ctaText: 'Shop Rare Spirits',
|
18370
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18371
|
+
},
|
18372
|
+
],
|
18373
|
+
rbSmallDiscoverTout: [
|
18374
|
+
{
|
18375
|
+
id: '666666_666666',
|
18376
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
18377
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_DISCOVER_TOUT,
|
18378
|
+
width: 224,
|
18379
|
+
height: 378,
|
18380
|
+
header: 'Château Margaux 2015 Bordeaux',
|
18381
|
+
textColor: '#ffffff',
|
18382
|
+
primaryImage: 'https://placehold.co/224x378/png?text=Château+Margaux',
|
18383
|
+
mobilePrimaryImage: 'https://placehold.co/224x378/png?text=Mobile+Château+Margaux',
|
18384
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18385
|
+
},
|
18386
|
+
],
|
18387
|
+
rbSmallCategoryImageTout: [
|
18388
|
+
{
|
18389
|
+
id: '777777_777777',
|
18390
|
+
spot: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
18391
|
+
variant: RMN_SPOT_TYPE.RB_SMALL_CATEGORY_IMAGE_TOUT,
|
18392
|
+
width: 224,
|
18393
|
+
height: 410,
|
18394
|
+
header: 'Japanese Sake',
|
18395
|
+
textColor: '#ffffff',
|
18396
|
+
primaryImage: 'https://placehold.co/224x410/png?text=Japanese+Sake',
|
18397
|
+
mobilePrimaryImage: 'https://placehold.co/224x410/png?text=Mobile+Japanese+Sake',
|
18398
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18399
|
+
},
|
18400
|
+
],
|
18401
|
+
rbCollectionBannerWithoutTextBlock: [
|
18402
|
+
{
|
18403
|
+
id: '888888_888888',
|
18404
|
+
spot: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
18405
|
+
variant: RMN_SPOT_TYPE.RB_COLLECTION_BANNER_WITHOUT_TEXT_BLOCK,
|
18406
|
+
width: 887,
|
18407
|
+
height: 344,
|
18408
|
+
primaryImage: 'https://placehold.co/887x344/png?text=Summer+Cocktails',
|
18409
|
+
mobilePrimaryImage: 'https://placehold.co/887x344/png?text=Mobile+Summer+Cocktails',
|
18410
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18411
|
+
},
|
18412
|
+
],
|
18413
|
+
rbNavigationBanner: [
|
18414
|
+
{
|
18415
|
+
id: '999999_999999',
|
18416
|
+
spot: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
18417
|
+
variant: RMN_SPOT_TYPE.RB_NAVIGATION_BANNER,
|
18418
|
+
width: 440,
|
18419
|
+
height: 220,
|
18420
|
+
header: 'Explore Tequilas',
|
18421
|
+
textColor: '#ffffff',
|
18422
|
+
primaryImage: 'https://placehold.co/440x220/png?text=Tequila+Collection',
|
18423
|
+
mobilePrimaryImage: 'https://placehold.co/440x220/png?text=Mobile+Tequila+Collection',
|
18424
|
+
events: SPOT_EVENTS_EXAMPLE,
|
18425
|
+
},
|
18426
|
+
],
|
18427
|
+
};
|
18428
|
+
|
17963
18429
|
class LiquidCommerceRmnClient {
|
17964
18430
|
constructor(auth) {
|
17965
|
-
/**
|
17966
|
-
* Returns the event manager instance.
|
17967
|
-
*
|
17968
|
-
* @return {EventService} - The event manager instance.
|
17969
|
-
*/
|
17970
|
-
this.eventManager = {
|
17971
|
-
subscribe: (eventType, callback
|
17972
|
-
/* eslint-disable arrow-body-style */
|
17973
|
-
) => {
|
17974
|
-
return this.eventService.subscribe(eventType, callback);
|
17975
|
-
},
|
17976
|
-
publish: (eventType, data) => {
|
17977
|
-
this.eventService.publish(eventType, data);
|
17978
|
-
},
|
17979
|
-
};
|
17980
18431
|
this.selectionService = SelectionService.getInstance(auth);
|
17981
18432
|
this.elementService = ElementService.getInstance();
|
17982
18433
|
this.eventService = EventService.getInstance();
|
@@ -18024,6 +18475,7 @@ class LiquidCommerceRmnClient {
|
|
18024
18475
|
inject = this.preventNonExistentSpotTypes(inject);
|
18025
18476
|
// Make the spot selection request
|
18026
18477
|
const response = await this.spotSelectionRequest({ ...params, inject });
|
18478
|
+
// const response = await this.useSpotSelectionExample(inject);
|
18027
18479
|
// Handle the response
|
18028
18480
|
if (typeof response === 'object' && 'error' in response) {
|
18029
18481
|
this.eventService.handleSpotState('all', {
|
@@ -18056,6 +18508,15 @@ class LiquidCommerceRmnClient {
|
|
18056
18508
|
});
|
18057
18509
|
continue;
|
18058
18510
|
}
|
18511
|
+
// Take over placement styles
|
18512
|
+
placement.removeAttribute('style');
|
18513
|
+
placement.removeAttribute('class');
|
18514
|
+
Object.assign(placement.style, {
|
18515
|
+
width: '100%',
|
18516
|
+
height: 'auto',
|
18517
|
+
display: 'flex',
|
18518
|
+
justifyContent: 'center',
|
18519
|
+
});
|
18059
18520
|
if (spots.length === 1) {
|
18060
18521
|
const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
|
18061
18522
|
if (!isInjected) {
|
@@ -18082,14 +18543,12 @@ class LiquidCommerceRmnClient {
|
|
18082
18543
|
const request = {
|
18083
18544
|
url: config === null || config === void 0 ? void 0 : config.url,
|
18084
18545
|
filter,
|
18085
|
-
spots: inject.map((item) => {
|
18086
|
-
|
18087
|
-
|
18088
|
-
|
18089
|
-
|
18090
|
-
|
18091
|
-
};
|
18092
|
-
}),
|
18546
|
+
spots: inject.map((item) => ({
|
18547
|
+
placementId: item.placementId,
|
18548
|
+
spot: item.spotType,
|
18549
|
+
count: item === null || item === void 0 ? void 0 : item.count,
|
18550
|
+
...item === null || item === void 0 ? void 0 : item.filter,
|
18551
|
+
})),
|
18093
18552
|
};
|
18094
18553
|
return this.spotSelection(request);
|
18095
18554
|
}
|
@@ -18127,17 +18586,15 @@ class LiquidCommerceRmnClient {
|
|
18127
18586
|
this.eventService.registerSpot({
|
18128
18587
|
spot,
|
18129
18588
|
placementId: placement.id,
|
18130
|
-
|
18589
|
+
spotElement: content,
|
18131
18590
|
});
|
18132
18591
|
carouselSlides.push(content);
|
18133
18592
|
}
|
18134
18593
|
// Get the max width and height of the spots
|
18135
|
-
const { maxWidth, maxHeight } = spots.reduce((max, spot) => {
|
18136
|
-
|
18137
|
-
|
18138
|
-
|
18139
|
-
};
|
18140
|
-
}, { maxWidth: 0, maxHeight: 0 });
|
18594
|
+
const { maxWidth, maxHeight } = spots.reduce((max, spot) => ({
|
18595
|
+
maxWidth: Math.max(max.maxWidth, spot.width),
|
18596
|
+
maxHeight: Math.max(max.maxHeight, spot.height),
|
18597
|
+
}), { maxWidth: 0, maxHeight: 0 });
|
18141
18598
|
// Create the carousel element
|
18142
18599
|
const carouselElement = this.elementService.createCarouselElement({
|
18143
18600
|
slides: carouselSlides,
|
@@ -18161,7 +18618,7 @@ class LiquidCommerceRmnClient {
|
|
18161
18618
|
placement.replaceChildren(carouselElement);
|
18162
18619
|
this.eventService.handleSpotState(placement.id, {
|
18163
18620
|
dom: {
|
18164
|
-
|
18621
|
+
spotElement: carouselElement,
|
18165
18622
|
},
|
18166
18623
|
state: {
|
18167
18624
|
mounted: true,
|
@@ -18222,12 +18679,12 @@ class LiquidCommerceRmnClient {
|
|
18222
18679
|
this.eventService.registerSpot({
|
18223
18680
|
spot: spotData,
|
18224
18681
|
placementId: injectItem.placementId,
|
18225
|
-
|
18682
|
+
spotElement,
|
18226
18683
|
});
|
18227
18684
|
placement.replaceChildren(spotElement);
|
18228
18685
|
this.eventService.handleSpotState(injectItem.placementId, {
|
18229
18686
|
dom: {
|
18230
|
-
|
18687
|
+
spotElement,
|
18231
18688
|
},
|
18232
18689
|
state: {
|
18233
18690
|
mounted: true,
|
@@ -18288,6 +18745,17 @@ class LiquidCommerceRmnClient {
|
|
18288
18745
|
});
|
18289
18746
|
}
|
18290
18747
|
}
|
18748
|
+
useSpotSelectionExample(inject) {
|
18749
|
+
const examples = RB_SPOTS_SELECTION_EXAMPLE;
|
18750
|
+
const data = {};
|
18751
|
+
inject.map((item) => {
|
18752
|
+
var _a, _b, _c;
|
18753
|
+
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 : [];
|
18754
|
+
});
|
18755
|
+
return new Promise((resolve) => {
|
18756
|
+
resolve(data);
|
18757
|
+
});
|
18758
|
+
}
|
18291
18759
|
}
|
18292
18760
|
/**
|
18293
18761
|
* Creates a new instance of the RmnClient.
|
@@ -18302,6 +18770,36 @@ async function RmnClient(apiKey, config) {
|
|
18302
18770
|
const credentials = await authService.initialize();
|
18303
18771
|
return new LiquidCommerceRmnClient(credentials);
|
18304
18772
|
}
|
18773
|
+
/**
|
18774
|
+
* Creates a new instance of the RmnEventManager.
|
18775
|
+
*
|
18776
|
+
* @return {IRmnEventManager} - The RmnEventManager instance.
|
18777
|
+
*/
|
18778
|
+
function RmnEventManager() {
|
18779
|
+
const eventService = EventService.getInstance();
|
18780
|
+
return {
|
18781
|
+
/**
|
18782
|
+
* Subscribes to an event type.
|
18783
|
+
*/
|
18784
|
+
subscribe: (eventType, callback
|
18785
|
+
/* eslint-disable arrow-body-style */
|
18786
|
+
) => {
|
18787
|
+
return eventService.subscribe(eventType, callback);
|
18788
|
+
},
|
18789
|
+
/**
|
18790
|
+
* Publishes an event type.
|
18791
|
+
*/
|
18792
|
+
publish: (eventType, data) => {
|
18793
|
+
eventService.publish(eventType, data);
|
18794
|
+
},
|
18795
|
+
/**
|
18796
|
+
* Destroys a spot element
|
18797
|
+
*/
|
18798
|
+
destroySpot: (placementId) => {
|
18799
|
+
eventService.unregisterSpot(placementId);
|
18800
|
+
},
|
18801
|
+
};
|
18802
|
+
}
|
18305
18803
|
/**
|
18306
18804
|
* Creates the spot html element based on the provided data using shadow dom.
|
18307
18805
|
*
|
@@ -18334,4 +18832,4 @@ function RmnCreateSpotElement(spot, config) {
|
|
18334
18832
|
});
|
18335
18833
|
}
|
18336
18834
|
|
18337
|
-
export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement };
|
18835
|
+
export { LiquidCommerceRmnClient, RMN_ENV, RMN_FILTER_PROPERTIES, RMN_SPOT_EVENT, RMN_SPOT_TYPE, RmnClient, RmnCreateSpotElement, RmnEventManager };
|