ublo-lib 1.25.11 → 1.25.12
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/components/cross-selling-editor/cross-selling-editor.js +5 -2
- package/es/common/components/cross-selling-editor/editor.js +6 -3
- package/es/common/components/cross-selling-editor/hooks/use-custom-offers.js +5 -2
- package/es/common/components/cross-selling-editor/hooks/use-tunnel-offers.js +4 -2
- package/es/common/components/cross-selling-editor/override-trigger-form.js +12 -2
- package/es/common/components/cross-selling-editor/override.js +4 -2
- package/es/common/components/cross-selling-editor/overrides-list.js +4 -2
- package/es/common/components/cross-selling-editor/rules.js +4 -2
- package/es/common/components/cross-selling-editor/services/utils.js +24 -5
- package/es/common/components/cross-selling-editor/tester-tunnel-offer.js +23 -11
- package/es/common/components/cross-selling-editor/tester.js +14 -7
- package/package.json +1 -1
|
@@ -10,6 +10,8 @@ import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
export default function CrossSellingEditor({
|
|
11
11
|
titleZoneProps = {},
|
|
12
12
|
contentZoneProps = {},
|
|
13
|
+
durations,
|
|
14
|
+
className,
|
|
13
15
|
children
|
|
14
16
|
}) {
|
|
15
17
|
const ref = React.useRef();
|
|
@@ -28,10 +30,11 @@ export default function CrossSellingEditor({
|
|
|
28
30
|
}
|
|
29
31
|
};
|
|
30
32
|
return _jsxs("div", {
|
|
31
|
-
className: styles.editor,
|
|
33
|
+
className: classNames(styles.editor, className),
|
|
32
34
|
onClick: sendPlausibleEvent,
|
|
33
35
|
children: [children, cmsMode === "editing" && _jsx(Editor, {
|
|
34
|
-
zoneRef: ref
|
|
36
|
+
zoneRef: ref,
|
|
37
|
+
durations: durations
|
|
35
38
|
}), titleZoneProps.enabled && _jsx(Zone, {
|
|
36
39
|
ref: titleRef,
|
|
37
40
|
id: titleZoneProps.id || "tunnel-offers-title",
|
|
@@ -11,7 +11,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
11
11
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
13
|
export default function Editor({
|
|
14
|
-
zoneRef
|
|
14
|
+
zoneRef,
|
|
15
|
+
durations
|
|
15
16
|
}) {
|
|
16
17
|
const zoneContainer = zoneRef.current;
|
|
17
18
|
const [dialogOpened, setDialogOpened] = React.useState(false);
|
|
@@ -58,11 +59,13 @@ export default function Editor({
|
|
|
58
59
|
container: zoneContainer,
|
|
59
60
|
config: config,
|
|
60
61
|
setConfig: setConfig,
|
|
61
|
-
tunnelOffers: Utils.tunnelOffers
|
|
62
|
+
tunnelOffers: Utils.tunnelOffers,
|
|
63
|
+
durations: durations
|
|
62
64
|
}), _jsx(Tester, {
|
|
63
65
|
container: zoneContainer,
|
|
64
66
|
config: config,
|
|
65
|
-
tunnelOffers: Utils.tunnelOffers
|
|
67
|
+
tunnelOffers: Utils.tunnelOffers,
|
|
68
|
+
durations: durations
|
|
66
69
|
})]
|
|
67
70
|
})
|
|
68
71
|
})]
|
|
@@ -17,6 +17,7 @@ export default function useCustomOffers() {
|
|
|
17
17
|
let merchants = [];
|
|
18
18
|
let stay = {};
|
|
19
19
|
let skiPassDurations = [];
|
|
20
|
+
let durationTags = [];
|
|
20
21
|
if (cartId) {
|
|
21
22
|
try {
|
|
22
23
|
const {
|
|
@@ -25,14 +26,16 @@ export default function useCustomOffers() {
|
|
|
25
26
|
items = Utils.formatCartContent(cart);
|
|
26
27
|
merchants = Utils.getMerchantsFromCart(cart);
|
|
27
28
|
stay = Utils.getStayFromCart(cart);
|
|
28
|
-
skiPassDurations = await Utils.
|
|
29
|
+
skiPassDurations = await Utils.getSkiPassDurationFromCart(cart);
|
|
30
|
+
durationTags = await Utils.getDurationTagsFromCart(cart);
|
|
29
31
|
} catch (e) {}
|
|
30
32
|
}
|
|
31
33
|
const content = {
|
|
32
34
|
items,
|
|
33
35
|
merchants,
|
|
34
36
|
stay,
|
|
35
|
-
skiPassDurations
|
|
37
|
+
skiPassDurations,
|
|
38
|
+
durationTags
|
|
36
39
|
};
|
|
37
40
|
const storedConfig = Utils.getConfig(contentZone);
|
|
38
41
|
const sortedOffers = Utils.getSortedOffers(contentZone, content, storedConfig);
|
|
@@ -18,12 +18,14 @@ export default function useTunnelOffers(zone, path, cart) {
|
|
|
18
18
|
const items = Utils.formatCartContent(cart);
|
|
19
19
|
const merchants = Utils.getMerchantsFromCart(cart);
|
|
20
20
|
const stay = Utils.getStayFromCart(cart);
|
|
21
|
-
const skiPassDurations = await Utils.
|
|
21
|
+
const skiPassDurations = await Utils.getSkiPassDurationFromCart(cart);
|
|
22
|
+
const durationTags = await Utils.getDurationTagsFromCart(cart);
|
|
22
23
|
const content = {
|
|
23
24
|
items,
|
|
24
25
|
merchants,
|
|
25
26
|
stay,
|
|
26
|
-
skiPassDurations
|
|
27
|
+
skiPassDurations,
|
|
28
|
+
durationTags
|
|
27
29
|
};
|
|
28
30
|
const storedConfig = Utils.getConfig(container);
|
|
29
31
|
const sortedOffers = Utils.getSortedOffers(container, content, storedConfig);
|
|
@@ -11,7 +11,8 @@ import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
export default function OverrideTriggerForm({
|
|
12
12
|
currentOffer,
|
|
13
13
|
override,
|
|
14
|
-
setConfig
|
|
14
|
+
setConfig,
|
|
15
|
+
durations
|
|
15
16
|
}) {
|
|
16
17
|
const triggers = override?.triggers || {};
|
|
17
18
|
const {
|
|
@@ -20,7 +21,8 @@ export default function OverrideTriggerForm({
|
|
|
20
21
|
stayDuration = 0,
|
|
21
22
|
merchant,
|
|
22
23
|
skiPassDuration,
|
|
23
|
-
skiPassDurationOperator = ">"
|
|
24
|
+
skiPassDurationOperator = ">",
|
|
25
|
+
durationTag
|
|
24
26
|
} = triggers;
|
|
25
27
|
const updateEntry = (key, value) => {
|
|
26
28
|
setConfig((config = {}) => {
|
|
@@ -151,6 +153,14 @@ export default function OverrideTriggerForm({
|
|
|
151
153
|
value: skiPassDurationOperator || ">",
|
|
152
154
|
onValueChange: value => updateEntry("skiPassDurationOperator", value),
|
|
153
155
|
compact: true
|
|
156
|
+
}), durations && _jsx(Select, {
|
|
157
|
+
className: styles.input,
|
|
158
|
+
label: durations?.title,
|
|
159
|
+
placeholder: " ",
|
|
160
|
+
options: durations?.tags,
|
|
161
|
+
value: durationTag || "",
|
|
162
|
+
onValueChange: value => updateEntry("durationTag", value),
|
|
163
|
+
compact: true
|
|
154
164
|
})]
|
|
155
165
|
});
|
|
156
166
|
}
|
|
@@ -16,7 +16,8 @@ export default function Override({
|
|
|
16
16
|
setCurrentOverride,
|
|
17
17
|
config,
|
|
18
18
|
setConfig,
|
|
19
|
-
closeCreationForm
|
|
19
|
+
closeCreationForm,
|
|
20
|
+
durations
|
|
20
21
|
}) {
|
|
21
22
|
const [formOpen, setFormOpen] = React.useState(false);
|
|
22
23
|
const toggleFormOpen = e => {
|
|
@@ -108,7 +109,8 @@ export default function Override({
|
|
|
108
109
|
children: _jsx(OverrideTriggerForm, {
|
|
109
110
|
currentOffer: currentOffer,
|
|
110
111
|
override: override,
|
|
111
|
-
setConfig: setConfig
|
|
112
|
+
setConfig: setConfig,
|
|
113
|
+
durations: durations
|
|
112
114
|
})
|
|
113
115
|
}), _jsx(Tooltip, {
|
|
114
116
|
content: "Supprimer",
|
|
@@ -14,7 +14,8 @@ export default function OverridesList({
|
|
|
14
14
|
currentOverride,
|
|
15
15
|
setCurrentOverride,
|
|
16
16
|
config,
|
|
17
|
-
setConfig
|
|
17
|
+
setConfig,
|
|
18
|
+
durations
|
|
18
19
|
}) {
|
|
19
20
|
const [opened, setOpened] = React.useState(false);
|
|
20
21
|
const [newOverride, setNewOverride] = React.useState("");
|
|
@@ -75,7 +76,8 @@ export default function OverridesList({
|
|
|
75
76
|
setCurrentOverride: setCurrentOverride,
|
|
76
77
|
config: config,
|
|
77
78
|
setConfig: setConfig,
|
|
78
|
-
closeCreationForm: closeCreationForm
|
|
79
|
+
closeCreationForm: closeCreationForm,
|
|
80
|
+
durations: durations
|
|
79
81
|
}, override.id);
|
|
80
82
|
})
|
|
81
83
|
}) : null, _jsxs("div", {
|
|
@@ -14,7 +14,8 @@ export default function Rules({
|
|
|
14
14
|
container,
|
|
15
15
|
config,
|
|
16
16
|
setConfig,
|
|
17
|
-
tunnelOffers
|
|
17
|
+
tunnelOffers,
|
|
18
|
+
durations
|
|
18
19
|
}) {
|
|
19
20
|
const [currentOffer, setCurrentOffer] = React.useState("");
|
|
20
21
|
const [currentOverride, setCurrentOverride] = React.useState(null);
|
|
@@ -61,7 +62,8 @@ export default function Rules({
|
|
|
61
62
|
currentOverride: currentOverride,
|
|
62
63
|
setCurrentOverride: setCurrentOverride,
|
|
63
64
|
config: config,
|
|
64
|
-
setConfig: setConfig
|
|
65
|
+
setConfig: setConfig,
|
|
66
|
+
durations: durations
|
|
65
67
|
}), currentOffer && _jsxs(_Fragment, {
|
|
66
68
|
children: [_jsx("div", {
|
|
67
69
|
className: styles.subTitle,
|
|
@@ -20,7 +20,7 @@ export function getSortedOffers(container, cartContent, config) {
|
|
|
20
20
|
contentEditable.forEach(element => {
|
|
21
21
|
element.removeAttribute("contenteditable");
|
|
22
22
|
});
|
|
23
|
-
const title = clonedSection.querySelector(".tunnel-offer__title")?.textContent;
|
|
23
|
+
const title = clonedSection.querySelector(".tunnel-offer__title, [data-title]")?.textContent;
|
|
24
24
|
const uuid = section.getAttribute("data-uuid") || "";
|
|
25
25
|
const weight = Object.keys(config).reduce((acc, key) => {
|
|
26
26
|
const override = getActiveOverride(key, cartContent, config);
|
|
@@ -53,7 +53,7 @@ export function getActiveOverride(key, cartContent, config) {
|
|
|
53
53
|
const item = config[key];
|
|
54
54
|
if (!amountInCart) return item?.default;
|
|
55
55
|
const matchingOverrides = getMatchingOverrides(item, cartContent);
|
|
56
|
-
const activeOverride = matchingOverrides.length > 0 ? item?.overrides.find(o => o.id === matchingOverrides[
|
|
56
|
+
const activeOverride = matchingOverrides.length > 0 ? item?.overrides.find(o => o.id === matchingOverrides[matchingOverrides.length - 1]) : item?.default || {};
|
|
57
57
|
return activeOverride;
|
|
58
58
|
}
|
|
59
59
|
function getMatchingOverrides(item, cartContent) {
|
|
@@ -65,12 +65,14 @@ function getMatchingOverrides(item, cartContent) {
|
|
|
65
65
|
const {
|
|
66
66
|
stay,
|
|
67
67
|
merchants,
|
|
68
|
-
skiPassDurations = []
|
|
68
|
+
skiPassDurations = [],
|
|
69
|
+
durationTags
|
|
69
70
|
} = cartContent;
|
|
70
71
|
const isStayMatching = checkStay(override, stay);
|
|
71
72
|
const isMerchantMatching = checkMerchants(override, merchants);
|
|
72
73
|
const isSkiPassDurationMatching = checkSkiPassDurations(override, skiPassDurations);
|
|
73
|
-
const
|
|
74
|
+
const isDurationTagMatching = checkDurationTags(override, durationTags);
|
|
75
|
+
const isMatching = isStayMatching || isMerchantMatching || isSkiPassDurationMatching || isDurationTagMatching;
|
|
74
76
|
return isMatching ? [...acc, override.id] : acc;
|
|
75
77
|
}, []);
|
|
76
78
|
return matchs;
|
|
@@ -120,6 +122,14 @@ function checkSkiPassDurations(override, skiPassDurations) {
|
|
|
120
122
|
return false;
|
|
121
123
|
}
|
|
122
124
|
}
|
|
125
|
+
function checkDurationTags(override, durationTags) {
|
|
126
|
+
if (!durationTags) return false;
|
|
127
|
+
const {
|
|
128
|
+
durationTag
|
|
129
|
+
} = override.triggers || {};
|
|
130
|
+
if (!durationTag) return false;
|
|
131
|
+
return durationTags.includes(durationTag);
|
|
132
|
+
}
|
|
123
133
|
export const allowedOverrides = ["HOT", "LIFT", "SKI_RENTAL", "STAND"];
|
|
124
134
|
export function hasAllowedOverrides(kind) {
|
|
125
135
|
return allowedOverrides.includes(kind);
|
|
@@ -165,7 +175,7 @@ export function getStayFromCart(cart) {
|
|
|
165
175
|
duration
|
|
166
176
|
};
|
|
167
177
|
}
|
|
168
|
-
export async function
|
|
178
|
+
export async function getSkiPassDurationFromCart(cart) {
|
|
169
179
|
const {
|
|
170
180
|
LIFT: items
|
|
171
181
|
} = cart.orders;
|
|
@@ -191,6 +201,15 @@ export async function getskiPassDurationFromCart(cart) {
|
|
|
191
201
|
}, []);
|
|
192
202
|
return durations.map(d => d.nbDays);
|
|
193
203
|
}
|
|
204
|
+
export async function getDurationTagsFromCart(cart) {
|
|
205
|
+
const {
|
|
206
|
+
LIFT: items
|
|
207
|
+
} = cart.orders;
|
|
208
|
+
if (!items?.length) return [];
|
|
209
|
+
const tags = items[0].inscriptions.flatMap(i => i.durationTags).filter(Boolean);
|
|
210
|
+
const uniqueTags = tags?.length > 0 ? [...new Set(tags)] : [];
|
|
211
|
+
return uniqueTags;
|
|
212
|
+
}
|
|
194
213
|
export const CONFIG_ID = "cross-selling-editor";
|
|
195
214
|
export function getConfig(container) {
|
|
196
215
|
const config = container?.querySelector(`#${CONFIG_ID}`);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import NumberPicker from "dt-design-system/es/number-picker";
|
|
3
3
|
import Input from "dt-design-system/es/input";
|
|
4
|
+
import Select from "dt-design-system/es/select";
|
|
4
5
|
import * as Utils from "./services/utils";
|
|
5
6
|
import styles from "./tester-tunnel-offer.module.css";
|
|
6
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -11,7 +12,8 @@ export default function TesterTunnelOffer({
|
|
|
11
12
|
label,
|
|
12
13
|
cartOffers,
|
|
13
14
|
updateCartOffers,
|
|
14
|
-
refreshCartContent
|
|
15
|
+
refreshCartContent,
|
|
16
|
+
durations
|
|
15
17
|
}) {
|
|
16
18
|
const overrideAllowed = Utils.allowedOverrides.includes(kind);
|
|
17
19
|
const isSkiPasses = kind === "LIFT";
|
|
@@ -28,16 +30,26 @@ export default function TesterTunnelOffer({
|
|
|
28
30
|
}), overrideAllowed && items.map((_, index) => {
|
|
29
31
|
const number = index + 1;
|
|
30
32
|
if (isSkiPasses) {
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
return _jsxs(React.Fragment, {
|
|
34
|
+
children: [_jsx(Input, {
|
|
35
|
+
type: "number",
|
|
36
|
+
className: styles.input,
|
|
37
|
+
"data-kind": "skiPassDuration",
|
|
38
|
+
label: `Durée du forfait n°${number}`,
|
|
39
|
+
placeholder: "En jour(s) (Optionnel)",
|
|
40
|
+
min: 0,
|
|
41
|
+
max: 40,
|
|
42
|
+
onChange: refreshCartContent,
|
|
43
|
+
compact: true
|
|
44
|
+
}), durations && _jsx(Select, {
|
|
45
|
+
className: styles.input,
|
|
46
|
+
label: durations?.title + ` n°${number}`,
|
|
47
|
+
placeholder: " ",
|
|
48
|
+
"data-kind": "durationTags",
|
|
49
|
+
options: durations?.tags,
|
|
50
|
+
onChange: refreshCartContent,
|
|
51
|
+
compact: true
|
|
52
|
+
})]
|
|
41
53
|
}, index);
|
|
42
54
|
}
|
|
43
55
|
return _jsx(Input, {
|
|
@@ -3,16 +3,17 @@ import Input from "dt-design-system/es/input";
|
|
|
3
3
|
import Popover from "dt-design-system/es/popover";
|
|
4
4
|
import Button from "dt-design-system/es/button";
|
|
5
5
|
import * as Icons from "dt-design-system/es/icons";
|
|
6
|
-
import styles from "./tester.module.css";
|
|
7
|
-
import * as Utils from "./services/utils";
|
|
8
6
|
import TesterTunnelOffer from "./tester-tunnel-offer";
|
|
7
|
+
import * as Utils from "./services/utils";
|
|
8
|
+
import styles from "./tester.module.css";
|
|
9
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
10
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
11
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
12
12
|
export default function Tester({
|
|
13
13
|
container,
|
|
14
14
|
config,
|
|
15
|
-
tunnelOffers
|
|
15
|
+
tunnelOffers,
|
|
16
|
+
durations
|
|
16
17
|
}) {
|
|
17
18
|
const ref = React.useRef(null);
|
|
18
19
|
const [stayFrom, setStayFrom] = React.useState("");
|
|
@@ -20,6 +21,7 @@ export default function Tester({
|
|
|
20
21
|
const [cartOffers, setCartOffers] = React.useState({});
|
|
21
22
|
const [merchants, setMerchants] = React.useState([]);
|
|
22
23
|
const [skiPassDurations, setSkiPassDurations] = React.useState([]);
|
|
24
|
+
const [durationTags, setDurationTags] = React.useState([]);
|
|
23
25
|
const updateStayFrom = value => {
|
|
24
26
|
setStayFrom(value);
|
|
25
27
|
const stayToIsUndefined = !stayTo;
|
|
@@ -49,7 +51,8 @@ export default function Tester({
|
|
|
49
51
|
items: cartOffers,
|
|
50
52
|
stay,
|
|
51
53
|
merchants,
|
|
52
|
-
skiPassDurations
|
|
54
|
+
skiPassDurations,
|
|
55
|
+
durationTags
|
|
53
56
|
};
|
|
54
57
|
const sortedOffers = Utils.getSortedOffers(container, cartContent, config);
|
|
55
58
|
const activeOverrides = Object.keys(cartOffers).reduce((acc, key) => {
|
|
@@ -73,12 +76,15 @@ export default function Tester({
|
|
|
73
76
|
const refreshCartContent = () => {
|
|
74
77
|
const container = ref.current;
|
|
75
78
|
if (container) {
|
|
76
|
-
const merchantInputs = Array.from(container.querySelectorAll("[data-kind=merchant]"));
|
|
77
|
-
const skiPassDurationInputs = Array.from(container.querySelectorAll("[data-kind=skiPassDuration]"));
|
|
79
|
+
const merchantInputs = Array.from(container.querySelectorAll("[data-kind='merchant']"));
|
|
80
|
+
const skiPassDurationInputs = Array.from(container.querySelectorAll("[data-kind='skiPassDuration']"));
|
|
81
|
+
const durationTagsSelect = Array.from(container.querySelectorAll("[data-kind='durationTags']"));
|
|
78
82
|
const merchants = merchantInputs.map(input => input.value).filter(Boolean);
|
|
79
83
|
const skiPassDurations = skiPassDurationInputs.map(input => Number(input.value)).filter(Boolean);
|
|
84
|
+
const durationTags = durationTagsSelect.map(select => select.value).filter(Boolean);
|
|
80
85
|
setMerchants(merchants);
|
|
81
86
|
setSkiPassDurations(skiPassDurations);
|
|
87
|
+
setDurationTags(durationTags);
|
|
82
88
|
}
|
|
83
89
|
};
|
|
84
90
|
const tunnelOptions = Object.keys(tunnelOffers).map(key => {
|
|
@@ -139,7 +145,8 @@ export default function Tester({
|
|
|
139
145
|
label: label,
|
|
140
146
|
cartOffers: cartOffers,
|
|
141
147
|
updateCartOffers: updateCartOffers,
|
|
142
|
-
refreshCartContent: refreshCartContent
|
|
148
|
+
refreshCartContent: refreshCartContent,
|
|
149
|
+
durations: durations
|
|
143
150
|
}, key.concat(label));
|
|
144
151
|
})
|
|
145
152
|
})]
|