@liquidcommercedev/rmn-sdk 1.4.6-beta.6 → 1.4.6-beta.8
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.cjs +248 -81
- package/dist/index.esm.js +248 -81
- package/dist/types/enums.d.ts +1 -2
- package/dist/types/modules/event/event.interface.d.ts +22 -8
- package/dist/types/modules/event/event.service.d.ts +6 -3
- package/dist/types/modules/selection/selection.interface.d.ts +3 -1
- package/dist/types/modules/selection/selection.service.d.ts +4 -2
- package/dist/types/rmn-client.d.ts +13 -6
- package/dist/types/types.d.ts +9 -4
- package/package.json +1 -1
- package/umd/liquidcommerce-rmn-sdk.min.js +1 -1
package/dist/index.esm.js
CHANGED
@@ -54,8 +54,7 @@ var RMN_FILTER_PROPERTIES;
|
|
54
54
|
})(RMN_FILTER_PROPERTIES || (RMN_FILTER_PROPERTIES = {}));
|
55
55
|
var RMN_SPOT_EVENT;
|
56
56
|
(function (RMN_SPOT_EVENT) {
|
57
|
-
RMN_SPOT_EVENT["
|
58
|
-
RMN_SPOT_EVENT["UNMOUNTED"] = "UNMOUNTED";
|
57
|
+
RMN_SPOT_EVENT["LIFECYCLE_STATE"] = "LIFECYCLE_STATE";
|
59
58
|
RMN_SPOT_EVENT["IMPRESSION"] = "IMPRESSION";
|
60
59
|
RMN_SPOT_EVENT["CLICK"] = "CLICK";
|
61
60
|
RMN_SPOT_EVENT["PURCHASE"] = "PURCHASE";
|
@@ -16825,11 +16824,11 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
16825
16824
|
align-items: flex-start;
|
16826
16825
|
width: 100%;
|
16827
16826
|
height: fit-content;
|
16828
|
-
gap:
|
16827
|
+
gap: 8px;
|
16829
16828
|
}
|
16830
16829
|
|
16831
16830
|
.${prefix}__header {
|
16832
|
-
font-size:
|
16831
|
+
font-size: 24px;
|
16833
16832
|
margin: 0;
|
16834
16833
|
font-family: "Cormorant";
|
16835
16834
|
font-style: normal;
|
@@ -16887,10 +16886,6 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
16887
16886
|
height: 50%;
|
16888
16887
|
}
|
16889
16888
|
|
16890
|
-
.${prefix}__header {
|
16891
|
-
font-size: 22px;
|
16892
|
-
}
|
16893
|
-
|
16894
16889
|
.${prefix}__description {
|
16895
16890
|
font-size: 12px;
|
16896
16891
|
}
|
@@ -16902,7 +16897,7 @@ const STYLES$6 = ({ textColor = '#ffffff', ctaTextColor = textColor, ctaBorderCo
|
|
16902
16897
|
|
16903
16898
|
@container (min-width: 1024px) {
|
16904
16899
|
.${prefix}__header {
|
16905
|
-
font-size:
|
16900
|
+
font-size: 26px;
|
16906
16901
|
}
|
16907
16902
|
|
16908
16903
|
.${prefix}__description {
|
@@ -16963,7 +16958,7 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
16963
16958
|
display: flex;
|
16964
16959
|
flex-direction: column;
|
16965
16960
|
background-color: transparent;
|
16966
|
-
gap:
|
16961
|
+
gap: 6px;
|
16967
16962
|
color: inherit;
|
16968
16963
|
cursor: pointer;
|
16969
16964
|
}
|
@@ -16982,7 +16977,7 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
16982
16977
|
height: 40%;
|
16983
16978
|
display: flex;
|
16984
16979
|
flex-direction: row;
|
16985
|
-
|
16980
|
+
gap: 6px;
|
16986
16981
|
}
|
16987
16982
|
|
16988
16983
|
.${prefix}__secondary-image {
|
@@ -17004,7 +16999,7 @@ const STYLES$5 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
17004
16999
|
align-items: center;
|
17005
17000
|
width: 50%;
|
17006
17001
|
height: 100%;
|
17007
|
-
gap:
|
17002
|
+
gap: 10px;
|
17008
17003
|
padding: 0 10px;
|
17009
17004
|
box-sizing: border-box;
|
17010
17005
|
}
|
@@ -17150,7 +17145,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
17150
17145
|
display: flex;
|
17151
17146
|
flex-direction: column-reverse;
|
17152
17147
|
background-color: transparent;
|
17153
|
-
gap:
|
17148
|
+
gap: 6px;
|
17154
17149
|
cursor: pointer;
|
17155
17150
|
container-type: inline-size;
|
17156
17151
|
position: relative;
|
@@ -17175,7 +17170,7 @@ const STYLES$4 = ({ textColor = '#212121', backgroundColor = '#e8e6de', ctaTextC
|
|
17175
17170
|
align-items: center;
|
17176
17171
|
width: 100%;
|
17177
17172
|
height: 100%;
|
17178
|
-
gap:
|
17173
|
+
gap: 10px;
|
17179
17174
|
padding: 0 10px;
|
17180
17175
|
box-sizing: border-box;
|
17181
17176
|
}
|
@@ -17785,6 +17780,7 @@ class EventService {
|
|
17785
17780
|
constructor() {
|
17786
17781
|
this.pubSub = new PubSub();
|
17787
17782
|
this.activeSpots = new Map();
|
17783
|
+
this.spotStates = new Map();
|
17788
17784
|
this.intersectionObserver = new IntersectionObserverService();
|
17789
17785
|
}
|
17790
17786
|
static getInstance() {
|
@@ -17793,6 +17789,46 @@ class EventService {
|
|
17793
17789
|
}
|
17794
17790
|
return EventService.instance;
|
17795
17791
|
}
|
17792
|
+
subscribe(eventType, callback) {
|
17793
|
+
return this.pubSub.subscribe(eventType, callback);
|
17794
|
+
}
|
17795
|
+
publish(eventType, data) {
|
17796
|
+
this.pubSub.publish(eventType, data);
|
17797
|
+
}
|
17798
|
+
handleSpotState(placementId, updates, publish = true) {
|
17799
|
+
let currentState = this.spotStates.get(placementId);
|
17800
|
+
if (!currentState) {
|
17801
|
+
currentState = {
|
17802
|
+
identifier: {
|
17803
|
+
placementId,
|
17804
|
+
spotId: '',
|
17805
|
+
spotType: '',
|
17806
|
+
},
|
17807
|
+
dom: {
|
17808
|
+
element: undefined,
|
17809
|
+
visible: false,
|
17810
|
+
},
|
17811
|
+
state: {
|
17812
|
+
mounted: false,
|
17813
|
+
unmounted: false,
|
17814
|
+
loading: false,
|
17815
|
+
error: undefined,
|
17816
|
+
},
|
17817
|
+
displayConfig: {
|
17818
|
+
isCarousel: false,
|
17819
|
+
isCarouselItem: false,
|
17820
|
+
isSingleItem: false,
|
17821
|
+
},
|
17822
|
+
};
|
17823
|
+
}
|
17824
|
+
this.spotStates.set(placementId, {
|
17825
|
+
...currentState,
|
17826
|
+
...updates,
|
17827
|
+
});
|
17828
|
+
if (publish) {
|
17829
|
+
this.pubSub.publish(RMN_SPOT_EVENT.LIFECYCLE_STATE, this.spotStates.get(placementId));
|
17830
|
+
}
|
17831
|
+
}
|
17796
17832
|
registerSpot({ placementId, element, spot }) {
|
17797
17833
|
this.activeSpots.set(spot.id, {
|
17798
17834
|
placementId,
|
@@ -17815,23 +17851,20 @@ class EventService {
|
|
17815
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 : '',
|
17816
17852
|
});
|
17817
17853
|
});
|
17818
|
-
// Publish spot created event
|
17819
|
-
this.pubSub.publish(RMN_SPOT_EVENT.MOUNTED, {
|
17820
|
-
placementId,
|
17821
|
-
spotId: spot.id,
|
17822
|
-
spotType: spot.spot,
|
17823
|
-
spotVariant: spot.variant,
|
17824
|
-
element,
|
17825
|
-
});
|
17826
17854
|
}
|
17827
17855
|
unregisterSpot(spotId) {
|
17828
17856
|
const spotData = this.activeSpots.get(spotId);
|
17829
17857
|
if (spotData) {
|
17830
17858
|
this.intersectionObserver.unobserve(spotData.element);
|
17831
|
-
|
17832
|
-
|
17833
|
-
|
17834
|
-
|
17859
|
+
this.handleSpotState(spotData.placementId, {
|
17860
|
+
dom: {
|
17861
|
+
element: undefined,
|
17862
|
+
visible: false,
|
17863
|
+
},
|
17864
|
+
state: {
|
17865
|
+
unmounted: true,
|
17866
|
+
mounted: false,
|
17867
|
+
},
|
17835
17868
|
});
|
17836
17869
|
this.activeSpots.delete(spotId);
|
17837
17870
|
}
|
@@ -17850,6 +17883,12 @@ class EventService {
|
|
17850
17883
|
element,
|
17851
17884
|
impressionTracked: true,
|
17852
17885
|
});
|
17886
|
+
this.handleSpotState(placementId, {
|
17887
|
+
dom: {
|
17888
|
+
element,
|
17889
|
+
visible: true,
|
17890
|
+
},
|
17891
|
+
});
|
17853
17892
|
// Fire impression event
|
17854
17893
|
await this.fireEvent({
|
17855
17894
|
event: RMN_SPOT_EVENT.IMPRESSION,
|
@@ -17858,12 +17897,6 @@ class EventService {
|
|
17858
17897
|
};
|
17859
17898
|
this.intersectionObserver.observe(element, spotIsVisibleCb);
|
17860
17899
|
}
|
17861
|
-
subscribe(eventType, callback) {
|
17862
|
-
return this.pubSub.subscribe(eventType, callback);
|
17863
|
-
}
|
17864
|
-
publish(eventType, data) {
|
17865
|
-
this.pubSub.publish(eventType, data);
|
17866
|
-
}
|
17867
17900
|
/**
|
17868
17901
|
* Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
|
17869
17902
|
*
|
@@ -17911,24 +17944,39 @@ class SelectionService extends BaseApi {
|
|
17911
17944
|
*
|
17912
17945
|
* @param {ISpotSelectionParams} data - Spots selection parameters.
|
17913
17946
|
*
|
17914
|
-
* @return {Promise<ISpots>} - The spots response object.
|
17947
|
+
* @return {Promise<ISpots | { error: string }>} - The spots response object.
|
17915
17948
|
*/
|
17916
17949
|
async spotSelection(data) {
|
17917
17950
|
const { isOk, val, isErr } = await this.post(SELECTION_API_PATH, data, {});
|
17918
17951
|
if (isErr) {
|
17919
|
-
|
17952
|
+
return { error: `There was an error during spot selection: (${isErr === null || isErr === void 0 ? void 0 : isErr.errorMessage})` };
|
17920
17953
|
}
|
17921
17954
|
if (isOk && val && val.data && (val === null || val === void 0 ? void 0 : val.refresh.token)) {
|
17922
17955
|
this.authInfo.authenticated = true;
|
17923
17956
|
this.authInfo.token = val.refresh.token;
|
17924
17957
|
return val.data.spots;
|
17925
17958
|
}
|
17926
|
-
|
17959
|
+
return { error: 'Spot selection response was not successful' };
|
17927
17960
|
}
|
17928
17961
|
}
|
17929
17962
|
|
17930
17963
|
class LiquidCommerceRmnClient {
|
17931
17964
|
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
|
+
};
|
17932
17980
|
this.selectionService = SelectionService.getInstance(auth);
|
17933
17981
|
this.elementService = ElementService.getInstance();
|
17934
17982
|
this.eventService = EventService.getInstance();
|
@@ -17940,7 +17988,7 @@ class LiquidCommerceRmnClient {
|
|
17940
17988
|
*
|
17941
17989
|
* @param {ISpotSelectionParams} params - Spots selection parameters.
|
17942
17990
|
*
|
17943
|
-
* @return {Promise<ISpots>} - The spots response object.
|
17991
|
+
* @return {Promise<ISpots | {error : string}>} - The spots response object.
|
17944
17992
|
*/
|
17945
17993
|
async spotSelection(params) {
|
17946
17994
|
return this.selectionService.spotSelection(params);
|
@@ -17954,60 +18002,94 @@ class LiquidCommerceRmnClient {
|
|
17954
18002
|
*/
|
17955
18003
|
async injectSpotElement(params) {
|
17956
18004
|
var _a;
|
17957
|
-
const
|
18005
|
+
const config = params.config;
|
18006
|
+
let inject = params.inject;
|
17958
18007
|
if (!inject.length) {
|
17959
|
-
|
18008
|
+
this.eventService.handleSpotState('all', {
|
18009
|
+
state: {
|
18010
|
+
error: 'No spot elements provided for injection.',
|
18011
|
+
loading: false,
|
18012
|
+
},
|
18013
|
+
});
|
18014
|
+
return;
|
18015
|
+
}
|
18016
|
+
// Update the state of the spots to loading
|
18017
|
+
this.updateSpotsState(inject);
|
18018
|
+
// Prevent duplicate placement ids
|
18019
|
+
const hasDuplicatePlacementIds = this.preventDuplicateSpotPlacementIds(inject);
|
18020
|
+
if (!hasDuplicatePlacementIds) {
|
18021
|
+
return;
|
18022
|
+
}
|
18023
|
+
// Prevent non-existent spot types
|
18024
|
+
inject = this.preventNonExistentSpotTypes(inject);
|
18025
|
+
// Make the spot selection request
|
18026
|
+
const response = await this.spotSelectionRequest({ ...params, inject });
|
18027
|
+
// Handle the response
|
18028
|
+
if (typeof response === 'object' && 'error' in response) {
|
18029
|
+
this.eventService.handleSpotState('all', {
|
18030
|
+
state: {
|
18031
|
+
error: response.error,
|
18032
|
+
},
|
18033
|
+
});
|
17960
18034
|
return;
|
17961
18035
|
}
|
17962
|
-
this.preventDuplicateSpotPlacementIds(inject);
|
17963
|
-
const response = await this.spotSelectionRequest(params);
|
17964
18036
|
for (const item of inject) {
|
17965
18037
|
const itemConfig = (_a = item.config) !== null && _a !== void 0 ? _a : config;
|
17966
18038
|
const spots = response[item.placementId];
|
17967
18039
|
if (!(spots === null || spots === void 0 ? void 0 : spots.length)) {
|
17968
|
-
|
18040
|
+
this.eventService.handleSpotState(item.placementId, {
|
18041
|
+
state: {
|
18042
|
+
error: `No spots found for type "${item.spotType}".`,
|
18043
|
+
loading: false,
|
18044
|
+
},
|
18045
|
+
});
|
17969
18046
|
continue;
|
17970
18047
|
}
|
17971
18048
|
const placementId = item.placementId.replace('#', '');
|
17972
18049
|
const placement = document.getElementById(placementId);
|
17973
18050
|
if (!placement) {
|
17974
|
-
|
18051
|
+
this.eventService.handleSpotState(item.placementId, {
|
18052
|
+
state: {
|
18053
|
+
error: `Placement not found for id "${placementId}".`,
|
18054
|
+
loading: false,
|
18055
|
+
},
|
18056
|
+
});
|
17975
18057
|
continue;
|
17976
18058
|
}
|
17977
18059
|
if (spots.length === 1) {
|
17978
|
-
this.injectOneSpotElement(item, placement, spots[0], itemConfig);
|
18060
|
+
const isInjected = this.injectOneSpotElement(item, placement, spots[0], itemConfig);
|
18061
|
+
if (!isInjected) {
|
18062
|
+
continue;
|
18063
|
+
}
|
17979
18064
|
}
|
17980
18065
|
if (spots.length > 1) {
|
17981
|
-
this.injectCarouselSpotElement(placement, spots, itemConfig);
|
18066
|
+
const isInjected = this.injectCarouselSpotElement(placement, spots, itemConfig);
|
18067
|
+
if (!isInjected) {
|
18068
|
+
continue;
|
18069
|
+
}
|
17982
18070
|
}
|
17983
18071
|
}
|
17984
18072
|
}
|
17985
|
-
/**
|
17986
|
-
* Returns the event manager instance.
|
17987
|
-
*
|
17988
|
-
* @return {EventService} - The event manager instance.
|
17989
|
-
*/
|
17990
|
-
eventManager() {
|
17991
|
-
return this.eventService;
|
17992
|
-
}
|
17993
18073
|
/**
|
17994
18074
|
* Makes a selection request on our server based on the provided data.
|
17995
18075
|
*
|
17996
18076
|
* @param {IInjectSpotElementParams} params - Parameters for injecting spot elements.
|
17997
18077
|
*
|
17998
|
-
* @return {Promise<ISpots>} - The spots response object.
|
18078
|
+
* @return {Promise<ISpots | {error: string}>} - The spots response object.
|
17999
18079
|
*/
|
18000
18080
|
async spotSelectionRequest(params) {
|
18001
18081
|
const { inject, filter, config } = params;
|
18002
18082
|
const request = {
|
18003
18083
|
url: config === null || config === void 0 ? void 0 : config.url,
|
18004
18084
|
filter,
|
18005
|
-
spots: inject.map((item) =>
|
18006
|
-
|
18007
|
-
|
18008
|
-
|
18009
|
-
|
18010
|
-
|
18085
|
+
spots: inject.map((item) => {
|
18086
|
+
return {
|
18087
|
+
placementId: item.placementId,
|
18088
|
+
spot: item.spotType,
|
18089
|
+
count: item === null || item === void 0 ? void 0 : item.count,
|
18090
|
+
...item === null || item === void 0 ? void 0 : item.filter,
|
18091
|
+
};
|
18092
|
+
}),
|
18011
18093
|
};
|
18012
18094
|
return this.spotSelection(request);
|
18013
18095
|
}
|
@@ -18024,23 +18106,39 @@ class LiquidCommerceRmnClient {
|
|
18024
18106
|
var _a;
|
18025
18107
|
const carouselSlides = [];
|
18026
18108
|
for (const spotItem of spots) {
|
18109
|
+
this.eventService.handleSpotState(placement.id, {
|
18110
|
+
displayConfig: {
|
18111
|
+
isCarousel: true,
|
18112
|
+
isCarouselItem: true,
|
18113
|
+
isSingleItem: false,
|
18114
|
+
},
|
18115
|
+
}, false);
|
18027
18116
|
const spot = this.elementService.overrideSpotColors(spotItem, config === null || config === void 0 ? void 0 : config.colors);
|
18028
18117
|
const content = SPOT_TEMPLATE_HTML_ELEMENT(spot, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
18029
18118
|
if (!content) {
|
18030
|
-
|
18031
|
-
|
18119
|
+
this.eventService.handleSpotState(placement.id, {
|
18120
|
+
state: {
|
18121
|
+
error: `Failed to inject carousel spot item element. Could not create element for type "${spot.spot}".`,
|
18122
|
+
loading: false,
|
18123
|
+
},
|
18124
|
+
});
|
18125
|
+
continue;
|
18032
18126
|
}
|
18033
|
-
this.
|
18127
|
+
this.eventService.registerSpot({
|
18034
18128
|
spot,
|
18035
18129
|
placementId: placement.id,
|
18036
18130
|
element: content,
|
18037
18131
|
});
|
18038
18132
|
carouselSlides.push(content);
|
18039
18133
|
}
|
18040
|
-
|
18041
|
-
|
18042
|
-
|
18043
|
-
|
18134
|
+
// Get the max width and height of the spots
|
18135
|
+
const { maxWidth, maxHeight } = spots.reduce((max, spot) => {
|
18136
|
+
return {
|
18137
|
+
maxWidth: Math.max(max.maxWidth, spot.width),
|
18138
|
+
maxHeight: Math.max(max.maxHeight, spot.height),
|
18139
|
+
};
|
18140
|
+
}, { maxWidth: 0, maxHeight: 0 });
|
18141
|
+
// Create the carousel element
|
18044
18142
|
const carouselElement = this.elementService.createCarouselElement({
|
18045
18143
|
slides: carouselSlides,
|
18046
18144
|
config: {
|
@@ -18052,10 +18150,25 @@ class LiquidCommerceRmnClient {
|
|
18052
18150
|
},
|
18053
18151
|
});
|
18054
18152
|
if (!carouselElement) {
|
18055
|
-
|
18056
|
-
|
18153
|
+
this.eventService.handleSpotState(placement.id, {
|
18154
|
+
state: {
|
18155
|
+
error: `Failed to inject spot carousel element. Could not create spot carousel element.`,
|
18156
|
+
loading: false,
|
18157
|
+
},
|
18158
|
+
});
|
18159
|
+
return false;
|
18057
18160
|
}
|
18058
18161
|
placement.replaceChildren(carouselElement);
|
18162
|
+
this.eventService.handleSpotState(placement.id, {
|
18163
|
+
dom: {
|
18164
|
+
element: carouselElement,
|
18165
|
+
},
|
18166
|
+
state: {
|
18167
|
+
mounted: true,
|
18168
|
+
loading: false,
|
18169
|
+
},
|
18170
|
+
});
|
18171
|
+
return true;
|
18059
18172
|
}
|
18060
18173
|
/**
|
18061
18174
|
* Injects a single spot element into the provided placement.
|
@@ -18070,11 +18183,23 @@ class LiquidCommerceRmnClient {
|
|
18070
18183
|
injectOneSpotElement(injectItem, placement, spot, config) {
|
18071
18184
|
var _a;
|
18072
18185
|
const spotData = this.elementService.overrideSpotColors(spot, config === null || config === void 0 ? void 0 : config.colors);
|
18186
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
18187
|
+
displayConfig: {
|
18188
|
+
isSingleItem: true,
|
18189
|
+
},
|
18190
|
+
}, false);
|
18191
|
+
// Create the spot template element
|
18073
18192
|
const content = SPOT_TEMPLATE_HTML_ELEMENT(spotData, { overlay: config === null || config === void 0 ? void 0 : config.overlay });
|
18074
18193
|
if (!content) {
|
18075
|
-
|
18076
|
-
|
18194
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
18195
|
+
state: {
|
18196
|
+
error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
|
18197
|
+
loading: false,
|
18198
|
+
},
|
18199
|
+
});
|
18200
|
+
return false;
|
18077
18201
|
}
|
18202
|
+
// Create the spot element
|
18078
18203
|
const spotElement = this.elementService.createSpotElement({
|
18079
18204
|
content,
|
18080
18205
|
config: {
|
@@ -18086,22 +18211,30 @@ class LiquidCommerceRmnClient {
|
|
18086
18211
|
},
|
18087
18212
|
});
|
18088
18213
|
if (!spotElement) {
|
18089
|
-
|
18090
|
-
|
18214
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
18215
|
+
state: {
|
18216
|
+
error: `Failed to inject spot element. Could not create element for type "${injectItem.spotType}".`,
|
18217
|
+
loading: false,
|
18218
|
+
},
|
18219
|
+
});
|
18220
|
+
return false;
|
18091
18221
|
}
|
18092
|
-
this.
|
18093
|
-
spot,
|
18222
|
+
this.eventService.registerSpot({
|
18223
|
+
spot: spotData,
|
18094
18224
|
placementId: injectItem.placementId,
|
18095
18225
|
element: spotElement,
|
18096
18226
|
});
|
18097
18227
|
placement.replaceChildren(spotElement);
|
18098
|
-
|
18099
|
-
|
18100
|
-
|
18101
|
-
|
18102
|
-
|
18103
|
-
|
18228
|
+
this.eventService.handleSpotState(injectItem.placementId, {
|
18229
|
+
dom: {
|
18230
|
+
element: spotElement,
|
18231
|
+
},
|
18232
|
+
state: {
|
18233
|
+
mounted: true,
|
18234
|
+
loading: false,
|
18235
|
+
},
|
18104
18236
|
});
|
18237
|
+
return true;
|
18105
18238
|
}
|
18106
18239
|
/**
|
18107
18240
|
* Prevents duplicate placement ids in the inject data.
|
@@ -18116,10 +18249,44 @@ class LiquidCommerceRmnClient {
|
|
18116
18249
|
const placementIds = new Set();
|
18117
18250
|
for (const item of inject) {
|
18118
18251
|
if (placementIds.has(item.placementId)) {
|
18119
|
-
|
18252
|
+
this.eventService.handleSpotState(item.placementId, {
|
18253
|
+
state: {
|
18254
|
+
error: `Duplicate placement id (${item.placementId}) found. Please provide a unique placement id for each spot element.`,
|
18255
|
+
},
|
18256
|
+
});
|
18257
|
+
return false;
|
18120
18258
|
}
|
18121
18259
|
placementIds.add(item.placementId);
|
18122
18260
|
}
|
18261
|
+
return true;
|
18262
|
+
}
|
18263
|
+
preventNonExistentSpotTypes(inject) {
|
18264
|
+
const newInject = [];
|
18265
|
+
for (const item of inject) {
|
18266
|
+
if (!Object.values(RMN_SPOT_TYPE).includes(item.spotType)) {
|
18267
|
+
this.eventService.handleSpotState(item.placementId, {
|
18268
|
+
state: {
|
18269
|
+
error: `Invalid spot type (${item.spotType}) found. Please provide a valid spot type for each spot element.`,
|
18270
|
+
},
|
18271
|
+
});
|
18272
|
+
continue;
|
18273
|
+
}
|
18274
|
+
newInject.push(item);
|
18275
|
+
}
|
18276
|
+
return newInject;
|
18277
|
+
}
|
18278
|
+
updateSpotsState(inject) {
|
18279
|
+
for (const item of inject) {
|
18280
|
+
this.eventService.handleSpotState(item.placementId, {
|
18281
|
+
identifier: {
|
18282
|
+
placementId: item.placementId,
|
18283
|
+
spotType: item.spotType,
|
18284
|
+
},
|
18285
|
+
state: {
|
18286
|
+
loading: true,
|
18287
|
+
},
|
18288
|
+
});
|
18289
|
+
}
|
18123
18290
|
}
|
18124
18291
|
}
|
18125
18292
|
/**
|
package/dist/types/enums.d.ts
CHANGED
@@ -49,8 +49,7 @@ export declare enum RMN_FILTER_PROPERTIES {
|
|
49
49
|
SECTION = "section"
|
50
50
|
}
|
51
51
|
export declare enum RMN_SPOT_EVENT {
|
52
|
-
|
53
|
-
UNMOUNTED = "UNMOUNTED",
|
52
|
+
LIFECYCLE_STATE = "LIFECYCLE_STATE",
|
54
53
|
IMPRESSION = "IMPRESSION",
|
55
54
|
CLICK = "CLICK",
|
56
55
|
PURCHASE = "PURCHASE",
|
@@ -4,16 +4,31 @@ export interface IFireEventParams {
|
|
4
4
|
event: RMN_SPOT_EVENT;
|
5
5
|
eventUrl: string;
|
6
6
|
}
|
7
|
-
export interface
|
7
|
+
export interface ILSIdentifier {
|
8
8
|
placementId: string;
|
9
9
|
spotId: string;
|
10
10
|
spotType: string;
|
11
|
-
spotVariant: string;
|
12
|
-
element: HTMLElement;
|
13
11
|
}
|
14
|
-
export interface
|
15
|
-
|
16
|
-
|
12
|
+
export interface ILSDom {
|
13
|
+
visible: boolean;
|
14
|
+
element?: HTMLElement;
|
15
|
+
}
|
16
|
+
export interface ILSState {
|
17
|
+
mounted: boolean;
|
18
|
+
unmounted: boolean;
|
19
|
+
loading: boolean;
|
20
|
+
error?: string;
|
21
|
+
}
|
22
|
+
export interface ILSDisplayConfig {
|
23
|
+
isCarousel: boolean;
|
24
|
+
isCarouselItem: boolean;
|
25
|
+
isSingleItem: boolean;
|
26
|
+
}
|
27
|
+
export interface ILifecycleState {
|
28
|
+
identifier: Partial<ILSIdentifier>;
|
29
|
+
dom?: Partial<ILSDom>;
|
30
|
+
state?: Partial<ILSState>;
|
31
|
+
displayConfig?: Partial<ILSDisplayConfig>;
|
17
32
|
}
|
18
33
|
export interface IClickEvent {
|
19
34
|
placementId: string;
|
@@ -42,8 +57,7 @@ export interface IBuyNowEvent {
|
|
42
57
|
spotId: string;
|
43
58
|
}
|
44
59
|
export interface IEventMap {
|
45
|
-
[RMN_SPOT_EVENT.
|
46
|
-
[RMN_SPOT_EVENT.UNMOUNTED]: IUnMountedEvent;
|
60
|
+
[RMN_SPOT_EVENT.LIFECYCLE_STATE]: ILifecycleState;
|
47
61
|
[RMN_SPOT_EVENT.CLICK]: IClickEvent;
|
48
62
|
[RMN_SPOT_EVENT.IMPRESSION]: IImpressionEvent;
|
49
63
|
[RMN_SPOT_EVENT.ADD_TO_CART]: IAddToCartEvent;
|
@@ -1,16 +1,19 @@
|
|
1
|
-
import
|
1
|
+
import { RMN_SPOT_EVENT } from 'enums';
|
2
|
+
import type { IEventMap, ILifecycleState, IRegisterSpotParams } from './event.interface';
|
2
3
|
export declare class EventService {
|
3
4
|
private static instance;
|
4
5
|
private pubSub;
|
5
6
|
private intersectionObserver;
|
7
|
+
private spotStates;
|
6
8
|
private activeSpots;
|
7
9
|
private constructor();
|
8
10
|
static getInstance(): EventService;
|
11
|
+
subscribe(eventType: RMN_SPOT_EVENT, callback: (data: IEventMap[RMN_SPOT_EVENT]) => void): () => void;
|
12
|
+
publish(eventType: RMN_SPOT_EVENT, data: IEventMap[RMN_SPOT_EVENT]): void;
|
13
|
+
handleSpotState(placementId: string, updates: Partial<ILifecycleState>, publish?: boolean): void;
|
9
14
|
registerSpot({ placementId, element, spot }: IRegisterSpotParams): void;
|
10
15
|
unregisterSpot(spotId: string): void;
|
11
16
|
private handleIntersectionObserver;
|
12
|
-
subscribe<K extends keyof IEventMap>(eventType: K, callback: (data: IEventMap[K]) => void): () => void;
|
13
|
-
publish<K extends keyof IEventMap>(eventType: K, data: IEventMap[K]): void;
|
14
17
|
/**
|
15
18
|
* Fires an event using the navigator.sendBeacon method and redirects the user if the event is a click event.
|
16
19
|
*
|
@@ -33,5 +33,7 @@ export interface ISpot {
|
|
33
33
|
}
|
34
34
|
export type ISpots = Record<PlacementIdType, ISpot[]>;
|
35
35
|
export interface ISelectionService {
|
36
|
-
spotSelection(data: ISpotSelectionParams): Promise<ISpots
|
36
|
+
spotSelection(data: ISpotSelectionParams): Promise<ISpots | {
|
37
|
+
error: string;
|
38
|
+
}>;
|
37
39
|
}
|
@@ -10,7 +10,9 @@ export declare class SelectionService extends BaseApi implements ISelectionServi
|
|
10
10
|
*
|
11
11
|
* @param {ISpotSelectionParams} data - Spots selection parameters.
|
12
12
|
*
|
13
|
-
* @return {Promise<ISpots>} - The spots response object.
|
13
|
+
* @return {Promise<ISpots | { error: string }>} - The spots response object.
|
14
14
|
*/
|
15
|
-
spotSelection(data: ISpotSelectionParams): Promise<ISpots
|
15
|
+
spotSelection(data: ISpotSelectionParams): Promise<ISpots | {
|
16
|
+
error: string;
|
17
|
+
}>;
|
16
18
|
}
|