ublo-lib 1.49.12 → 1.50.1

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.
Files changed (78) hide show
  1. package/es/common/components/admin-links/admin-links.d.ts.map +1 -1
  2. package/es/common/hooks/use-faq.d.ts.map +1 -1
  3. package/es/common/hooks/use-scroll-direction.d.ts.map +1 -1
  4. package/es/common/utils/cookies.d.ts.map +1 -1
  5. package/es/common/utils/copy.d.ts.map +1 -1
  6. package/es/common/utils/dates.d.ts.map +1 -1
  7. package/es/common/utils/fetcher.d.ts.map +1 -1
  8. package/es/common/utils/msem-widget.d.ts.map +1 -1
  9. package/es/common/utils/url-parameters.d.ts.map +1 -1
  10. package/es/esf/components/espace-prive/services/middleware.d.ts.map +1 -1
  11. package/es/future/components/event-analytics/instant-search.d.ts.map +1 -1
  12. package/es/future/components/msem-package/components/config.d.ts.map +1 -1
  13. package/es/future/components/msem-package/components/config.js +44 -18
  14. package/es/future/components/msem-package/components/filters.d.ts +5 -1
  15. package/es/future/components/msem-package/components/filters.d.ts.map +1 -1
  16. package/es/future/components/msem-package/components/filters.js +78 -15
  17. package/es/future/components/msem-package/components/filters.module.css +124 -20
  18. package/es/future/components/msem-package/components/global-settings.d.ts.map +1 -1
  19. package/es/future/components/msem-package/components/global-settings.js +2 -11
  20. package/es/future/components/msem-package/components/global-settings.module.css +2 -34
  21. package/es/future/components/msem-package/components/pax-settings.d.ts +9 -0
  22. package/es/future/components/msem-package/components/pax-settings.d.ts.map +1 -0
  23. package/es/future/components/msem-package/components/pax-settings.js +73 -0
  24. package/es/future/components/msem-package/components/pax-settings.module.css +48 -0
  25. package/es/future/components/msem-package/components/settings-ui.d.ts +23 -0
  26. package/es/future/components/msem-package/components/settings-ui.d.ts.map +1 -0
  27. package/es/future/components/msem-package/components/settings-ui.js +14 -0
  28. package/es/future/components/msem-package/components/settings-ui.module.css +152 -0
  29. package/es/future/components/msem-package/components/stay-settings.d.ts.map +1 -1
  30. package/es/future/components/msem-package/components/stay-settings.js +44 -25
  31. package/es/future/components/msem-package/components/stay-settings.module.css +21 -44
  32. package/es/future/components/msem-package/components/widget-dialog.d.ts.map +1 -1
  33. package/es/future/components/msem-package/components/widget-dialog.js +20 -12
  34. package/es/future/components/msem-package/components/widget-dialog.module.css +1 -22
  35. package/es/future/components/msem-package/components/widget.d.ts +3 -1
  36. package/es/future/components/msem-package/components/widget.d.ts.map +1 -1
  37. package/es/future/components/msem-package/components/widget.js +102 -36
  38. package/es/future/components/msem-package/components/widget.module.css +114 -51
  39. package/es/future/components/msem-package/components/widgets-settings.d.ts.map +1 -1
  40. package/es/future/components/msem-package/components/widgets-settings.js +22 -22
  41. package/es/future/components/msem-package/components/widgets-settings.module.css +95 -44
  42. package/es/future/components/msem-package/components/widgets.d.ts +3 -1
  43. package/es/future/components/msem-package/components/widgets.d.ts.map +1 -1
  44. package/es/future/components/msem-package/components/widgets.js +28 -13
  45. package/es/future/components/msem-package/core.d.ts.map +1 -1
  46. package/es/future/components/msem-package/core.js +13 -2
  47. package/es/future/components/msem-package/i18n/ca.json +17 -3
  48. package/es/future/components/msem-package/i18n/en.json +17 -3
  49. package/es/future/components/msem-package/i18n/es.json +17 -3
  50. package/es/future/components/msem-package/i18n/fr.json +17 -3
  51. package/es/future/components/msem-package/msem-package.module.css +29 -0
  52. package/es/future/components/msem-package/types.d.ts +12 -1
  53. package/es/future/components/msem-package/types.d.ts.map +1 -1
  54. package/es/future/components/msem-package/utils/api.d.ts.map +1 -1
  55. package/es/future/components/msem-package/utils/pax.d.ts +3 -0
  56. package/es/future/components/msem-package/utils/pax.d.ts.map +1 -0
  57. package/es/future/components/msem-package/utils/pax.js +9 -0
  58. package/es/future/components/msem-preset-editor/editors/easyrent-rental.d.ts.map +1 -1
  59. package/es/future/components/msem-preset-editor/editors/easyrent-rental.js +1 -1
  60. package/es/future/components/msem-preset-editor/editors/ski-rental.d.ts.map +1 -1
  61. package/es/future/components/msem-preset-editor/editors/ski-rental.js +1 -1
  62. package/es/future/components/msem-preset-editor/msem-preset-editor.d.ts.map +1 -1
  63. package/es/future/components/msem-preset-editor/msem-preset-editor.js +1 -0
  64. package/es/future/components/msem-preset-editor/services/offers.js +1 -1
  65. package/es/future/components/msem-preset-editor/services/url-params.d.ts.map +1 -1
  66. package/es/future/utils/url-parameters.d.ts.map +1 -1
  67. package/es/lbm/components/instant-search/widgets/access.d.ts.map +1 -1
  68. package/es/lbm/components/instant-search/widgets/activity.d.ts.map +1 -1
  69. package/es/lbm/components/instant-search/widgets/dawn-nights-openings.d.ts.map +1 -1
  70. package/es/lbm/components/instant-search/widgets/lift.d.ts.map +1 -1
  71. package/es/lbm/components/instant-search/widgets/lifts.d.ts.map +1 -1
  72. package/es/lbm/components/instant-search/widgets/openings.d.ts.map +1 -1
  73. package/es/lbm/components/instant-search/widgets/slope.d.ts.map +1 -1
  74. package/es/lbm/components/instant-search/widgets/slopes.d.ts.map +1 -1
  75. package/es/lbm/components/instant-search/widgets/snow.d.ts.map +1 -1
  76. package/es/lbm/components/instant-search/widgets/weather.d.ts.map +1 -1
  77. package/es/lbm/components/instant-search/widgets/webcam.d.ts.map +1 -1
  78. package/package.json +1 -1
@@ -25,24 +25,37 @@ const defaultHide = [
25
25
  "description",
26
26
  "upsales",
27
27
  ];
28
- export default function Widget({ index, config, widget, step, setStep, stay, completedSteps, setCompletedSteps, packageId, }) {
28
+ export default function Widget({ index, config, widget, step, setStep, stay, pax, locked, completedSteps, setCompletedSteps, packageId, }) {
29
29
  const ref = React.useRef(null);
30
30
  const widgetContainerRef = React.useRef(null);
31
31
  const { lang, widgets } = useMsemRuntime();
32
32
  const [addedToCart, setAddedToCart] = React.useState(false);
33
- const { id, widget: kind, image, title, tagline, options, presets, repeatable, optional, maxParticipants, } = widget;
33
+ const { id, widget: kind, logo, title, tagline, options, presets, repeatable, optional, maxParticipants, } = widget;
34
+ const dated = config.stay?.dated ?? Boolean(config.stay?.from || config.stay?.to);
35
+ const paxRangeVisible = config.pax?.mode === "range" && !config.pax?.hidden;
34
36
  const [innerStep, setInnerStep] = React.useState(1);
35
37
  const [optionalRepeat, setOptionalRepeat] = React.useState(0);
36
- const repeat = repeatable ? (optional ? optionalRepeat : config.paxPlan) : 1;
37
- const areAllInnerStepsFinished = !repeatable || (!optional && innerStep === repeat);
38
+ const [count, setCount] = React.useState(0);
39
+ const { min: repeatMin, max: repeatMax } = resolveMandatoryRange(config.pax, pax, maxParticipants);
38
40
  const { name: packageName } = config;
39
- const nextWidget = config.widgets[index + 1];
41
+ const nextWidget = optional ? undefined : config.widgets[index + 1];
40
42
  const widgetLang = lang === "fr" ? "fr" : "en";
41
43
  const isStarted = id === step;
42
- const isDisabled = !optional &&
43
- (!stay?.from || !stay?.to || !completedSteps.includes(index - 1));
44
+ const done = repeatable && !optional ? count >= repeatMin : addedToCart;
45
+ const canAddPerson = repeatable && !optional && done && count < repeatMax && !isStarted;
46
+ const showAddChip = !isStarted &&
47
+ repeatable &&
48
+ ((!optional && done && count < repeatMax) ||
49
+ (optional && optionalRepeat > 0 && optionalRepeat < (maxParticipants ?? 0)));
50
+ const needsStay = dated && (!stay?.from || !stay?.to);
51
+ const needsPax = paxRangeVisible && pax == null;
52
+ const otherStepOpen = step != null && step !== id;
53
+ const isDisabled = locked ||
54
+ needsStay ||
55
+ needsPax ||
56
+ (optional ? otherStepOpen : !completedSteps.includes(index - 1));
44
57
  const startWidget = (force) => {
45
- if (!force && (isDisabled || isStarted || addedToCart))
58
+ if (!force && (isDisabled || isStarted || done))
46
59
  return;
47
60
  if (innerStep > optionalRepeat) {
48
61
  setOptionalRepeat(optionalRepeat + 1);
@@ -55,29 +68,45 @@ export default function Widget({ index, config, widget, step, setStep, stay, com
55
68
  }, 600);
56
69
  }
57
70
  };
71
+ const addPerson = (e) => {
72
+ e.stopPropagation();
73
+ startWidget(true);
74
+ };
58
75
  const preventBubbling = (e) => {
59
76
  e.stopPropagation();
60
77
  };
78
+ const cancelWidget = (e) => {
79
+ e.stopPropagation();
80
+ setStep(null);
81
+ };
61
82
  const handleCartChange = () => {
62
83
  if (widgetContainerRef.current)
63
84
  widgetContainerRef.current.scrollIntoView();
64
- if (areAllInnerStepsFinished) {
85
+ if (!repeatable) {
65
86
  setAddedToCart(true);
66
87
  setCompletedSteps([...completedSteps, index]);
88
+ setStep(!optional && nextWidget ? nextWidget.id : null);
89
+ return;
67
90
  }
68
- if (areAllInnerStepsFinished && nextWidget) {
69
- const nextWidgetId = nextWidget.id;
70
- setStep(nextWidgetId);
91
+ if (optional) {
92
+ setStep(null);
93
+ setInnerStep(innerStep + 1);
94
+ return;
95
+ }
96
+ const newCount = count + 1;
97
+ setCount(newCount);
98
+ if (newCount < repeatMin) {
99
+ return;
100
+ }
101
+ if (newCount === repeatMin) {
102
+ setCompletedSteps([...completedSteps, index]);
103
+ }
104
+ if (repeatMin === repeatMax && nextWidget) {
105
+ setStep(nextWidget.id);
71
106
  }
72
107
  else {
73
108
  setStep(null);
74
109
  }
75
- if (repeatable && !areAllInnerStepsFinished) {
76
- setInnerStep(innerStep + 1);
77
- if (!optional) {
78
- startWidget(true);
79
- }
80
- }
81
110
  };
82
111
  const widgetId = `id-${id}`;
83
112
  const Widget = widgets[WIDGETS[kind]];
@@ -98,32 +127,69 @@ export default function Widget({ index, config, widget, step, setStep, stay, com
98
127
  cartChanged: handleCartChange,
99
128
  hide,
100
129
  };
101
- const allPresets = { stay, ...presets };
130
+ const allPresets = {
131
+ ...(dated ? { stay } : {}),
132
+ ...resolvePaxBounds(config.pax, pax),
133
+ ...presets,
134
+ };
102
135
  const classes = classNames(styles.widget, {
103
136
  [styles.optional]: optional && repeatable,
104
137
  [styles.repeatable]: repeatable,
105
138
  [styles.started]: isStarted,
106
139
  [styles.disabled]: isDisabled,
107
- [styles.addedToCart]: addedToCart,
108
- });
109
- const addStepClasses = classNames(styles.innerStep, styles.addStep, {
110
- [styles.disabledAdd]: isStarted || innerStep === optionalRepeat,
140
+ [styles.addedToCart]: done,
111
141
  });
112
- return (_jsxs("div", { ref: ref, className: classes, onClick: () => startWidget(), children: [_jsxs("div", { className: styles.header, children: [_jsx("div", { className: styles.iconContainer, children: addedToCart ? (_jsx(Icons.Check, { className: styles.icon })) : (_jsx("img", { src: image, className: styles.image, alt: "" })) }), _jsxs("div", { className: styles.text, children: [_jsx("div", { className: styles.title, children: title }), _jsx("div", { className: styles.tagline, children: tagline }), repeatable && (_jsxs("div", { className: styles.innerSteps, children: [[...new Array(repeat)].map((_, i) => {
113
- const id = i + 1;
114
- const isCurrent = isStarted && innerStep === id;
115
- const isCompleted = innerStep > id || addedToCart;
116
- const classes = classNames(styles.innerStep, {
142
+ return (_jsxs("div", { ref: ref, className: classes, onClick: () => startWidget(), children: [_jsxs("div", { className: styles.header, children: [_jsx("div", { className: styles.number, children: done ? (_jsx(Icons.Check, { className: styles.numberIcon })) : optional ? (logo ? (_jsx("img", { src: logo, className: styles.numberLogo, alt: "" })) : (_jsx(Icons.Pack, { className: styles.numberIcon }))) : (String(index + 1).padStart(2, "0")) }), _jsxs("div", { className: styles.text, children: [_jsx("div", { className: styles.title, children: title }), _jsx("div", { className: styles.tagline, children: tagline }), repeatable && (_jsxs("div", { className: styles.innerSteps, children: [(optional
143
+ ? [...new Array(optionalRepeat)].map((_, i) => ({
144
+ n: i + 1,
145
+ isCurrent: isStarted && innerStep === i + 1,
146
+ isCompleted: innerStep > i + 1 || addedToCart,
147
+ }))
148
+ : [
149
+ ...new Array(Math.max(repeatMin, count + (isStarted ? 1 : 0))),
150
+ ].map((_, i) => ({
151
+ n: i + 1,
152
+ isCurrent: isStarted && i + 1 === count + 1,
153
+ isCompleted: i + 1 <= count,
154
+ }))).map(({ n, isCurrent, isCompleted }) => {
155
+ const cls = classNames(styles.innerStep, {
117
156
  [styles.current]: isCurrent,
118
157
  [styles.completed]: isCompleted,
119
158
  });
120
159
  const Icon = isCompleted ? Icons.Check : Icons.User;
121
- return (_jsxs("div", { className: classes, children: [_jsx(Icon, { className: styles.innerStepIcon }), _jsx(T, { id: "widget.person" }), " ", id] }, i));
122
- }), optional && optionalRepeat < maxParticipants && (_jsxs("div", { className: addStepClasses, onClick: isStarted
123
- ? undefined
124
- : () => {
125
- if (innerStep > optionalRepeat) {
126
- startWidget(true);
127
- }
128
- }, children: [_jsx(Icons.Plus, { className: styles.innerStepIcon }), "Ajouter"] }))] }))] })] }), isStarted && (_jsx("div", { ref: widgetContainerRef, className: styles.widgetContainer, onClick: preventBubbling, children: _jsx(Widget, { options: allOptions, presets: allPresets, children: _jsx("div", { id: widgetId }) }) }))] }));
160
+ return (_jsxs("div", { className: cls, children: [_jsx(Icon, { className: styles.innerStepIcon }), _jsx(T, { id: "widget.person" }), " ", n] }, n));
161
+ }), showAddChip && (_jsxs("button", { type: "button", className: classNames(styles.innerStep, styles.addChip), onClick: addPerson, children: [_jsx(Icons.Plus, { className: styles.innerStepIcon }), _jsx(T, { id: "widget.extra-person" })] }))] }))] }), isStarted && (optional || done) ? (_jsx("button", { type: "button", className: styles.cancel, onClick: cancelWidget, children: _jsx(T, { id: "widget.cancel" }) })) : !isStarted && !done ? (_jsx("div", { className: styles.action, children: _jsx(T, { id: optional ? "widget.add" : "widget.book" }) })) : canAddPerson ? (_jsx("button", { type: "button", className: styles.action, onClick: addPerson, children: _jsx(T, { id: "widget.add-person" }) })) : null] }), isStarted && (_jsx("div", { ref: widgetContainerRef, className: styles.widgetContainer, onClick: preventBubbling, children: _jsx(Widget, { options: allOptions, presets: allPresets, children: _jsx("div", { id: widgetId }) }) }))] }));
162
+ }
163
+ function resolveMandatoryRange(pax, chosen, widgetMax) {
164
+ if (!pax || pax.mode === "unlimited") {
165
+ const n = widgetMax ?? 1;
166
+ return { min: n, max: n };
167
+ }
168
+ if (pax.mode === "fixed") {
169
+ const n = pax.value ?? 1;
170
+ return { min: n, max: n };
171
+ }
172
+ if (pax.hidden) {
173
+ const a = pax.min ?? pax.max ?? 1;
174
+ const b = pax.max ?? pax.min ?? 1;
175
+ return { min: Math.min(a, b), max: Math.max(a, b) };
176
+ }
177
+ const n = chosen ?? pax.min ?? 1;
178
+ return { min: n, max: n };
179
+ }
180
+ function resolvePaxBounds(pax, chosen) {
181
+ if (!pax || pax.mode === "unlimited")
182
+ return {};
183
+ if (pax.mode === "fixed") {
184
+ return pax.value != null ? { paxMin: pax.value, paxMax: pax.value } : {};
185
+ }
186
+ if (pax.hidden) {
187
+ const bounds = {};
188
+ if (pax.min != null)
189
+ bounds.paxMin = pax.min;
190
+ if (pax.max != null)
191
+ bounds.paxMax = pax.max;
192
+ return bounds;
193
+ }
194
+ return chosen != null ? { paxMin: chosen, paxMax: chosen } : {};
129
195
  }
@@ -1,14 +1,10 @@
1
1
  .widget {
2
- padding: 12px;
3
- background-color: var(--ds-grey-100, #f8f8f8);
2
+ overflow: hidden;
3
+ background-color: var(--ds-grey-000, #fff);
4
4
  border: 1px solid var(--ds-grey-200, #ededed);
5
5
  border-radius: var(--ds-radius-200, 8px);
6
6
  }
7
7
 
8
- .addedToCart {
9
- background-color: var(--ds-green-200, #a6ffc3);
10
- }
11
-
12
8
  .disabled {
13
9
  cursor: not-allowed;
14
10
  opacity: 0.5;
@@ -16,69 +12,127 @@
16
12
 
17
13
  .widget:not(.started, .disabled, .addedToCart) {
18
14
  cursor: pointer;
19
- transition: box-shadow 160ms
20
- var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9));
15
+ transition: border-color 160ms
16
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9)),
17
+ box-shadow 160ms
18
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9));
19
+ }
20
+
21
+ .widget:not(.started, .disabled, .addedToCart):hover {
22
+ border-color: var(--ds-grey-300, #d7d7d7);
23
+ box-shadow: var(--ds-shadow-200, 0 5px 10px rgba(0, 0, 0, 0.08));
21
24
  }
22
25
 
23
- .widget:not(.started, .disabled, .addedToCart, .repeatable):hover {
24
- box-shadow: var(--ds-shadow-200, 0 5px 10px rgba(0, 0, 0, 0.12));
26
+ .started {
27
+ border-color: var(--ds-secondary, var(--ds-primary, #002dcc));
28
+ }
29
+
30
+ .addedToCart {
31
+ border-color: var(--ds-secondary, var(--ds-primary, #002dcc));
25
32
  }
26
33
 
27
34
  .header {
28
35
  display: flex;
29
- flex-direction: column;
30
- gap: 12px;
36
+ align-items: stretch;
37
+ min-height: 76px;
31
38
  }
32
39
 
33
- @media (min-width: 480px) {
34
- .header {
35
- flex-direction: row;
36
- }
40
+ /* Cellule numéro / coche / picto à gauche */
41
+ .number {
42
+ display: flex;
43
+ flex: 0 0 64px;
44
+ align-items: center;
45
+ justify-content: center;
46
+ padding: 12px;
47
+ font-size: 20px;
48
+ font-weight: 700;
49
+ color: var(--ds-grey-500, #7c7b7b);
50
+ border-right: 1px solid var(--ds-grey-200, #ededed);
37
51
  }
38
52
 
39
- .iconContainer {
40
- flex: 0 0 90px;
53
+ .started .number {
54
+ color: var(--ds-secondary, var(--ds-primary, #002dcc));
41
55
  }
42
56
 
43
- @media (min-width: 480px) {
44
- .iconContainer {
45
- flex: 0 0 140px;
46
- display: flex;
47
- align-items: center;
48
- justify-content: center;
49
- }
57
+ .addedToCart .number {
58
+ color: var(--ds-grey-000, #fff);
59
+ background-color: var(--ds-secondary, var(--ds-primary, #002dcc));
50
60
  }
51
61
 
52
- .icon {
53
- width: 44px;
54
- height: 44px;
62
+ .numberIcon {
63
+ width: 24px;
64
+ height: 24px;
65
+ fill: currentcolor;
55
66
  }
56
67
 
57
- .image {
58
- max-width: 100%;
59
- border: 1px solid var(--ds-grey-200, #ededed);
60
- border-radius: var(--ds-radius-200, 8px);
68
+ .numberLogo {
69
+ width: 32px;
70
+ height: 32px;
71
+ object-fit: contain;
61
72
  }
62
73
 
63
74
  .text {
64
75
  display: flex;
76
+ flex: 1 1 auto;
65
77
  flex-direction: column;
66
- gap: 6px;
78
+ justify-content: center;
79
+ gap: 4px;
80
+ padding: 14px 18px;
67
81
  }
68
82
 
69
83
  .title {
70
- font-size: 22px;
84
+ font-size: 18px;
71
85
  font-weight: 700;
86
+ line-height: 1.25;
72
87
  }
73
88
 
74
89
  .tagline {
90
+ font-size: 14px;
91
+ color: var(--ds-grey-600, #484848);
92
+ }
93
+
94
+ /* Action "Réserver" / "Ajouter" à droite (div ou button) */
95
+ .action {
96
+ display: flex;
97
+ flex: 0 0 auto;
98
+ align-items: center;
99
+ padding: 0 20px;
100
+ font: inherit;
75
101
  font-size: 15px;
102
+ font-weight: 700;
103
+ color: var(--ds-secondary, var(--ds-primary, #002dcc));
104
+ background: none;
105
+ border: 0;
106
+ cursor: pointer;
107
+ white-space: nowrap;
76
108
  }
77
109
 
110
+ /* Bouton "Annuler" (option en cours d'ajout) */
111
+ .cancel {
112
+ display: flex;
113
+ flex: 0 0 auto;
114
+ align-items: center;
115
+ padding: 0 20px;
116
+ font: inherit;
117
+ font-size: 15px;
118
+ font-weight: 700;
119
+ color: var(--ds-grey-600, #484848);
120
+ background: none;
121
+ border: 0;
122
+ cursor: pointer;
123
+ white-space: nowrap;
124
+ }
125
+
126
+ .cancel:hover {
127
+ color: var(--ds-grey-800, #000);
128
+ }
129
+
130
+ /* Étapes internes "Personne N" (widget répétable) */
78
131
  .innerSteps {
79
132
  display: flex;
80
133
  flex-wrap: wrap;
81
134
  gap: 8px;
135
+ margin-top: 6px;
82
136
  }
83
137
 
84
138
  .innerStep {
@@ -87,23 +141,39 @@
87
141
  align-items: center;
88
142
  justify-content: center;
89
143
  gap: 4px;
90
- padding: 10px;
91
- color: var(--ds-grey-800, #000);
92
- font-size: 15px;
144
+ width: 96px;
145
+ padding: 8px;
146
+ font-size: 14px;
93
147
  font-weight: 700;
148
+ color: var(--ds-grey-800, #000);
94
149
  border: 2px dashed var(--ds-grey-300, #d7d7d7);
95
150
  border-radius: var(--ds-radius-200, 8px);
96
- width: 110px;
97
151
  }
98
152
 
99
153
  .completed {
100
- background-color: var(--ds-green-200, #a6ffc3);
101
- border: 2px solid var(--ds-green-400, #24c678);
154
+ color: var(--ds-secondary, var(--ds-primary, #002dcc));
155
+ border-style: solid;
156
+ border-color: var(--ds-secondary, var(--ds-primary, #002dcc));
102
157
  }
103
158
 
104
159
  .current {
105
- background-color: var(--ds-grey-200, #ededed);
106
- border: 2px solid var(--ds-grey-500, #7c7b7b);
160
+ background-color: var(--ds-grey-100, #f8f8f8);
161
+ border-color: var(--ds-grey-500, #7c7b7b);
162
+ }
163
+
164
+ /* Puce "+ Personne supplémentaire" (invite à ajouter) — neutre, pas "validée" */
165
+ .addChip {
166
+ width: auto;
167
+ padding-inline: 16px;
168
+ color: var(--ds-grey-600, #484848);
169
+ border-style: dashed;
170
+ border-color: var(--ds-grey-300, #d7d7d7);
171
+ background: none;
172
+ cursor: pointer;
173
+ font: inherit;
174
+ font-size: 14px;
175
+ font-weight: 700;
176
+ white-space: nowrap;
107
177
  }
108
178
 
109
179
  .innerStepIcon {
@@ -113,13 +183,6 @@
113
183
  }
114
184
 
115
185
  .widgetContainer {
116
- margin-top: 10px;
117
- }
118
-
119
- .addStep {
120
- cursor: pointer;
121
- }
122
- .disabledAdd {
123
- cursor: not-allowed;
124
- opacity: 0.5;
186
+ padding: 16px 18px;
187
+ border-top: 1px solid var(--ds-grey-200, #ededed);
125
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"widgets-settings.d.ts","sourceRoot":"","sources":["../../../../../src/future/components/msem-package/components/widgets-settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,KAAK,KAAK,MAAM,UAAU,CAAC;AAGvC,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9D,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC;CACpC,CAAC;AAeF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,MAAM,EACN,SAAS,EACT,aAAa,GACd,EAAE,KAAK,2CA4NP"}
1
+ {"version":3,"file":"widgets-settings.d.ts","sourceRoot":"","sources":["../../../../../src/future/components/msem-package/components/widgets-settings.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,KAAK,KAAK,MAAM,UAAU,CAAC;AAGvC,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;IACrB,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9D,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC;CACpC,CAAC;AAcF,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,MAAM,EACN,SAAS,EACT,aAAa,GACd,EAAE,KAAK,2CA8NP"}
@@ -4,10 +4,10 @@ import Button from "dt-design-system/es/button";
4
4
  import Popover from "dt-design-system/es/popover";
5
5
  import * as Icons from "dt-design-system/es/icons";
6
6
  import WidgetDialog from "./widget-dialog";
7
+ import { Card } from "./settings-ui";
7
8
  import styles from "./widgets-settings.module.css";
8
9
  const createNewWidget = (optional) => ({
9
10
  id: "new",
10
- image: "",
11
11
  name: "",
12
12
  widget: "",
13
13
  title: optional ? "Nouvelle offre optionnelle" : "Nouvelle offre",
@@ -57,25 +57,25 @@ export default function WidgetsSettings({ config, setConfig, editorOptions, }) {
57
57
  }
58
58
  };
59
59
  const showDialog = widget !== null;
60
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.container, children: [_jsxs("div", { className: styles.title, children: [_jsx(Icons.ShoppingBag, {}), "Composition du package"] }), _jsxs("div", { className: styles.widgets, children: [config.widgets?.map(({ id, image, title, tagline }, i) => {
61
- const isFirst = i === 0;
62
- const isLast = i === config.widgets.length - 1;
63
- const moveBefore = () => {
64
- reorder(i, -1);
65
- };
66
- const moveAfter = () => {
67
- reorder(i, 1);
68
- };
69
- return (_jsxs("div", { className: styles.widget, children: [_jsxs(Button, { variant: "secondary", className: styles.widgetButton, onClick: openWidgetDialog(i), children: [image ? _jsx("img", { src: image, alt: "" }) : _jsx(Icons.Grid, {}), _jsx("span", { className: styles.widgetTitle, children: title }), _jsx("span", { className: styles.widgetTagline, children: tagline })] }), _jsxs(Popover, { className: styles.removePopover, trigger: _jsxs(Button, { variant: "danger", className: styles.remove, compact: true, children: [_jsx(Icons.Bin, {}), " Supprimer"] }), children: ["Confirmer la suppression ?", _jsx(Button, { variant: "danger", className: styles.confirmRemove, onClick: () => removeWidget(id), compact: true, children: _jsx(Icons.Check, {}) })] }), _jsxs("div", { className: styles.controls, children: [_jsx(Button, { "data-control": "prev", className: styles.control, onClick: moveBefore, disabled: isFirst, compact: true, children: _jsx(Icons.ChevronLeft, {}) }), _jsx(Button, { "data-control": "next", className: styles.control, onClick: moveAfter, disabled: isLast, compact: true, children: _jsx(Icons.ChevronRight, {}) })] })] }, id));
70
- }), _jsxs(Button, { variant: "primary", className: styles.add, onClick: openWidgetDialog("new"), children: [_jsx(Icons.Plus, {}), _jsx("span", { className: styles.widgetTitle, children: "Ajouter une offre" })] })] })] }), _jsxs("div", { className: styles.container, children: [_jsxs("div", { className: styles.title, children: [_jsx(Icons.ShoppingBag, {}), "Offres optionnelles"] }), _jsxs("div", { className: styles.widgets, children: [config.optionalWidgets?.map(({ id, image, title, tagline }, i) => {
71
- const isFirst = i === 0;
72
- const isLast = i === config.optionalWidgets.length - 1;
73
- const moveBefore = () => {
74
- reorder(i, -1, true);
75
- };
76
- const moveAfter = () => {
77
- reorder(i, 1, true);
78
- };
79
- return (_jsxs("div", { className: styles.widget, children: [_jsxs(Button, { variant: "secondary", className: styles.widgetButton, onClick: openWidgetDialog(i, true), children: [image ? _jsx("img", { src: image, alt: "" }) : _jsx(Icons.Grid, {}), _jsx("span", { className: styles.widgetTitle, children: title }), _jsx("span", { className: styles.widgetTagline, children: tagline })] }), _jsxs(Popover, { className: styles.removePopover, trigger: _jsxs(Button, { variant: "danger", className: styles.remove, compact: true, children: [_jsx(Icons.Bin, {}), " Supprimer"] }), children: ["Confirmer la suppression ?", _jsx(Button, { variant: "danger", className: styles.confirmRemove, onClick: () => removeWidget(id, true), compact: true, children: _jsx(Icons.Check, {}) })] }), _jsxs("div", { className: styles.controls, children: [_jsx(Button, { "data-control": "prev", className: styles.control, onClick: moveBefore, disabled: isFirst, compact: true, children: _jsx(Icons.ChevronLeft, {}) }), _jsx(Button, { "data-control": "next", className: styles.control, onClick: moveAfter, disabled: isLast, compact: true, children: _jsx(Icons.ChevronRight, {}) })] })] }, id));
80
- }), _jsxs(Button, { variant: "primary", className: styles.add, onClick: openWidgetDialog("new", true), children: [_jsx(Icons.Plus, {}), _jsx("span", { className: styles.widgetTitle, children: "Ajouter une option" })] })] })] }), showDialog && (_jsx(WidgetDialog, { config: config, setConfig: setConfig, editorOptions: editorOptions, widget: widget, closeWidgetDialog: closeWidgetDialog }))] }));
60
+ return (_jsxs(_Fragment, { children: [_jsx(Card, { icon: _jsx(Icons.ShoppingBag, {}), title: "Composition du package", children: _jsxs("div", { className: styles.widgets, children: [config.widgets?.map(({ id, title, tagline, logo }, i) => {
61
+ const isFirst = i === 0;
62
+ const isLast = i === config.widgets.length - 1;
63
+ const moveBefore = () => {
64
+ reorder(i, -1);
65
+ };
66
+ const moveAfter = () => {
67
+ reorder(i, 1);
68
+ };
69
+ return (_jsxs("div", { className: styles.widget, children: [_jsxs(Button, { variant: "transparent", className: styles.widgetButton, onClick: openWidgetDialog(i), children: [logo ? (_jsx("img", { src: logo, alt: "", className: styles.logo })) : (_jsx(Icons.Pack, {})), _jsxs("span", { className: styles.step, children: ["\u00C9tape ", i + 1] }), _jsx("span", { className: styles.widgetTitle, children: title }), _jsx("span", { className: styles.widgetTagline, children: tagline })] }), _jsxs(Popover, { className: styles.removePopover, trigger: _jsxs(Button, { variant: "danger", className: styles.remove, compact: true, children: [_jsx(Icons.Bin, {}), " Supprimer"] }), children: ["Confirmer la suppression ?", _jsx(Button, { variant: "danger", className: styles.confirmRemove, onClick: () => removeWidget(id), compact: true, children: _jsx(Icons.Check, {}) })] }), _jsxs("div", { className: styles.controls, children: [_jsx(Button, { "data-control": "prev", className: styles.control, onClick: moveBefore, disabled: isFirst, compact: true, children: _jsx(Icons.ChevronLeft, {}) }), _jsx(Button, { "data-control": "next", className: styles.control, onClick: moveAfter, disabled: isLast, compact: true, children: _jsx(Icons.ChevronRight, {}) })] })] }, id));
70
+ }), _jsxs(Button, { variant: "transparent", className: styles.add, onClick: openWidgetDialog("new"), children: [_jsx(Icons.Plus, {}), _jsx("span", { className: styles.widgetTitle, children: "Ajouter une offre" })] })] }) }), _jsx(Card, { icon: _jsx(Icons.Grid, {}), title: "Offres optionnelles", children: _jsxs("div", { className: styles.widgets, children: [config.optionalWidgets?.map(({ id, title, tagline, logo }, i) => {
71
+ const isFirst = i === 0;
72
+ const isLast = i === config.optionalWidgets.length - 1;
73
+ const moveBefore = () => {
74
+ reorder(i, -1, true);
75
+ };
76
+ const moveAfter = () => {
77
+ reorder(i, 1, true);
78
+ };
79
+ return (_jsxs("div", { className: styles.widget, children: [_jsxs(Button, { variant: "transparent", className: styles.widgetButton, onClick: openWidgetDialog(i, true), children: [logo ? (_jsx("img", { src: logo, alt: "", className: styles.logo })) : (_jsx(Icons.Pack, {})), _jsx("span", { className: styles.widgetTitle, children: title }), _jsx("span", { className: styles.widgetTagline, children: tagline })] }), _jsxs(Popover, { className: styles.removePopover, trigger: _jsxs(Button, { variant: "danger", className: styles.remove, compact: true, children: [_jsx(Icons.Bin, {}), " Supprimer"] }), children: ["Confirmer la suppression ?", _jsx(Button, { variant: "danger", className: styles.confirmRemove, onClick: () => removeWidget(id, true), compact: true, children: _jsx(Icons.Check, {}) })] }), _jsxs("div", { className: styles.controls, children: [_jsx(Button, { "data-control": "prev", className: styles.control, onClick: moveBefore, disabled: isFirst, compact: true, children: _jsx(Icons.ChevronLeft, {}) }), _jsx(Button, { "data-control": "next", className: styles.control, onClick: moveAfter, disabled: isLast, compact: true, children: _jsx(Icons.ChevronRight, {}) })] })] }, id));
80
+ }), _jsxs(Button, { variant: "transparent", className: styles.add, onClick: openWidgetDialog("new", true), children: [_jsx(Icons.Plus, {}), _jsx("span", { className: styles.widgetTitle, children: "Ajouter une option" })] })] }) }), showDialog && (_jsx(WidgetDialog, { config: config, setConfig: setConfig, editorOptions: editorOptions, widget: widget, closeWidgetDialog: closeWidgetDialog }))] }));
81
81
  }
@@ -1,39 +1,112 @@
1
- .container {
2
- width: min(calc(100% - 20px), 840px);
1
+ .widgets {
2
+ display: grid;
3
+ grid-template-columns: repeat(auto-fill, minmax(140px, 160px));
4
+ justify-content: start;
5
+ gap: 10px;
6
+ }
7
+
8
+ .widget {
9
+ position: relative;
3
10
  display: flex;
4
- flex-direction: column;
5
- gap: 8px;
6
- margin-inline: auto;
7
- padding: 12px;
8
- border: 1px solid var(--ds-grey-200, #ededed);
9
- border-radius: var(--ds-radius-200, 8px);
10
11
  }
11
12
 
12
- .title {
13
+ /* Base commune carte offre + carte "Ajouter" */
14
+ :is(.add, .widgetButton) {
15
+ width: 100%;
16
+ min-height: 150px;
13
17
  display: flex;
18
+ flex-direction: column;
14
19
  align-items: center;
20
+ justify-content: center;
15
21
  gap: 6px;
16
- margin-bottom: 8px;
17
- font-size: 18px;
22
+ padding: 12px 10px;
23
+ text-align: center;
24
+ font-size: 14px;
25
+ background-color: var(--ds-grey-000, #fff);
26
+ border: 1px solid var(--ds-grey-200, #ededed);
27
+ border-radius: var(--ds-radius-200, 8px);
28
+ box-shadow: none;
29
+ transition: border-color 160ms
30
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9)),
31
+ background-color 160ms
32
+ var(--ds-transition-easing, cubic-bezier(0.4, 0.1, 0.2, 0.9));
33
+ }
34
+
35
+ .widgetButton {
36
+ flex: 1;
37
+ height: 100%;
38
+ justify-content: center;
39
+ }
40
+
41
+ .widgetButton:is(:hover, :focus-visible) {
42
+ border-color: var(--ds-grey-300, #d7d7d7);
43
+ }
44
+
45
+ /* Picto : logo d'offre, image marketing, ou repli icône */
46
+ :is(.add, .widgetButton) > svg {
47
+ --size: 28px;
48
+
49
+ color: var(--ds-grey-400, #949494);
50
+ }
51
+
52
+ .widgetButton img.logo {
53
+ width: 38px;
54
+ height: 38px;
55
+ object-fit: contain;
56
+ }
57
+
58
+ .step {
59
+ font-size: 11px;
60
+ font-weight: 600;
61
+ letter-spacing: 0.04em;
62
+ text-transform: uppercase;
63
+ color: var(--ds-grey-500, #7c7b7b);
64
+ }
65
+
66
+ .widgetTitle {
67
+ font-size: 15px;
18
68
  font-weight: 700;
69
+ line-height: 1.25;
70
+ display: -webkit-box;
71
+ -webkit-line-clamp: 2;
72
+ -webkit-box-orient: vertical;
73
+ overflow: hidden;
19
74
  }
20
75
 
21
- .title > svg {
22
- flex: 0 0 22px;
23
- height: 22px;
24
- fill: currentcolor;
76
+ .widgetTagline {
77
+ font-size: 12px;
78
+ font-weight: 400;
79
+ line-height: 1.3;
80
+ color: var(--ds-grey-500, #7c7b7b);
81
+ display: -webkit-box;
82
+ -webkit-line-clamp: 2;
83
+ -webkit-box-orient: vertical;
84
+ overflow: hidden;
25
85
  }
26
86
 
27
- .widgets {
28
- display: grid;
29
- grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
30
- gap: 8px;
87
+ /* Carte "Ajouter" : pointillés + accent */
88
+ .add {
89
+ gap: 6px;
90
+ color: var(--ds-secondary, var(--ds-primary, #002dcc));
91
+ font-weight: 700;
92
+ background-color: transparent;
93
+ border-style: dashed;
94
+ border-color: var(--ds-grey-300, #d7d7d7);
31
95
  }
32
96
 
33
- .widget {
34
- position: relative;
97
+ .add > svg {
98
+ --size: 22px;
99
+
100
+ color: currentcolor;
35
101
  }
36
102
 
103
+ .add:is(:hover, :focus-visible) {
104
+ color: var(--ds-secondary, var(--ds-primary, #002dcc));
105
+ border-color: var(--ds-secondary, var(--ds-primary, #002dcc));
106
+ background-color: var(--ds-grey-100, #f8f8f8);
107
+ }
108
+
109
+ /* Bouton "Supprimer" (apparaît au survol, haut-droite) */
37
110
  .remove {
38
111
  position: absolute;
39
112
  top: 10px;
@@ -62,29 +135,7 @@
62
135
  pointer-events: auto;
63
136
  }
64
137
 
65
- :is(.add, .widgetButton) {
66
- width: 100%;
67
- flex-direction: column;
68
- padding: 50px 10px;
69
- font-size: 18px;
70
- border-radius: var(--ds-radius-200, 8px);
71
- }
72
-
73
- :is(.add, .widgetButton) > svg {
74
- --size: 40px;
75
- }
76
-
77
- .widgetButton img {
78
- width: 80px;
79
- height: auto;
80
- border-radius: var(--ds-radius-100, 4px);
81
- }
82
-
83
- .widgetTagline {
84
- font-size: 13px;
85
- font-weight: 400;
86
- }
87
-
138
+ /* Contrôles de réordonnancement (apparaissent au survol, en bas) */
88
139
  .controls {
89
140
  position: absolute;
90
141
  bottom: 0;