mautourco-components 0.2.76 → 0.2.78

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.
@@ -162,11 +162,42 @@
162
162
  opacity: 0.6;
163
163
  }
164
164
 
165
- .chip--clickable:focus {
165
+ /* Focus styles - specific to each color */
166
+ .chip--clickable.chip--brand:focus {
166
167
  outline: 2px solid var(--chip-color-brand-outline-foreground, #ed4c09);
167
168
  outline-offset: 2px;
168
169
  }
169
170
 
171
+ .chip--clickable.chip--accent:focus {
172
+ outline: 2px solid var(--chip-color-accent-outline-foreground, #0f7173);
173
+ outline-offset: 2px;
174
+ }
175
+
176
+ .chip--clickable.chip--blue:focus {
177
+ outline: 2px solid var(--chip-color-blue-outline-foreground, #2e4780);
178
+ outline-offset: 2px;
179
+ }
180
+
181
+ .chip--clickable.chip--green:focus {
182
+ outline: 2px solid var(--chip-color-green-outline-foreground, #4a6045);
183
+ outline-offset: 2px;
184
+ }
185
+
186
+ .chip--clickable.chip--yellow:focus {
187
+ outline: 2px solid var(--chip-color-yellow-outline-foreground, #eab308);
188
+ outline-offset: 2px;
189
+ }
190
+
191
+ .chip--clickable.chip--red:focus {
192
+ outline: 2px solid var(--chip-color-red-outline-foreground, #991b1b);
193
+ outline-offset: 2px;
194
+ }
195
+
196
+ .chip--clickable.chip--neutral:focus {
197
+ outline: 2px solid var(--chip-color-neutral-outline-foreground, #9ca3af);
198
+ outline-offset: 2px;
199
+ }
200
+
170
201
  .chip--outline.chip--black-text {
171
202
  color: var(--chip-color-neutral-outline-text, #262626);
172
203
  }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+
5
+ .vehicle-supplement {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: var(--spacing-gap-gap-6, 24px);
9
+ padding: var(--spacing-padding-px-0, 0px);
10
+ }
11
+
12
+ .vehicle-supplement__content {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: var(--spacing-gap-gap-4, 16px);
16
+ }
17
+
18
+ .vehicle-supplement__transfer-section {
19
+ display: flex;
20
+ flex-direction: column;
21
+ gap: var(--spacing-gap-gap-4, 16px);
22
+ }
23
+
24
+ .vehicle-supplement__transfer-header {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: space-between;
28
+ height: 44px;
29
+ padding: var(--spacing-gap-gap-0, 0px);
30
+ }
31
+
32
+ .vehicle-supplement__transfer-title {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: var(--spacing-gap-gap-2, 8px);
36
+ }
37
+
38
+ .vehicle-supplement__transfer-label {
39
+ font-family: var(--font-font-family-body, "Satoshi"), "Inter", "Segoe UI", "system-ui", sans-serif;
40
+ font-weight: var(--font-weight-font-bold, 700);
41
+ font-size: var(--font-size-text-base, 16px);
42
+ line-height: calc(var(--font-leading-leading-md, 24) * 1px);
43
+ color: var(--checkbox-color-label-default, #303642);
44
+ }
45
+
46
+ .vehicle-supplement__supplements-list {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: var(--spacing-gap-gap-3, 12px);
50
+ }
51
+
52
+ .vehicle-supplement__supplement-row {
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: space-between;
56
+ height: 32px;
57
+ padding: var(--spacing-padding-px-0, 0px);
58
+ }
59
+
60
+ .vehicle-supplement__supplement-name {
61
+ font-family: var(--font-font-family-body, "Satoshi"), "Inter", "Segoe UI", "system-ui", sans-serif;
62
+ font-weight: var(--font-weight-font-medium, 500);
63
+ font-size: var(--font-size-text-base, 16px);
64
+ line-height: calc(var(--font-leading-leading-md, 24) * 1px);
65
+ color: var(--checkbox-color-label-default, #303642);
66
+ }
67
+
68
+ .vehicle-supplement__divider {
69
+ width: 100%;
70
+ height: 0;
71
+ border-top: 1px solid var(--color-border-default, #d9d9d9);
72
+ }
73
+
74
+ .vehicle-supplement__footer {
75
+ display: flex;
76
+ align-items: center;
77
+ justify-content: flex-end;
78
+ gap: var(--spacing-gap-gap-4, 16px);
79
+ height: 36px;
80
+ }
81
+
82
+ .vehicle-supplement__cancel-button,
83
+ .vehicle-supplement__done-button {
84
+ min-width: 114px;
85
+ }
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { TransferDocket } from '../../../types/docket/services.types';
3
+ import './VehicleSupplement.css';
4
+ export interface Supplement {
5
+ supplement_name: string;
6
+ max?: number;
7
+ min?: number;
8
+ }
9
+ export interface SupplementValue {
10
+ transferId: number;
11
+ supplementName: string;
12
+ value: number;
13
+ }
14
+ export interface VehicleSupplementProps {
15
+ /** Array of available supplements */
16
+ supplements: Supplement[];
17
+ /** Array of transfers (Arrival, Inter-Hotel, Departure) */
18
+ transfer: TransferDocket[];
19
+ /** Handler called when supplement values change */
20
+ onChange: (values: SupplementValue[]) => void;
21
+ /** Handler called when Done button is clicked */
22
+ onDone: (values: SupplementValue[]) => void;
23
+ /** Handler called when Clear/Cancel button is clicked */
24
+ onClear: () => void;
25
+ /** Initial values for the supplements (optional) */
26
+ initialValues?: SupplementValue[];
27
+ /** Additional CSS classes */
28
+ className?: string;
29
+ }
30
+ declare const VehicleSupplement: React.FC<VehicleSupplementProps>;
31
+ export default VehicleSupplement;
@@ -0,0 +1,101 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ import { useState } from 'react';
14
+ import Button from '../../atoms/Button/Button';
15
+ import Chip from '../../atoms/Chip/Chip';
16
+ import Icon from '../../atoms/Icon/Icon';
17
+ import Stepper from '../Stepper/Stepper';
18
+ import './VehicleSupplement.css';
19
+ var VehicleSupplement = function (_a) {
20
+ var supplements = _a.supplements, transfer = _a.transfer, onChange = _a.onChange, onDone = _a.onDone, onClear = _a.onClear, _b = _a.initialValues, initialValues = _b === void 0 ? [] : _b, _c = _a.className, className = _c === void 0 ? '' : _c;
21
+ // Initialize state for all supplements across all transfers
22
+ var _d = useState(function () {
23
+ // If initial values are provided, use them
24
+ if (initialValues.length > 0) {
25
+ return initialValues;
26
+ }
27
+ // Otherwise, create default values with 0
28
+ var defaultValues = [];
29
+ transfer.forEach(function (t) {
30
+ supplements.forEach(function (s) {
31
+ defaultValues.push({
32
+ transferId: t.IdTransfer,
33
+ supplementName: s.supplement_name,
34
+ value: 0,
35
+ });
36
+ });
37
+ });
38
+ return defaultValues;
39
+ }), supplementValues = _d[0], setSupplementValues = _d[1];
40
+ var getValue = function (transferId, supplementName) {
41
+ var item = supplementValues.find(function (v) { return v.transferId === transferId && v.supplementName === supplementName; });
42
+ return (item === null || item === void 0 ? void 0 : item.value) || 0;
43
+ };
44
+ var handleSupplementChange = function (transferId, supplementName, newValue) {
45
+ var updatedValues = supplementValues.map(function (v) {
46
+ return v.transferId === transferId && v.supplementName === supplementName
47
+ ? __assign(__assign({}, v), { value: newValue }) : v;
48
+ });
49
+ setSupplementValues(updatedValues);
50
+ onChange(updatedValues);
51
+ };
52
+ var getTransferTypeIcon = function (transferType) {
53
+ var type = transferType.toLowerCase();
54
+ if (type.includes('arrival') || type.includes('airport') || type.includes('inbound')) {
55
+ return 'plane-landing-outline';
56
+ }
57
+ if (type.includes('departure') || type.includes('outbound')) {
58
+ return 'plane-takeoff-outline';
59
+ }
60
+ return 'building-2-outline';
61
+ };
62
+ var getTransferTypeLabel = function (transferType) {
63
+ var type = transferType.toLowerCase();
64
+ if (type.includes('arrival') || type.includes('airport') || type.includes('inbound')) {
65
+ return 'Arrival';
66
+ }
67
+ if (type.includes('departure') || type.includes('outbound')) {
68
+ return 'Departure';
69
+ }
70
+ return 'Inter-Hotel';
71
+ };
72
+ var formatDate = function (dateStr) {
73
+ try {
74
+ var date = new Date(dateStr);
75
+ var day = String(date.getDate()).padStart(2, '0');
76
+ var month = String(date.getMonth() + 1).padStart(2, '0');
77
+ var year = date.getFullYear();
78
+ return "".concat(day, "/").concat(month, "/").concat(year);
79
+ }
80
+ catch (_a) {
81
+ return dateStr;
82
+ }
83
+ };
84
+ var handleDone = function () {
85
+ onDone(supplementValues);
86
+ };
87
+ var baseClass = 'vehicle-supplement';
88
+ var classes = [baseClass, className].filter(Boolean).join(' ');
89
+ return (_jsxs("div", { className: classes, children: [_jsx("div", { className: "".concat(baseClass, "__content"), children: transfer.map(function (t, index) {
90
+ var isLast = index === transfer.length - 1;
91
+ var typeLabel = getTransferTypeLabel(t.TransferType);
92
+ var iconName = getTransferTypeIcon(t.TransferType);
93
+ return (_jsxs("div", { className: "".concat(baseClass, "__transfer-section"), children: [_jsxs("div", { className: "".concat(baseClass, "__transfer-header"), children: [_jsxs("div", { className: "".concat(baseClass, "__transfer-title"), children: [_jsx(Icon, { name: iconName, size: "sm" }), _jsx("span", { className: "".concat(baseClass, "__transfer-label"), children: typeLabel })] }), _jsx(Chip, { leadingIcon: "calendar", label: formatDate(t.TransferDate), size: "sm", color: "neutral", isBlackText: true })] }), _jsx("div", { className: "".concat(baseClass, "__supplements-list"), children: supplements.map(function (supplement) {
94
+ var currentValue = getValue(t.IdTransfer, supplement.supplement_name);
95
+ return (_jsxs("div", { className: "".concat(baseClass, "__supplement-row"), children: [_jsx("span", { className: "".concat(baseClass, "__supplement-name"), children: supplement.supplement_name }), _jsx(Stepper, { value: currentValue, min: supplement.min || 0, max: supplement.max || 99, onChange: function (value) {
96
+ return handleSupplementChange(t.IdTransfer, supplement.supplement_name, value);
97
+ } })] }, supplement.supplement_name));
98
+ }) }), !isLast && _jsx("div", { className: "".concat(baseClass, "__divider") })] }, t.IdTransfer));
99
+ }) }), _jsxs("div", { className: "".concat(baseClass, "__footer"), children: [_jsx(Button, { variant: "outline-secondary", size: "sm", onClick: onClear, className: "".concat(baseClass, "__cancel-button"), children: "Cancel" }), _jsx(Button, { variant: "secondary", size: "sm", onClick: handleDone, className: "".concat(baseClass, "__done-button"), children: "Done" })] })] }));
100
+ };
101
+ export default VehicleSupplement;
@@ -0,0 +1,2 @@
1
+ export { default } from './VehicleSupplement';
2
+ export type { VehicleSupplementProps, Supplement, SupplementValue } from './VehicleSupplement';
@@ -0,0 +1 @@
1
+ export { default } from './VehicleSupplement';
@@ -137,12 +137,15 @@
137
137
 
138
138
  .car-booking-card__supplement-message {
139
139
  margin: 0;
140
- color: var(--color-messaging-danger-foreground, #a01414);
141
140
  white-space: normal;
142
141
  text-align: right;
143
142
  flex: 1 1 auto;
144
143
  }
145
144
 
145
+ .car-booking-card__supplement-header .car-booking-card__supplement-message--error {
146
+ color: var(--color-messaging-danger-foreground, #a01414);
147
+ }
148
+
146
149
  .car-booking-card__section--supplement {
147
150
  /* Control spacing precisely: divider -> header != header -> select */
148
151
  gap: 0;
@@ -247,4 +250,122 @@
247
250
 
248
251
  .car-booking-card__cta {
249
252
  white-space: nowrap;
253
+ }
254
+
255
+ /* Supplement dropdown styles */
256
+ .car-booking-card__supplement-dropdown {
257
+ position: relative;
258
+ width: 100%;
259
+ }
260
+
261
+ .car-booking-card__supplement-trigger {
262
+ width: 100%;
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: space-between;
266
+ gap: var(--spacing-gap-gap-2, 8px);
267
+ padding: var(--spacing-padding-py-3, 12px) var(--spacing-padding-px-4, 16px);
268
+ background: var(--color-elevation-level-1, #ffffff);
269
+ border: var(--input-border-width-default, 1px) solid var(--color-border-default, #d4d4d4);
270
+ border-radius: var(--border-radius-rounded-xl, 12px);
271
+ font-family: var(--font-font-family-body, "Satoshi"), "Inter", "Segoe UI", "system-ui", sans-serif;
272
+ font-size: var(--font-size-text-base, 16px);
273
+ line-height: calc(var(--font-leading-leading-md, 24) * 1px);
274
+ color: var(--color-text-default, #262626);
275
+ cursor: pointer;
276
+ transition: border-color 0.2s ease, background-color 0.2s ease;
277
+ min-height: 48px;
278
+ }
279
+
280
+ .car-booking-card__supplement-trigger:hover:not(:disabled) {
281
+ border-color: var(--color-border-active-default, #0f7173);
282
+ }
283
+
284
+ .car-booking-card__supplement-trigger:focus {
285
+ outline: var(--border-width-focus, 2px) solid var(--color-border-active-default, #0f7173);
286
+ outline-offset: var(--spacing-base-0-5, 2px);
287
+ }
288
+
289
+ .car-booking-card__supplement-trigger--disabled {
290
+ background: var(--color-elevation-level-2, #f5f5f5);
291
+ cursor: not-allowed;
292
+ opacity: 0.6;
293
+ }
294
+
295
+ .car-booking-card__supplement-placeholder {
296
+ color: var(--color-text-subtle, #737373);
297
+ font-weight: var(--font-weight-font-regular, 400);
298
+ }
299
+
300
+ .car-booking-card__supplement-trigger--has-value .car-booking-card__supplement-placeholder {
301
+ color: var(--color-text-default, #262626);
302
+ }
303
+
304
+ .car-booking-card__supplement-chips {
305
+ display: flex;
306
+ flex-wrap: wrap;
307
+ gap: var(--spacing-gap-gap-2, 8px);
308
+ flex: 1;
309
+ align-items: center;
310
+ }
311
+
312
+ /* Ensure chips are properly interactive within the button */
313
+ .car-booking-card__supplement-chips .chip {
314
+ cursor: pointer;
315
+ transition: opacity 0.15s ease, transform 0.15s ease;
316
+ -webkit-user-select: none;
317
+ user-select: none;
318
+ }
319
+
320
+ /* Hover state for chips - subtle scale and opacity change */
321
+ .car-booking-card__supplement-chips .chip:hover {
322
+ opacity: 0.85;
323
+ transform: translateY(-1px);
324
+ }
325
+
326
+ /* Active/pressed state for chips */
327
+ .car-booking-card__supplement-chips .chip:active {
328
+ opacity: 0.7;
329
+ transform: translateY(0);
330
+ }
331
+
332
+ /* Make close icon more prominent on chip hover */
333
+ .car-booking-card__supplement-chips .chip:hover .chip__icon--trailing {
334
+ opacity: 1;
335
+ transform: scale(1.1);
336
+ }
337
+
338
+ /* Transition for chip icons */
339
+ .car-booking-card__supplement-chips .chip .chip__icon--trailing {
340
+ transition: transform 0.15s ease, opacity 0.15s ease;
341
+ opacity: 0.8;
342
+ }
343
+
344
+ .car-booking-card__supplement-icon {
345
+ transition: transform 0.2s ease;
346
+ flex-shrink: 0;
347
+ }
348
+
349
+ .car-booking-card__supplement-icon--open {
350
+ transform: rotate(180deg);
351
+ }
352
+
353
+ .car-booking-card__supplement-panel {
354
+ position: absolute;
355
+ top: calc(100% + var(--spacing-gap-gap-2, 8px));
356
+ left: 0;
357
+ right: 0;
358
+ z-index: 10;
359
+ background: var(--color-elevation-level-1, #ffffff);
360
+ border-radius: var(--border-radius-rounded-xl, 12px);
361
+ box-shadow:
362
+ var(--spacing-base-0, 0px) var(--spacing-base-1, 4px)
363
+ var(--backdrop-blur-backdrop-blur, 8px) var(--spacing-base-0, 0px)
364
+ rgba(48, 54, 66, 0.1),
365
+ var(--spacing-base-0, 0px) var(--spacing-base-px, 1px)
366
+ var(--backdrop-blur-backdrop-blur, 8px) var(--spacing-base-0, 0px)
367
+ rgba(48, 54, 66, 0.11);
368
+ padding: var(--spacing-padding-py-6, 24px);
369
+ max-height: 600px;
370
+ overflow-y: auto;
250
371
  }
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
+ import { TransferDocket } from '../../../types/docket/services.types';
2
3
  import { ButtonProps } from '../../atoms/Button/Button';
3
4
  import { FeatureRowProps } from '../../molecules/FeatureRow/FeatureRow';
5
+ import { Supplement, SupplementValue } from '../../molecules/VehicleSupplement/VehicleSupplement';
4
6
  import './CarBookingCard.css';
5
7
  export type CarBookingCardSize = 'small' | 'large';
6
8
  export type CarBookingCardState = 'default' | 'selected' | 'hover';
@@ -30,21 +32,25 @@ export interface CarBookingCardProps {
30
32
  /** Supplement dropdown section */
31
33
  /** Whether to render the supplement section (matches Figma variants Supplement=Yes/No/-) */
32
34
  showSupplement?: boolean;
33
- /** Optional message shown in red next to the "Supplement" label (Figma: "Supplement is not available for this vehicle.") */
35
+ /** Optional message shown next to the "Supplement" label (Figma: "Supplement is not available for this vehicle.") */
34
36
  supplementMessage?: string;
37
+ /** State variant for the supplement message: 'error' applies danger/red styling, 'default' uses normal text color */
38
+ supplementMessageState?: 'default' | 'error';
35
39
  supplementLabel?: string;
36
40
  supplementPlaceholder?: string;
37
- supplementValue?: string;
38
- supplementState?: 'default' | 'loading' | 'selected' | 'error' | 'disabled';
39
- supplementOptions?: string[];
40
- onSupplementSelect?: (option: string) => void;
41
+ /** Array of available supplements */
42
+ supplements?: Supplement[];
43
+ /** Array of transfers for supplement selection */
44
+ transfers?: TransferDocket[];
45
+ /** Handler when supplements are selected */
46
+ onSupplementChange?: (values: SupplementValue[]) => void;
41
47
  /** Footer price */
42
48
  totalPrice: string;
43
49
  totalPriceLabel?: string;
44
50
  /** Footer CTA */
45
51
  ctaLabel: string;
46
52
  ctaButtonProps?: Omit<ButtonProps, 'children'>;
47
- onCtaClick?: ButtonProps['onClick'];
53
+ onCtaClick?: (event: React.MouseEvent<HTMLButtonElement>, supplements?: SupplementValue[]) => void;
48
54
  /** Readonly mode - disables interactions and shows values as text */
49
55
  readonly?: boolean;
50
56
  className?: string;
@@ -10,24 +10,95 @@ var __assign = (this && this.__assign) || function () {
10
10
  return __assign.apply(this, arguments);
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
- import { useState } from 'react';
13
+ import { useEffect, useRef, useState } from 'react';
14
14
  import Button from '../../atoms/Button/Button';
15
+ import Chip from '../../atoms/Chip/Chip';
15
16
  import Divider from '../../atoms/Divider/Divider';
16
- import DropdownInput from '../../atoms/Inputs/DropdownInput/DropdownInput';
17
+ import Icon from '../../atoms/Icon/Icon';
17
18
  import { Heading, Text } from '../../atoms/Typography/Typography';
18
19
  import FeatureRow from '../../molecules/FeatureRow/FeatureRow';
20
+ import VehicleSupplement from '../../molecules/VehicleSupplement/VehicleSupplement';
19
21
  import './CarBookingCard.css';
20
22
  var CarBookingCard = function (_a) {
21
23
  var _b;
22
- var imageSrc = _a.imageSrc, title = _a.title, _c = _a.size, size = _c === void 0 ? 'large' : _c, _d = _a.state, state = _d === void 0 ? 'default' : _d, _e = _a.type, type = _e === void 0 ? 'default' : _e, features = _a.features, infoText = _a.infoText, _f = _a.priceTitle, priceTitle = _f === void 0 ? 'Price breakdown' : _f, _g = _a.priceRows, priceRows = _g === void 0 ? [] : _g, showSupplement = _a.showSupplement, supplementMessage = _a.supplementMessage, _h = _a.supplementLabel, supplementLabel = _h === void 0 ? 'Supplement' : _h, _j = _a.supplementPlaceholder, supplementPlaceholder = _j === void 0 ? 'Select a supplement' : _j, supplementValue = _a.supplementValue, _k = _a.supplementState, supplementState = _k === void 0 ? 'default' : _k, _l = _a.supplementOptions, supplementOptions = _l === void 0 ? [] : _l, onSupplementSelect = _a.onSupplementSelect, totalPrice = _a.totalPrice, _m = _a.totalPriceLabel, totalPriceLabel = _m === void 0 ? 'Total price' : _m, ctaLabel = _a.ctaLabel, ctaButtonProps = _a.ctaButtonProps, onCtaClick = _a.onCtaClick, _o = _a.readonly, readonly = _o === void 0 ? false : _o, _p = _a.className, className = _p === void 0 ? '' : _p;
23
- var _q = useState(state === 'selected'), isSelected = _q[0], setIsSelected = _q[1];
24
- var _r = useState(false), isHovered = _r[0], setIsHovered = _r[1];
25
- var resolvedShowSupplement = showSupplement !== null && showSupplement !== void 0 ? showSupplement : Boolean(supplementLabel || supplementPlaceholder || supplementOptions.length > 0);
26
- var resolvedSupplementState = supplementMessage ? 'disabled' : supplementState;
27
- // Handle CTA click: toggle between "Add to quote" and "Selected"
24
+ var imageSrc = _a.imageSrc, title = _a.title, _c = _a.size, size = _c === void 0 ? 'large' : _c, _d = _a.state, state = _d === void 0 ? 'default' : _d, _e = _a.type, type = _e === void 0 ? 'default' : _e, features = _a.features, infoText = _a.infoText, _f = _a.priceTitle, priceTitle = _f === void 0 ? 'Price breakdown' : _f, _g = _a.priceRows, priceRows = _g === void 0 ? [] : _g, showSupplement = _a.showSupplement, supplementMessage = _a.supplementMessage, _h = _a.supplementMessageState, supplementMessageState = _h === void 0 ? 'error' : _h, _j = _a.supplementLabel, supplementLabel = _j === void 0 ? 'Supplement' : _j, _k = _a.supplementPlaceholder, supplementPlaceholder = _k === void 0 ? 'Select a supplement' : _k, _l = _a.supplements, supplements = _l === void 0 ? [] : _l, _m = _a.transfers, transfers = _m === void 0 ? [] : _m, onSupplementChange = _a.onSupplementChange, totalPrice = _a.totalPrice, _o = _a.totalPriceLabel, totalPriceLabel = _o === void 0 ? 'Total price' : _o, ctaLabel = _a.ctaLabel, ctaButtonProps = _a.ctaButtonProps, onCtaClick = _a.onCtaClick, _p = _a.readonly, readonly = _p === void 0 ? false : _p, _q = _a.className, className = _q === void 0 ? '' : _q;
25
+ var _r = useState(state === 'selected'), isSelected = _r[0], setIsSelected = _r[1];
26
+ var _s = useState(false), isHovered = _s[0], setIsHovered = _s[1];
27
+ var _t = useState(false), isSupplementOpen = _t[0], setIsSupplementOpen = _t[1];
28
+ var _u = useState([]), selectedSupplements = _u[0], setSelectedSupplements = _u[1];
29
+ var dropdownRef = useRef(null);
30
+ var panelRef = useRef(null);
31
+ var resolvedShowSupplement = showSupplement !== null && showSupplement !== void 0 ? showSupplement : Boolean(supplements.length > 0 && transfers.length > 0);
32
+ var hasSupplementsSelected = selectedSupplements.some(function (s) { return s.value > 0; });
33
+ // Close dropdown when clicking outside
34
+ useEffect(function () {
35
+ var handleClickOutside = function (event) {
36
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
37
+ setIsSupplementOpen(false);
38
+ }
39
+ };
40
+ if (isSupplementOpen) {
41
+ document.addEventListener('mousedown', handleClickOutside);
42
+ }
43
+ return function () {
44
+ document.removeEventListener('mousedown', handleClickOutside);
45
+ };
46
+ }, [isSupplementOpen]);
47
+ // Auto-scroll to panel when opened
48
+ useEffect(function () {
49
+ if (isSupplementOpen && panelRef.current) {
50
+ // Small delay to ensure the panel is rendered
51
+ setTimeout(function () {
52
+ var _a;
53
+ (_a = panelRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({
54
+ behavior: 'smooth',
55
+ block: 'nearest',
56
+ });
57
+ }, 100);
58
+ }
59
+ }, [isSupplementOpen]);
60
+ var getSupplementSummary = function () {
61
+ var summary = [];
62
+ var grouped = selectedSupplements.reduce(function (acc, item) {
63
+ if (item.value > 0) {
64
+ if (!acc[item.supplementName]) {
65
+ acc[item.supplementName] = 0;
66
+ }
67
+ acc[item.supplementName] += item.value;
68
+ }
69
+ return acc;
70
+ }, {});
71
+ Object.entries(grouped).forEach(function (_a) {
72
+ var name = _a[0], count = _a[1];
73
+ summary.push("".concat(name, " x").concat(count));
74
+ });
75
+ return summary;
76
+ };
77
+ var handleSupplementDone = function (values) {
78
+ setSelectedSupplements(values);
79
+ setIsSupplementOpen(false);
80
+ onSupplementChange === null || onSupplementChange === void 0 ? void 0 : onSupplementChange(values);
81
+ };
82
+ var handleSupplementClear = function () {
83
+ setIsSupplementOpen(false);
84
+ };
85
+ var handleSupplementToggle = function () {
86
+ if (!supplementMessage) {
87
+ setIsSupplementOpen(!isSupplementOpen);
88
+ }
89
+ };
90
+ var handleRemoveSupplement = function (supplementName) {
91
+ var updatedValues = selectedSupplements.map(function (s) {
92
+ return s.supplementName === supplementName ? __assign(__assign({}, s), { value: 0 }) : s;
93
+ });
94
+ setSelectedSupplements(updatedValues);
95
+ onSupplementChange === null || onSupplementChange === void 0 ? void 0 : onSupplementChange(updatedValues);
96
+ };
97
+ // Handle CTA click: toggle between "Add to quote" and "Selected" and pass supplement data
28
98
  var handleCtaClick = function (e) {
29
99
  setIsSelected(!isSelected);
30
- onCtaClick === null || onCtaClick === void 0 ? void 0 : onCtaClick(e);
100
+ // Pass the selected supplements to the parent component
101
+ onCtaClick === null || onCtaClick === void 0 ? void 0 : onCtaClick(e, selectedSupplements.length > 0 ? selectedSupplements : undefined);
31
102
  };
32
103
  // Determine button state based on selection and hover
33
104
  var shouldShowRemove = isSelected && isHovered;
@@ -71,6 +142,12 @@ var CarBookingCard = function (_a) {
71
142
  return (_jsxs("article", { className: classes, children: [_jsx("div", { className: "car-booking-card__image-wrap", children: _jsx("img", { className: "car-booking-card__image", src: imageSrc, alt: "" }) }), _jsx("div", { className: "car-booking-card__active-divider" }), _jsxs("div", { className: "car-booking-card__body", children: [_jsxs("section", { className: "car-booking-card__section car-booking-card__section--content", children: [_jsxs("div", { className: "car-booking-card__title", children: [_jsx("span", { className: "car-booking-card__title-marker", "aria-hidden": "true" }), _jsx(Heading, { level: 4, variant: "bold", color: "accent", className: "car-booking-card__title-text", children: title })] }), _jsx("div", { className: "car-booking-card__features", children: features.map(function (feature, idx) {
72
143
  var _a;
73
144
  return (_jsx(FeatureRow, __assign({}, feature, { className: "car-booking-card__feature-row ".concat((_a = feature.className) !== null && _a !== void 0 ? _a : '').trim() }), "".concat(feature.label, "-").concat(idx)));
74
- }) }), infoText && !readonly && (_jsxs("div", { className: "car-booking-card__info", children: [_jsx("span", { className: "car-booking-card__info-icon", "aria-hidden": "true", children: "i" }), _jsx(Text, { size: "sm", leading: "5", variant: "regular", color: "default", className: "car-booking-card__info-text", children: infoText })] }))] }), resolvedShowSupplement && !readonly && (_jsxs("section", { className: "car-booking-card__section car-booking-card__section--supplement", children: [_jsx(Divider, { variant: "dashed", className: "car-booking-card__dashed-divider" }), _jsxs("div", { className: "car-booking-card__supplement-header", children: [_jsx(Text, { as: "h3", size: "md", variant: "bold", leading: "none", color: "default", className: "car-booking-card__section-title", children: supplementLabel }), supplementMessage && (_jsx(Text, { as: "p", size: "sm", leading: "5", variant: "regular", className: "car-booking-card__supplement-message", children: supplementMessage }))] }), readonly ? (_jsx(Text, { size: "sm", leading: "5", variant: "regular", color: supplementValue ? "default" : "subtle", className: "car-booking-card__supplement-value", children: supplementValue || supplementPlaceholder })) : (_jsx(DropdownInput, { placeholder: supplementPlaceholder, value: supplementValue, state: resolvedSupplementState, options: supplementOptions, onSelect: onSupplementSelect }))] })), priceRows.length > 0 && !readonly && (_jsxs("section", { className: "car-booking-card__section car-booking-card__section--price", children: [_jsx(Divider, { variant: "dashed", className: "car-booking-card__dashed-divider" }), _jsxs("div", { className: "car-booking-card__price-content", children: [_jsx(Text, { as: "h3", size: "md", variant: "bold", leading: "none", color: "default", className: "car-booking-card__section-title", children: priceTitle }), _jsx("div", { className: "car-booking-card__price-rows", children: priceRows.map(function (row, idx) { return (_jsxs("div", { className: "car-booking-card__price-row", children: [_jsx(Text, { size: "sm", leading: "5", variant: "regular", color: "subtle", className: "car-booking-card__price-label", children: row.label }), _jsx(Text, { size: "sm", leading: "5", variant: "bold", color: "subtle", className: "car-booking-card__price-value", children: row.value })] }, "".concat(row.label, "-").concat(idx))); }) })] }), _jsx(Divider, { variant: "dashed", className: "car-booking-card__dashed-divider" })] })), !readonly && _jsxs("footer", { className: "car-booking-card__footer", children: [_jsxs("div", { className: "car-booking-card__total", children: [_jsx(Text, { size: "base", variant: "bold", color: "accent", className: "car-booking-card__total-price", children: totalPrice }), _jsx(Text, { size: "sm", variant: "regular", color: "subtle", className: "car-booking-card__total-label", children: totalPriceLabel })] }), !readonly && (_jsx("div", { onMouseEnter: function () { return setIsHovered(true); }, onMouseLeave: function () { return setIsHovered(false); }, className: "car-booking-card__cta-wrapper", children: _jsx(Button, __assign({}, resolvedCtaButtonProps, { onClick: handleCtaClick, className: "car-booking-card__cta ".concat((_b = resolvedCtaButtonProps === null || resolvedCtaButtonProps === void 0 ? void 0 : resolvedCtaButtonProps.className) !== null && _b !== void 0 ? _b : '').trim(), children: resolvedCtaLabel })) }))] })] })] }));
145
+ }) }), infoText && !readonly && (_jsxs("div", { className: "car-booking-card__info", children: [_jsx("span", { className: "car-booking-card__info-icon", "aria-hidden": "true", children: "i" }), _jsx(Text, { size: "sm", leading: "5", variant: "regular", color: "default", className: "car-booking-card__info-text", children: infoText })] }))] }), resolvedShowSupplement && !readonly && (_jsxs("section", { className: "car-booking-card__section car-booking-card__section--supplement", children: [_jsx(Divider, { variant: "dashed", className: "car-booking-card__dashed-divider" }), _jsxs("div", { className: "car-booking-card__supplement-header", children: [_jsx(Text, { as: "h3", size: "md", variant: "bold", leading: "none", color: "default", className: "car-booking-card__section-title", children: supplementLabel }), supplementMessage && (_jsx(Text, { as: "p", size: "sm", leading: "5", variant: "regular", className: "car-booking-card__supplement-message ".concat(supplementMessageState === 'error' ? 'car-booking-card__supplement-message--error' : '').trim(), children: supplementMessage }))] }), _jsxs("div", { className: "car-booking-card__supplement-dropdown", ref: dropdownRef, children: [_jsxs("button", { type: "button", className: "car-booking-card__supplement-trigger ".concat(hasSupplementsSelected ? 'car-booking-card__supplement-trigger--has-value' : '', " ").concat(supplementMessage ? 'car-booking-card__supplement-trigger--disabled' : ''), onClick: handleSupplementToggle, disabled: Boolean(supplementMessage), children: [hasSupplementsSelected ? (_jsx("div", { className: "car-booking-card__supplement-chips", children: getSupplementSummary().map(function (summary, idx) {
146
+ var name = summary.split(' x')[0];
147
+ return (_jsx(Chip, { label: summary, size: "sm", color: "accent", trailingIcon: "close", onClick: function (e) {
148
+ e.stopPropagation();
149
+ handleRemoveSupplement(name);
150
+ } }, idx));
151
+ }) })) : (_jsx("span", { className: "car-booking-card__supplement-placeholder", children: supplementPlaceholder })), _jsx(Icon, { name: "chevron-down", size: "sm", className: "car-booking-card__supplement-icon ".concat(isSupplementOpen ? 'car-booking-card__supplement-icon--open' : '') })] }), isSupplementOpen && (_jsx("div", { className: "car-booking-card__supplement-panel", ref: panelRef, children: _jsx(VehicleSupplement, { supplements: supplements, transfer: transfers, initialValues: selectedSupplements, onChange: function () { }, onDone: handleSupplementDone, onClear: handleSupplementClear }) }))] })] })), priceRows.length > 0 && !readonly && (_jsxs("section", { className: "car-booking-card__section car-booking-card__section--price", children: [_jsx(Divider, { variant: "dashed", className: "car-booking-card__dashed-divider" }), _jsxs("div", { className: "car-booking-card__price-content", children: [_jsx(Text, { as: "h3", size: "md", variant: "bold", leading: "none", color: "default", className: "car-booking-card__section-title", children: priceTitle }), _jsx("div", { className: "car-booking-card__price-rows", children: priceRows.map(function (row, idx) { return (_jsxs("div", { className: "car-booking-card__price-row", children: [_jsx(Text, { size: "sm", leading: "5", variant: "regular", color: "subtle", className: "car-booking-card__price-label", children: row.label }), _jsx(Text, { size: "sm", leading: "5", variant: "bold", color: "subtle", className: "car-booking-card__price-value", children: row.value })] }, "".concat(row.label, "-").concat(idx))); }) })] }), _jsx(Divider, { variant: "dashed", className: "car-booking-card__dashed-divider" })] })), !readonly && _jsxs("footer", { className: "car-booking-card__footer", children: [_jsxs("div", { className: "car-booking-card__total", children: [_jsx(Text, { size: "base", variant: "bold", color: "accent", className: "car-booking-card__total-price", children: totalPrice }), _jsx(Text, { size: "sm", variant: "regular", color: "subtle", className: "car-booking-card__total-label", children: totalPriceLabel })] }), !readonly && (_jsx("div", { onMouseEnter: function () { return setIsHovered(true); }, onMouseLeave: function () { return setIsHovered(false); }, className: "car-booking-card__cta-wrapper", children: _jsx(Button, __assign({}, resolvedCtaButtonProps, { onClick: handleCtaClick, className: "car-booking-card__cta ".concat((_b = resolvedCtaButtonProps === null || resolvedCtaButtonProps === void 0 ? void 0 : resolvedCtaButtonProps.className) !== null && _b !== void 0 ? _b : '').trim(), children: resolvedCtaLabel })) }))] })] })] }));
75
152
  };
76
153
  export default CarBookingCard;
package/dist/index.d.ts CHANGED
@@ -39,6 +39,8 @@ export { ServiceLanguages } from './components/molecules/ServiceLanguages/Servic
39
39
  export { default as ServiceSelector } from './components/molecules/ServiceSelector/ServiceSelector';
40
40
  export { default as Stepper } from './components/molecules/Stepper/Stepper';
41
41
  export { default as TextWithIcon } from './components/molecules/TextWithIcon/TextWithIcon';
42
+ export { default as VehicleSupplement } from './components/molecules/VehicleSupplement/VehicleSupplement';
43
+ export type { VehicleSupplementProps, Supplement, SupplementValue } from './components/molecules/VehicleSupplement';
42
44
  export { default as TimelineItem } from './components/molecules/TimelineItem/TimelineItem';
43
45
  export { default as Toast } from './components/molecules/Toast/Toast';
44
46
  export * from './components/molecules/TooltipDisplay/TooltipDisplay';
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ export { ServiceLanguages } from './components/molecules/ServiceLanguages/Servic
41
41
  export { default as ServiceSelector } from './components/molecules/ServiceSelector/ServiceSelector';
42
42
  export { default as Stepper } from './components/molecules/Stepper/Stepper';
43
43
  export { default as TextWithIcon } from './components/molecules/TextWithIcon/TextWithIcon';
44
+ export { default as VehicleSupplement } from './components/molecules/VehicleSupplement/VehicleSupplement';
44
45
  export { default as TimelineItem } from './components/molecules/TimelineItem/TimelineItem';
45
46
  export { default as Toast } from './components/molecules/Toast/Toast';
46
47
  export * from './components/molecules/TooltipDisplay/TooltipDisplay';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mautourco-components",
3
- "version": "0.2.76",
3
+ "version": "0.2.78",
4
4
  "private": false,
5
5
  "description": "Bibliothèque de composants Mautourco pour le redesign",
6
6
  "main": "dist/index.js",