ublo-lib 1.31.29 → 1.31.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/common/hooks/use-tunnel.js +2 -6
- package/es/future/components/msem/index.js +3 -0
- package/es/future/components/msem/script.js +14 -0
- package/es/future/components/msem/tunnel.js +21 -0
- package/es/future/components/msem/types.js +1 -0
- package/es/future/components/msem/utils.js +15 -0
- package/es/future/components/plausible/hooks/use-plausible.js +29 -0
- package/es/future/components/plausible/index.js +7 -0
- package/es/future/components/plausible/plausible.js +26 -0
- package/es/future/components/plausible/services/callback.js +201 -0
- package/es/future/components/plausible/services/load.js +5 -0
- package/es/future/components/plausible/services/send-goal.js +8 -0
- package/package.json +1 -1
|
@@ -24,7 +24,6 @@ export default function useTunnel({
|
|
|
24
24
|
lang,
|
|
25
25
|
breadcrumb
|
|
26
26
|
} = useUbloContext();
|
|
27
|
-
const [started, setStared] = React.useState(false);
|
|
28
27
|
const {
|
|
29
28
|
path: esfPath
|
|
30
29
|
} = multipleVillages ? breadcrumb?.next : breadcrumb;
|
|
@@ -33,7 +32,6 @@ export default function useTunnel({
|
|
|
33
32
|
React.useEffect(() => {
|
|
34
33
|
if (enableCustomOffers && cmsMode !== "editing" || !enableCustomOffers) {
|
|
35
34
|
const startTunnel = async () => {
|
|
36
|
-
setStared(true);
|
|
37
35
|
await loadWidgetMseM(integration);
|
|
38
36
|
const categoryCode = window.sessionStorage.getItem("categoryCode") || undefined;
|
|
39
37
|
window.MseM?.onLoad(() => {
|
|
@@ -51,11 +49,9 @@ export default function useTunnel({
|
|
|
51
49
|
});
|
|
52
50
|
});
|
|
53
51
|
};
|
|
54
|
-
|
|
55
|
-
startTunnel();
|
|
56
|
-
}
|
|
52
|
+
startTunnel();
|
|
57
53
|
}
|
|
58
|
-
}, [channel, cmsMode, customOffers, enableCustomOffers, esfUrl, groundedTo, integration,
|
|
54
|
+
}, [channel, cmsMode, customOffers, enableCustomOffers, esfUrl, groundedTo, integration, widgetLang]);
|
|
59
55
|
}
|
|
60
56
|
async function loadWidgetMseM(integration) {
|
|
61
57
|
const source = integration ? "https://widget-integration.msem.tech/static/js/widget-msem.js" : "https://widget.msem.tech/static/js/widget-msem.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import NextScript from "next/script";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
export function Script({
|
|
4
|
+
msemUrl
|
|
5
|
+
}) {
|
|
6
|
+
const setLoaded = () => {
|
|
7
|
+
window.MseMLoaded = true;
|
|
8
|
+
};
|
|
9
|
+
return _jsx(NextScript, {
|
|
10
|
+
src: `${msemUrl}/static/js/widget-msem.js`,
|
|
11
|
+
onLoad: setLoaded,
|
|
12
|
+
defer: true
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as Utils from "./utils";
|
|
3
|
+
import * as Plausible from "../plausible";
|
|
4
|
+
export default React.memo(Tunnel);
|
|
5
|
+
function Tunnel({
|
|
6
|
+
options,
|
|
7
|
+
presets,
|
|
8
|
+
children
|
|
9
|
+
}) {
|
|
10
|
+
const patchedOptions = React.useMemo(() => ({
|
|
11
|
+
...options,
|
|
12
|
+
analytics: (...args) => {
|
|
13
|
+
options?.analytics?.apply(null, args);
|
|
14
|
+
Plausible.callback.apply(null, args);
|
|
15
|
+
}
|
|
16
|
+
}), [options]);
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
Utils.loadWidget("tunnel", patchedOptions, presets);
|
|
19
|
+
}, [patchedOptions, presets]);
|
|
20
|
+
return children;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function loadWidget(widget, options = {}, presets = {}) {
|
|
2
|
+
if (window.MseMLoaded) {
|
|
3
|
+
window.MseM?.onLoad(() => window.requestAnimationFrame(() => window.MseM[widget](options, presets)));
|
|
4
|
+
} else {
|
|
5
|
+
setTimeout(() => {
|
|
6
|
+
const isGroundedTo = ("groundedTo" in options);
|
|
7
|
+
if (isGroundedTo) {
|
|
8
|
+
const selector = options.groundedTo;
|
|
9
|
+
const widgetStillHasTarget = document.querySelector(selector);
|
|
10
|
+
if (!widgetStillHasTarget) return;
|
|
11
|
+
}
|
|
12
|
+
loadWidget(widget, options, presets);
|
|
13
|
+
}, 200);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import getConfig from "next/config";
|
|
3
|
+
import load from "../services/load";
|
|
4
|
+
import sendGoal from "../services/send-goal";
|
|
5
|
+
const {
|
|
6
|
+
publicRuntimeConfig
|
|
7
|
+
} = getConfig();
|
|
8
|
+
const {
|
|
9
|
+
plausibleDomain
|
|
10
|
+
} = publicRuntimeConfig;
|
|
11
|
+
export default function useGoal(goal, props, revenue, overridenDomain) {
|
|
12
|
+
const [loaded] = usePlausible(overridenDomain);
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
if (!loaded || !window.plausible) return;
|
|
15
|
+
const defaultProps = {
|
|
16
|
+
path: document.location.pathname
|
|
17
|
+
};
|
|
18
|
+
sendGoal(goal, props || defaultProps, revenue);
|
|
19
|
+
}, [goal, loaded, props]);
|
|
20
|
+
}
|
|
21
|
+
function usePlausible(overridenDomain) {
|
|
22
|
+
const [loaded, setLoaded] = React.useState(false);
|
|
23
|
+
React.useEffect(() => {
|
|
24
|
+
if (!overridenDomain && !plausibleDomain) return;
|
|
25
|
+
load();
|
|
26
|
+
setLoaded(true);
|
|
27
|
+
}, [overridenDomain]);
|
|
28
|
+
return [loaded, setLoaded];
|
|
29
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import Script from "./plausible";
|
|
2
|
+
import * as Callback from "./services/callback";
|
|
3
|
+
const callback = Callback.MseM;
|
|
4
|
+
export { default as load } from "./services/load";
|
|
5
|
+
export { default as sendGoal } from "./services/send-goal";
|
|
6
|
+
export { default as useGoal } from "./hooks/use-plausible";
|
|
7
|
+
export { callback, Script };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import Script from "next/script";
|
|
3
|
+
import getConfig from "next/config";
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
const {
|
|
6
|
+
publicRuntimeConfig
|
|
7
|
+
} = getConfig();
|
|
8
|
+
const {
|
|
9
|
+
plausibleDomain
|
|
10
|
+
} = publicRuntimeConfig;
|
|
11
|
+
const DEFAULT_SOURCE = "https://plausible.io/js/script.revenue.file-downloads.outbound-links.js";
|
|
12
|
+
export default function PlausibleScript({
|
|
13
|
+
lang,
|
|
14
|
+
source = DEFAULT_SOURCE
|
|
15
|
+
}) {
|
|
16
|
+
const hasI18n = typeof plausibleDomain === "object";
|
|
17
|
+
if (hasI18n && !lang) {
|
|
18
|
+
console.warn("PlausibleScript: the lang props is mandatory if you want to use a specific domain for each lang");
|
|
19
|
+
}
|
|
20
|
+
const domain = hasI18n && lang ? plausibleDomain[lang] : plausibleDomain;
|
|
21
|
+
if (!domain) return null;
|
|
22
|
+
return _jsx(Script, {
|
|
23
|
+
"data-domain": domain,
|
|
24
|
+
src: source
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import sendGoal from "./send-goal";
|
|
2
|
+
const EVENT_NAMES = {
|
|
3
|
+
view_item: "MseM: View item",
|
|
4
|
+
add_to_cart: "MseM: Add to cart",
|
|
5
|
+
remove_from_cart: "MseM: Remove from cart",
|
|
6
|
+
checkout: "MseM: Begin checkout",
|
|
7
|
+
add_payment_info: "MseM: Checkout process",
|
|
8
|
+
purchase: "MseM: Payment success",
|
|
9
|
+
payment_failure: "MseM: Payment failure"
|
|
10
|
+
};
|
|
11
|
+
export function MseM({
|
|
12
|
+
event,
|
|
13
|
+
payment_type: paymentType,
|
|
14
|
+
execcode,
|
|
15
|
+
items = [],
|
|
16
|
+
orderId,
|
|
17
|
+
cartId,
|
|
18
|
+
currency = "EUR"
|
|
19
|
+
}) {
|
|
20
|
+
const hoteId = getBusinessProvider();
|
|
21
|
+
const stay = getStay();
|
|
22
|
+
const amount = items.reduce((acc, item) => {
|
|
23
|
+
return acc + item.gtmData.price * item.gtmData.quantity;
|
|
24
|
+
}, 0);
|
|
25
|
+
const revenue = {
|
|
26
|
+
currency,
|
|
27
|
+
amount
|
|
28
|
+
};
|
|
29
|
+
let name = EVENT_NAMES[event];
|
|
30
|
+
const firstProductProps = {
|
|
31
|
+
Name: items[0]?.gtmData.item_name,
|
|
32
|
+
Brand: items[0]?.gtmData.item_brand,
|
|
33
|
+
Kind: items[0]?.gtmData.item_category,
|
|
34
|
+
Activity: items[0]?.gtmData.item_category2,
|
|
35
|
+
Code: items[0]?.gtmData.item_category3,
|
|
36
|
+
Product: items[0]?.gtmData.item_variant
|
|
37
|
+
};
|
|
38
|
+
switch (event) {
|
|
39
|
+
case "view_item":
|
|
40
|
+
{
|
|
41
|
+
const formatedItems = formatPeekPerformancesItem(items);
|
|
42
|
+
const rawData = JSON.stringify({
|
|
43
|
+
products: formatedItems,
|
|
44
|
+
hoteId,
|
|
45
|
+
stay
|
|
46
|
+
});
|
|
47
|
+
sendGoal(name, {
|
|
48
|
+
...firstProductProps,
|
|
49
|
+
stayFrom: stay?.from,
|
|
50
|
+
rawData
|
|
51
|
+
});
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case "add_to_cart":
|
|
55
|
+
{
|
|
56
|
+
const formatedItems = formatPeekPerformancesItem(items);
|
|
57
|
+
const rawData = JSON.stringify({
|
|
58
|
+
products: formatedItems,
|
|
59
|
+
hoteId,
|
|
60
|
+
stay
|
|
61
|
+
});
|
|
62
|
+
sendGoal(name, {
|
|
63
|
+
...firstProductProps,
|
|
64
|
+
stayFrom: stay?.from,
|
|
65
|
+
rawData
|
|
66
|
+
}, revenue);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case "remove_from_cart":
|
|
70
|
+
{
|
|
71
|
+
const formatedItems = formatPeekPerformancesItem(items);
|
|
72
|
+
const rawData = JSON.stringify({
|
|
73
|
+
products: formatedItems,
|
|
74
|
+
hoteId,
|
|
75
|
+
stay
|
|
76
|
+
});
|
|
77
|
+
sendGoal(name, {
|
|
78
|
+
...firstProductProps,
|
|
79
|
+
stayFrom: stay?.from,
|
|
80
|
+
rawData
|
|
81
|
+
}, revenue);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "checkout":
|
|
85
|
+
{
|
|
86
|
+
const formatedItems = formatPeekPerformancesItem(items);
|
|
87
|
+
const rawData = JSON.stringify({
|
|
88
|
+
products: formatedItems,
|
|
89
|
+
hoteId,
|
|
90
|
+
stay
|
|
91
|
+
});
|
|
92
|
+
sendGoal(name, {
|
|
93
|
+
cartId,
|
|
94
|
+
stayFrom: stay?.from,
|
|
95
|
+
rawData
|
|
96
|
+
}, revenue);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case "add_payment_info":
|
|
100
|
+
{
|
|
101
|
+
const formatedItems = formatPeekPerformancesItem(items);
|
|
102
|
+
const rawData = JSON.stringify({
|
|
103
|
+
products: formatedItems,
|
|
104
|
+
hoteId,
|
|
105
|
+
stay,
|
|
106
|
+
paymentMethod: paymentType
|
|
107
|
+
});
|
|
108
|
+
sendGoal(name, {
|
|
109
|
+
cartId,
|
|
110
|
+
"Payment type": paymentType,
|
|
111
|
+
stayFrom: stay?.from,
|
|
112
|
+
rawData
|
|
113
|
+
}, revenue);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "purchase":
|
|
117
|
+
{
|
|
118
|
+
const isFailure = execcode !== "0000";
|
|
119
|
+
const formatedItems = formatPeekPerformancesItem(items);
|
|
120
|
+
const attempts = cartId && getPurchaseAttempts()[cartId] || 0;
|
|
121
|
+
const rawData = JSON.stringify({
|
|
122
|
+
products: formatedItems,
|
|
123
|
+
hoteId,
|
|
124
|
+
stay,
|
|
125
|
+
attempts,
|
|
126
|
+
paymentMethod: paymentType,
|
|
127
|
+
execCode: execcode
|
|
128
|
+
});
|
|
129
|
+
if (isFailure) {
|
|
130
|
+
name = EVENT_NAMES.payment_failure;
|
|
131
|
+
sendGoal(name, {
|
|
132
|
+
cartId,
|
|
133
|
+
orderId,
|
|
134
|
+
Code: execcode,
|
|
135
|
+
stayFrom: stay?.from,
|
|
136
|
+
rawData
|
|
137
|
+
}, revenue);
|
|
138
|
+
if (cartId) {
|
|
139
|
+
setPurchaseAttempts(cartId, attempts + 1);
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
sendGoal(name, {
|
|
143
|
+
cartId,
|
|
144
|
+
orderId,
|
|
145
|
+
Code: execcode,
|
|
146
|
+
stayFrom: stay?.from,
|
|
147
|
+
rawData
|
|
148
|
+
}, revenue);
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const PURCHASE_ATTEMPTS_STORAGE_KEY = "purchase_attempts";
|
|
155
|
+
function getPurchaseAttempts() {
|
|
156
|
+
try {
|
|
157
|
+
const storedAttempts = window.localStorage.getItem(PURCHASE_ATTEMPTS_STORAGE_KEY);
|
|
158
|
+
return storedAttempts !== null ? JSON.parse(storedAttempts) : {};
|
|
159
|
+
} catch (e) {
|
|
160
|
+
return {};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function setPurchaseAttempts(cartId, attempts) {
|
|
164
|
+
const purchaseAttempts = getPurchaseAttempts();
|
|
165
|
+
window.localStorage.setItem(PURCHASE_ATTEMPTS_STORAGE_KEY, JSON.stringify({
|
|
166
|
+
...purchaseAttempts,
|
|
167
|
+
[cartId]: attempts
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
function formatPeekPerformancesItem(items) {
|
|
171
|
+
if (!items || !items.length) return;
|
|
172
|
+
return items.map(({
|
|
173
|
+
gtmData
|
|
174
|
+
}) => {
|
|
175
|
+
return {
|
|
176
|
+
category: gtmData.item_category,
|
|
177
|
+
subCategory: gtmData.item_category2,
|
|
178
|
+
merchant: gtmData.item_brand,
|
|
179
|
+
price: gtmData.price
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function getStay() {
|
|
184
|
+
const stay = window.sessionStorage.getItem("stay");
|
|
185
|
+
if (stay) {
|
|
186
|
+
return JSON.parse(stay);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function getBusinessProvider() {
|
|
190
|
+
const businessProvider = window.localStorage.getItem("businessProvider");
|
|
191
|
+
if (businessProvider) {
|
|
192
|
+
try {
|
|
193
|
+
const {
|
|
194
|
+
id
|
|
195
|
+
} = JSON.parse(businessProvider);
|
|
196
|
+
if (id !== -1) {
|
|
197
|
+
return id;
|
|
198
|
+
}
|
|
199
|
+
} catch (e) {}
|
|
200
|
+
}
|
|
201
|
+
}
|