mautourco-components 0.2.28 → 0.2.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/dist/components/atoms/Icon/icons/BadgeAlertIcon.d.ts +4 -0
- package/dist/components/atoms/Icon/icons/BadgeAlertIcon.js +36 -0
- package/dist/components/atoms/Icon/icons/registry.d.ts +1 -0
- package/dist/components/atoms/Icon/icons/registry.js +2 -0
- package/dist/components/molecules/AccomodationDocket/AccomodationDocket.d.ts +5 -1
- package/dist/components/molecules/AccomodationDocket/AccomodationDocket.js +4 -3
- package/dist/components/molecules/Calendar/CalendarInput.js +2 -1
- package/dist/components/molecules/DateDisplay/DateDisplay.d.ts +4 -0
- package/dist/components/molecules/DateDisplay/DateDisplay.js +3 -5
- package/dist/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.css +50 -0
- package/dist/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.d.ts +2 -0
- package/dist/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.js +3 -2
- package/dist/components/molecules/DialogContentPolicy/DialogCancellationAccom.d.ts +2 -0
- package/dist/components/molecules/DialogContentPolicy/DialogCancellationAccom.js +2 -2
- package/dist/components/molecules/DialogContentPolicy/DialogCancellationExcursion.d.ts +2 -0
- package/dist/components/molecules/DialogContentPolicy/DialogCancellationExcursion.js +2 -2
- package/dist/components/molecules/DialogContentPolicy/DialogCancellationList.d.ts +1 -0
- package/dist/components/molecules/DialogContentPolicy/DialogCancellationList.js +14 -11
- package/dist/components/molecules/ExcursionDocket/ExcursionDocket.d.ts +4 -0
- package/dist/components/molecules/ExcursionDocket/ExcursionDocket.js +3 -2
- package/dist/components/molecules/LocationDropdown/LocationDropdown.d.ts +2 -0
- package/dist/components/molecules/LocationDropdown/LocationDropdown.js +9 -3
- package/dist/components/molecules/OtherServiceDocket/OtherServiceDocket.d.ts +4 -0
- package/dist/components/molecules/OtherServiceDocket/OtherServiceDocket.js +3 -2
- package/dist/components/molecules/Toast/Toast.d.ts +25 -0
- package/dist/components/molecules/Toast/Toast.js +29 -0
- package/dist/components/molecules/Toast/index.d.ts +2 -0
- package/dist/components/molecules/Toast/index.js +1 -0
- package/dist/components/molecules/TransferDocket/TransferDocket.d.ts +4 -0
- package/dist/components/molecules/TransferDocket/TransferDocket.js +3 -2
- package/dist/components/organisms/CancelService/CancelPolicy.d.ts +29 -0
- package/dist/components/organisms/CancelService/CancelPolicy.js +19 -0
- package/dist/components/organisms/CancelService/CancelService.d.ts +14 -0
- package/dist/components/organisms/CancelService/CancelService.js +23 -0
- package/dist/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.css +2143 -0
- package/dist/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.d.ts +14 -0
- package/dist/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.js +35 -0
- package/dist/components/organisms/CancelService/FromList.d.ts +12 -0
- package/dist/components/organisms/CancelService/FromList.js +29 -0
- package/dist/components/organisms/CarBookingCard/CarBookingCard.css +13 -1
- package/dist/components/organisms/CarBookingCard/CarBookingCard.d.ts +2 -0
- package/dist/components/organisms/CarBookingCard/CarBookingCard.js +4 -3
- package/dist/components/organisms/CarBookingCard/CarBookingCardSkeleton.css +2334 -0
- package/dist/components/organisms/CarBookingCard/CarBookingCardSkeleton.d.ts +19 -0
- package/dist/components/organisms/CarBookingCard/CarBookingCardSkeleton.js +35 -0
- package/dist/components/organisms/CarBookingCard/index.d.ts +4 -2
- package/dist/components/organisms/CarBookingCard/index.js +2 -1
- package/dist/components/organisms/DateTimePicker/DateTimePicker.d.ts +8 -0
- package/dist/components/organisms/DateTimePicker/DateTimePicker.js +20 -7
- package/dist/components/organisms/Docket/Docket.d.ts +25 -2
- package/dist/components/organisms/Docket/Docket.js +18 -10
- package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +2 -0
- package/dist/components/organisms/PaxSelector/PaxSelector.js +11 -5
- package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +4 -2
- package/dist/components/organisms/RoundTrip/RoundTrip.js +21 -11
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +2 -2
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +51 -8
- package/dist/components/organisms/Table/Table.js +1 -1
- package/dist/components/organisms/Table/TableCell.d.ts +2 -1
- package/dist/components/organisms/Table/TableCell.js +2 -2
- package/dist/components/organisms/Table/columns/booking-cancel-service-columns.d.ts +5 -0
- package/dist/components/organisms/Table/columns/booking-cancel-service-columns.js +182 -0
- package/dist/components/organisms/Table/columns/detail-resume-columns.d.ts +3 -1
- package/dist/components/organisms/Table/columns/detail-resume-columns.js +5 -3
- package/dist/components/organisms/Table/columns/index.d.ts +6 -1
- package/dist/components/organisms/Table/columns/index.js +2 -0
- package/dist/components/organisms/TransferLine/TransferLine.d.ts +4 -2
- package/dist/components/organisms/TransferLine/TransferLine.js +18 -9
- package/dist/components/ui/popover.d.ts +1 -1
- package/dist/components/ui/popover.js +5 -3
- package/dist/index.d.ts +15 -14
- package/dist/index.js +2 -1
- package/dist/lib/utils.d.ts +21 -0
- package/dist/lib/utils.js +114 -0
- package/dist/styles/components/molecule/calendarInput.css +40 -5
- package/dist/styles/components/molecule/location-dropdown.css +7 -5
- package/dist/styles/components/molecule/toast.css +2185 -0
- package/dist/styles/components/organism/docket.css +7 -1
- package/dist/styles/components/organism/pax-selector.css +12 -1
- package/dist/styles/components/organism/round-trip.css +4 -0
- package/dist/styles/components/organism/transfer-line.css +5 -1
- package/package.json +1 -1
- package/src/components/atoms/Icon/icons/BadgeAlertIcon.tsx +44 -0
- package/src/components/atoms/Icon/icons/registry.tsx +2 -0
- package/src/components/molecules/AccomodationDocket/AccomodationDocket.tsx +26 -6
- package/src/components/molecules/Calendar/CalendarInput.tsx +5 -2
- package/src/components/molecules/DateDisplay/DateDisplay.tsx +7 -7
- package/src/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.css +27 -0
- package/src/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.tsx +12 -1
- package/src/components/molecules/DialogContentPolicy/DialogCancellationAccom.tsx +9 -2
- package/src/components/molecules/DialogContentPolicy/DialogCancellationExcursion.tsx +10 -2
- package/src/components/molecules/DialogContentPolicy/DialogCancellationList.tsx +18 -11
- package/src/components/molecules/ExcursionDocket/ExcursionDocket.tsx +25 -5
- package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +11 -0
- package/src/components/molecules/OtherServiceDocket/OtherServiceDocket.tsx +25 -5
- package/src/components/molecules/Toast/Toast.tsx +49 -0
- package/src/components/molecules/Toast/index.ts +3 -0
- package/src/components/molecules/TransferDocket/TransferDocket.tsx +21 -3
- package/src/components/organisms/CancelService/CancelPolicy.tsx +68 -0
- package/src/components/organisms/CancelService/CancelService.tsx +30 -0
- package/src/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.css +56 -0
- package/src/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.tsx +67 -0
- package/src/components/organisms/CancelService/FromList.tsx +50 -0
- package/src/components/organisms/CarBookingCard/CarBookingCard.css +13 -1
- package/src/components/organisms/CarBookingCard/CarBookingCard.tsx +40 -21
- package/src/components/organisms/CarBookingCard/CarBookingCardSkeleton.css +257 -0
- package/src/components/organisms/CarBookingCard/CarBookingCardSkeleton.tsx +112 -0
- package/src/components/organisms/CarBookingCard/index.ts +10 -15
- package/src/components/organisms/DateTimePicker/DateTimePicker.tsx +39 -3
- package/src/components/organisms/Docket/Docket.tsx +82 -20
- package/src/components/organisms/PaxSelector/PaxSelector.tsx +11 -0
- package/src/components/organisms/RoundTrip/RoundTrip.tsx +31 -10
- package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +108 -54
- package/src/components/organisms/SearchBarTransfer/index.ts +6 -0
- package/src/components/organisms/Table/Table.tsx +6 -1
- package/src/components/organisms/Table/TableCell.tsx +8 -4
- package/src/components/organisms/Table/columns/booking-cancel-service-columns.tsx +242 -0
- package/src/components/organisms/Table/columns/detail-resume-columns.tsx +19 -5
- package/src/components/organisms/Table/columns/index.ts +2 -0
- package/src/components/organisms/TransferLine/TransferLine.tsx +31 -10
- package/src/components/ui/popover.tsx +7 -7
- package/src/styles/components/molecule/calendarInput.css +33 -4
- package/src/styles/components/molecule/location-dropdown.css +6 -4
- package/src/styles/components/molecule/toast.css +93 -0
- package/src/styles/components/organism/docket.css +5 -1
- package/src/styles/components/organism/pax-selector.css +12 -1
- package/src/styles/components/organism/round-trip.css +4 -0
- package/src/styles/components/organism/transfer-line.css +5 -1
|
@@ -2,16 +2,17 @@ import React, { useEffect, useState } from 'react';
|
|
|
2
2
|
import '../../../styles/components/organism/docket.css';
|
|
3
3
|
import { Docket as DocketType } from '../../../types/docket/docket.types';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
AccomodationDocket as AccomodationDocketType,
|
|
6
|
+
ExcursionDocket as ExcursionDocketType,
|
|
7
|
+
OtherServiceDocket as OtherServiceDocketType,
|
|
8
|
+
ServiceDocket,
|
|
9
|
+
TransferDocket as TransferDocketType,
|
|
10
10
|
} from '../../../types/docket/services.types';
|
|
11
11
|
import Button from '../../atoms/Button/Button';
|
|
12
12
|
import Chip from '../../atoms/Chip/Chip';
|
|
13
13
|
import Icon from '../../atoms/Icon/Icon';
|
|
14
14
|
import { AccomodationDocket } from '../../molecules/AccomodationDocket/AccomodationDocket';
|
|
15
|
+
import { ActionDropdown, ActionDropdownItem } from '../../molecules/ActionDropdown/ActionDropdown';
|
|
15
16
|
import { DocketPrices } from '../../molecules/DocketPrices/DocketPrices';
|
|
16
17
|
import { ExcursionDocket } from '../../molecules/ExcursionDocket/ExcursionDocket';
|
|
17
18
|
import { OtherServiceDocket } from '../../molecules/OtherServiceDocket/OtherServiceDocket';
|
|
@@ -24,7 +25,12 @@ export interface DocketHeaderProps {
|
|
|
24
25
|
title?: string;
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
*
|
|
28
|
+
* Array of options for the "More options" dropdown
|
|
29
|
+
*/
|
|
30
|
+
moreOptions?: ActionDropdownItem[];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Handler for the "More options" button click (deprecated - use moreOptions instead)
|
|
28
34
|
*/
|
|
29
35
|
onMoreOptionsClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
30
36
|
|
|
@@ -78,7 +84,12 @@ export interface DocketProps {
|
|
|
78
84
|
title?: string;
|
|
79
85
|
|
|
80
86
|
/**
|
|
81
|
-
*
|
|
87
|
+
* Array of options for the "More options" dropdown
|
|
88
|
+
*/
|
|
89
|
+
moreOptions?: ActionDropdownItem[];
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Handler for the "More options" button click (deprecated - use moreOptions instead)
|
|
82
93
|
*/
|
|
83
94
|
onMoreOptionsClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
84
95
|
|
|
@@ -122,6 +133,11 @@ export interface DocketProps {
|
|
|
122
133
|
*/
|
|
123
134
|
className?: string;
|
|
124
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Additional CSS classes to apply to the wrapper container around the docket
|
|
138
|
+
*/
|
|
139
|
+
containerClassName?: string;
|
|
140
|
+
|
|
125
141
|
/**
|
|
126
142
|
* Optional click handler
|
|
127
143
|
*/
|
|
@@ -131,6 +147,17 @@ export interface DocketProps {
|
|
|
131
147
|
* Optional data attributes for testing or tracking
|
|
132
148
|
*/
|
|
133
149
|
'data-testid'?: string;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Remove mode - replaces price chips with remove buttons in all service dockets
|
|
153
|
+
*/
|
|
154
|
+
removeMode?: boolean;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Handler for remove button clicks in service dockets
|
|
158
|
+
* Receives the service index and service data
|
|
159
|
+
*/
|
|
160
|
+
onServiceRemove?: (index: number, service: ServiceDocket) => void;
|
|
134
161
|
}
|
|
135
162
|
|
|
136
163
|
/**
|
|
@@ -196,23 +223,29 @@ export const DocketEmptyState: React.FC<{ className?: string }> = ({
|
|
|
196
223
|
*/
|
|
197
224
|
export const DocketHeader: React.FC<DocketHeaderProps> = ({
|
|
198
225
|
title = 'Your quotation',
|
|
226
|
+
moreOptions,
|
|
199
227
|
onMoreOptionsClick,
|
|
200
228
|
className = '',
|
|
201
229
|
}) => {
|
|
230
|
+
const chipTrigger = (
|
|
231
|
+
<Chip trailingIcon="chevron-down" className="docket__header-more-options">
|
|
232
|
+
More options
|
|
233
|
+
</Chip>
|
|
234
|
+
);
|
|
235
|
+
|
|
202
236
|
return (
|
|
203
237
|
<div className={`docket__header ${className}`}>
|
|
204
238
|
<div className="docket__header-title">
|
|
205
239
|
<Icon name="quotation" size="lg" />
|
|
206
240
|
<h2 className="docket__header-title-text">{title}</h2>
|
|
207
241
|
</div>
|
|
208
|
-
{
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
)}
|
|
242
|
+
{moreOptions && moreOptions.length > 0 ? (
|
|
243
|
+
<ActionDropdown data={moreOptions} maxWidth="200px">
|
|
244
|
+
{chipTrigger}
|
|
245
|
+
</ActionDropdown>
|
|
246
|
+
) : onMoreOptionsClick ? (
|
|
247
|
+
<div onClick={onMoreOptionsClick}>{chipTrigger}</div>
|
|
248
|
+
) : null}
|
|
216
249
|
</div>
|
|
217
250
|
);
|
|
218
251
|
};
|
|
@@ -283,6 +316,7 @@ export const DocketFooter: React.FC<DocketFooterProps> = ({
|
|
|
283
316
|
export const Docket: React.FC<DocketProps> = ({
|
|
284
317
|
dockets,
|
|
285
318
|
title = 'Your quotation',
|
|
319
|
+
moreOptions,
|
|
286
320
|
onMoreOptionsClick,
|
|
287
321
|
onAddNewQuoteClick,
|
|
288
322
|
onViewClick,
|
|
@@ -292,8 +326,11 @@ export const Docket: React.FC<DocketProps> = ({
|
|
|
292
326
|
showHeader = true,
|
|
293
327
|
showFooter = true,
|
|
294
328
|
className = '',
|
|
329
|
+
containerClassName = '',
|
|
295
330
|
onClick,
|
|
296
331
|
'data-testid': testId,
|
|
332
|
+
removeMode = false,
|
|
333
|
+
onServiceRemove,
|
|
297
334
|
}) => {
|
|
298
335
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
299
336
|
const [isMobile, setIsMobile] = useState<boolean>(false);
|
|
@@ -328,23 +365,36 @@ export const Docket: React.FC<DocketProps> = ({
|
|
|
328
365
|
.join(' ');
|
|
329
366
|
|
|
330
367
|
const renderService = (service: ServiceDocket, index: number) => {
|
|
368
|
+
const handleRemove = () => {
|
|
369
|
+
onServiceRemove?.(index, service);
|
|
370
|
+
};
|
|
371
|
+
|
|
331
372
|
switch (service.type) {
|
|
332
373
|
case 'accommodation':
|
|
333
374
|
return (
|
|
334
375
|
<AccomodationDocket
|
|
335
376
|
key={`service-${index}`}
|
|
336
377
|
data={service as AccomodationDocketType}
|
|
378
|
+
removeMode={removeMode}
|
|
379
|
+
onRemove={handleRemove}
|
|
337
380
|
/>
|
|
338
381
|
);
|
|
339
382
|
case 'transfer':
|
|
340
383
|
return (
|
|
341
|
-
<TransferDocket
|
|
384
|
+
<TransferDocket
|
|
385
|
+
key={`service-${index}`}
|
|
386
|
+
data={service as TransferDocketType}
|
|
387
|
+
removeMode={removeMode}
|
|
388
|
+
onRemove={handleRemove}
|
|
389
|
+
/>
|
|
342
390
|
);
|
|
343
391
|
case 'excursion':
|
|
344
392
|
return (
|
|
345
393
|
<ExcursionDocket
|
|
346
394
|
key={`service-${index}`}
|
|
347
395
|
data={service as ExcursionDocketType}
|
|
396
|
+
removeMode={removeMode}
|
|
397
|
+
onRemove={handleRemove}
|
|
348
398
|
/>
|
|
349
399
|
);
|
|
350
400
|
case 'otherService':
|
|
@@ -385,8 +435,12 @@ export const Docket: React.FC<DocketProps> = ({
|
|
|
385
435
|
// Collect all prices from all dockets
|
|
386
436
|
const allPrices = dockets ? dockets.flatMap((docket) => docket.prices || []) : [];
|
|
387
437
|
|
|
438
|
+
const containerClasses = containerClassName
|
|
439
|
+
? `docket__container ${containerClassName}`
|
|
440
|
+
: 'docket__container';
|
|
441
|
+
|
|
388
442
|
return (
|
|
389
|
-
|
|
443
|
+
<div className={containerClasses}>
|
|
390
444
|
{isMobile && !isOpen && (
|
|
391
445
|
<DocketCollapsedHeader title={title} onClick={handleToggle} />
|
|
392
446
|
)}
|
|
@@ -405,7 +459,11 @@ export const Docket: React.FC<DocketProps> = ({
|
|
|
405
459
|
</div>
|
|
406
460
|
<div className={classes} onClick={onClick} data-testid={testId}>
|
|
407
461
|
{showHeader && (
|
|
408
|
-
<DocketHeader
|
|
462
|
+
<DocketHeader
|
|
463
|
+
title={title}
|
|
464
|
+
moreOptions={moreOptions}
|
|
465
|
+
onMoreOptionsClick={onMoreOptionsClick}
|
|
466
|
+
/>
|
|
409
467
|
)}
|
|
410
468
|
<div className="docket__content">{renderContent()}</div>
|
|
411
469
|
{allPrices.length > 0 && (
|
|
@@ -428,7 +486,11 @@ export const Docket: React.FC<DocketProps> = ({
|
|
|
428
486
|
{!isMobile && (
|
|
429
487
|
<div className={classes} onClick={onClick} data-testid={testId}>
|
|
430
488
|
{showHeader && (
|
|
431
|
-
<DocketHeader
|
|
489
|
+
<DocketHeader
|
|
490
|
+
title={title}
|
|
491
|
+
moreOptions={moreOptions}
|
|
492
|
+
onMoreOptionsClick={onMoreOptionsClick}
|
|
493
|
+
/>
|
|
432
494
|
)}
|
|
433
495
|
<div className="docket__content">{renderContent()}</div>
|
|
434
496
|
{allPrices.length > 0 && (
|
|
@@ -449,7 +511,7 @@ export const Docket: React.FC<DocketProps> = ({
|
|
|
449
511
|
)}
|
|
450
512
|
</div>
|
|
451
513
|
)}
|
|
452
|
-
|
|
514
|
+
</div>
|
|
453
515
|
);
|
|
454
516
|
};
|
|
455
517
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { scrollIntoViewOnOpen } from '../../../lib/utils';
|
|
2
3
|
import Icon from '../../atoms/Icon/Icon';
|
|
3
4
|
import { Text } from '../../atoms/Typography/Typography';
|
|
4
5
|
|
|
@@ -64,6 +65,8 @@ export interface PaxSelectorProps {
|
|
|
64
65
|
onRemoveRoom?: (roomId: string) => void;
|
|
65
66
|
/** Default pax data for single room mode (will trigger onChange on mount) */
|
|
66
67
|
defaultPaxData?: PaxData;
|
|
68
|
+
/** Whether to scroll to the input when the dropdown opens */
|
|
69
|
+
scrollOnOpen?: boolean;
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
const DEFAULT_PAX_DATA: PaxData = {
|
|
@@ -652,6 +655,7 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
652
655
|
onRoomsChange,
|
|
653
656
|
onRemoveRoom,
|
|
654
657
|
defaultPaxData = DEFAULT_PAX_DATA_WITH_ADULTS,
|
|
658
|
+
scrollOnOpen = false,
|
|
655
659
|
}) => {
|
|
656
660
|
const [isOpen, setIsOpen] = useState(false);
|
|
657
661
|
const [internalData, setInternalData] = useState<PaxData>(
|
|
@@ -661,6 +665,7 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
661
665
|
defaultRooms || [{ ...DEFAULT_PAX_DATA, roomId: '1' }]
|
|
662
666
|
);
|
|
663
667
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
668
|
+
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
664
669
|
const hasInitialized = useRef(false);
|
|
665
670
|
|
|
666
671
|
// Sync internal data with external value prop
|
|
@@ -755,6 +760,11 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
755
760
|
};
|
|
756
761
|
}, [isOpen]);
|
|
757
762
|
|
|
763
|
+
// Scroll to input when dropdown opens (if scrollOnOpen is true)
|
|
764
|
+
useEffect(() => {
|
|
765
|
+
scrollIntoViewOnOpen(triggerRef, isOpen, scrollOnOpen);
|
|
766
|
+
}, [isOpen, scrollOnOpen]);
|
|
767
|
+
|
|
758
768
|
const handleDataChange = (
|
|
759
769
|
field: keyof PaxData,
|
|
760
770
|
newValue: number | ClientType | number[]
|
|
@@ -834,6 +844,7 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
834
844
|
return (
|
|
835
845
|
<div className={`pax-selector ${className}`} ref={containerRef}>
|
|
836
846
|
<button
|
|
847
|
+
ref={triggerRef}
|
|
837
848
|
type="button"
|
|
838
849
|
className="pax-selector__trigger"
|
|
839
850
|
onClick={() => setIsOpen(!isOpen)}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import "../../../styles/components/organism/round-trip.css";
|
|
3
3
|
import { Text } from "../../atoms/Typography/Typography";
|
|
4
|
-
import PaxSelector, { PaxData } from "../PaxSelector/PaxSelector";
|
|
5
|
-
import DateTimePicker from "../DateTimePicker/DateTimePicker";
|
|
6
4
|
import LocationDropdown, {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
LocationData,
|
|
6
|
+
LocationGroup,
|
|
7
|
+
LocationOption,
|
|
10
8
|
} from "../../molecules/LocationDropdown/LocationDropdown";
|
|
11
|
-
import "
|
|
9
|
+
import DateTimePicker from "../DateTimePicker/DateTimePicker";
|
|
10
|
+
import PaxSelector, { PaxData } from "../PaxSelector/PaxSelector";
|
|
12
11
|
|
|
13
12
|
// Re-export LocationData for convenience
|
|
14
13
|
export type { LocationData };
|
|
@@ -61,6 +60,8 @@ export interface RoundTripProps {
|
|
|
61
60
|
onChange?: (data: RoundTripData) => void;
|
|
62
61
|
/** Additional CSS classes */
|
|
63
62
|
className?: string;
|
|
63
|
+
/** Whether to check if inputs are empty */
|
|
64
|
+
checkEmpty?: boolean;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
const RoundTrip: React.FC<RoundTripProps> = ({
|
|
@@ -77,6 +78,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
77
78
|
onAccommodationChange,
|
|
78
79
|
onChange,
|
|
79
80
|
className = "",
|
|
81
|
+
checkEmpty = false,
|
|
80
82
|
}) => {
|
|
81
83
|
const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(
|
|
82
84
|
paxData
|
|
@@ -270,18 +272,33 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
270
272
|
onAccommodationChange?.(location);
|
|
271
273
|
};
|
|
272
274
|
|
|
275
|
+
// Check if inputs are empty (when checkEmpty is true)
|
|
276
|
+
const isPaxEmpty = checkEmpty && (!internalPaxData ||
|
|
277
|
+
(internalPaxData.adults === 0 &&
|
|
278
|
+
internalPaxData.teens === 0 &&
|
|
279
|
+
internalPaxData.children === 0 &&
|
|
280
|
+
(internalPaxData.infants === undefined || internalPaxData.infants === 0)));
|
|
281
|
+
|
|
282
|
+
const isDateEmpty = checkEmpty && (!internalArrivalDate || !internalDepartureDate ||
|
|
283
|
+
internalArrivalDate === '' || internalDepartureDate === '');
|
|
284
|
+
|
|
285
|
+
const isPickupDropoffEmpty = checkEmpty && !internalPickupDropoffPoint;
|
|
286
|
+
|
|
287
|
+
const isAccommodationEmpty = checkEmpty && !internalAccommodation;
|
|
288
|
+
|
|
273
289
|
const pickupDropoffOptions = getPickupDropoffOptions();
|
|
274
290
|
const accommodationOptions = getAccommodationOptions();
|
|
275
291
|
|
|
276
292
|
return (
|
|
277
293
|
<div className={`round-trip ${className}`} data-round-trip-id={id}>
|
|
278
294
|
<div className="round-trip__content">
|
|
279
|
-
<div className=
|
|
295
|
+
<div className={`round-trip__field round-trip__field--pax ${isPaxEmpty ? 'round-trip__field--error' : ''}`}>
|
|
280
296
|
<PaxSelector
|
|
281
297
|
label="Number of pax"
|
|
282
298
|
value={internalPaxData}
|
|
283
299
|
onChange={handlePaxChange}
|
|
284
300
|
placeholder="2 pax"
|
|
301
|
+
className={isPaxEmpty ? 'pax-selector--error' : ''}
|
|
285
302
|
/>
|
|
286
303
|
</div>
|
|
287
304
|
|
|
@@ -298,7 +315,9 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
298
315
|
showChevron={true}
|
|
299
316
|
onValueChange={handleDateRangeChange}
|
|
300
317
|
selectionMode="range"
|
|
301
|
-
defaultValue={
|
|
318
|
+
defaultValue={internalArrivalDate && internalDepartureDate ? [internalArrivalDate, internalDepartureDate] : undefined}
|
|
319
|
+
inputClassName="round-trip__date-picker--input"
|
|
320
|
+
state={isDateEmpty ? 'error' : undefined}
|
|
302
321
|
/>
|
|
303
322
|
</div>
|
|
304
323
|
<div className="round-trip__field round-trip__field--pickup-dropoff">
|
|
@@ -312,6 +331,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
312
331
|
direction={undefined}
|
|
313
332
|
type="airport-port"
|
|
314
333
|
showGroupTitles={true}
|
|
334
|
+
error={isPickupDropoffEmpty}
|
|
315
335
|
/>
|
|
316
336
|
</div>
|
|
317
337
|
|
|
@@ -326,6 +346,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
326
346
|
direction="dropoff"
|
|
327
347
|
type="accommodation"
|
|
328
348
|
showGroupTitles={false}
|
|
349
|
+
error={isAccommodationEmpty}
|
|
329
350
|
/>
|
|
330
351
|
</div>
|
|
331
352
|
</div>
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import
|
|
3
|
-
import TransferLine, {
|
|
4
|
-
TransferLineData,
|
|
5
|
-
TransferType,
|
|
6
|
-
} from "../TransferLine/TransferLine";
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import "../../../styles/components/organism/search-bar-transfer.css";
|
|
7
3
|
import Button from "../../atoms/Button/Button";
|
|
8
4
|
import Checkbox from "../../atoms/Checkbox/Checkbox";
|
|
9
|
-
import { Text, Heading } from "../../atoms/Typography/Typography";
|
|
10
|
-
import { LocationOption, LocationGroup } from "../../molecules/LocationDropdown/LocationDropdown";
|
|
11
5
|
import Icon, { IconName } from "../../atoms/Icon/Icon";
|
|
12
6
|
import SegmentedButton, { SegmentedButtonOption } from "../../atoms/SegmentedButton/SegmentedButton";
|
|
13
|
-
import "
|
|
7
|
+
import { Heading, Text } from "../../atoms/Typography/Typography";
|
|
8
|
+
import { LocationGroup, LocationOption } from "../../molecules/LocationDropdown/LocationDropdown";
|
|
9
|
+
import Toast from "../../molecules/Toast/Toast";
|
|
10
|
+
import RoundTrip, { RoundTripData } from "../RoundTrip/RoundTrip";
|
|
11
|
+
import TransferLine, {
|
|
12
|
+
TransferLineData,
|
|
13
|
+
TransferType,
|
|
14
|
+
} from "../TransferLine/TransferLine";
|
|
14
15
|
|
|
15
16
|
export type TransferMode = "roundtrip" | "custom";
|
|
16
17
|
|
|
@@ -141,6 +142,81 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
141
142
|
setTransferLines([...transferLines, newTransfer]);
|
|
142
143
|
};
|
|
143
144
|
|
|
145
|
+
// Render transfer type buttons
|
|
146
|
+
const renderTransferTypeButtons = (onClick: (type: TransferType) => void) => (
|
|
147
|
+
<div className="search-bar-transfer__add-buttons">
|
|
148
|
+
<Button
|
|
149
|
+
variant="outline-secondary"
|
|
150
|
+
size="sm"
|
|
151
|
+
leadingIcon="plus"
|
|
152
|
+
onClick={() => onClick("arrival")}
|
|
153
|
+
>
|
|
154
|
+
Add Arrival
|
|
155
|
+
</Button>
|
|
156
|
+
<Button
|
|
157
|
+
variant="outline-secondary"
|
|
158
|
+
size="sm"
|
|
159
|
+
leadingIcon="plus"
|
|
160
|
+
onClick={() => onClick("departure")}
|
|
161
|
+
>
|
|
162
|
+
Add Departure
|
|
163
|
+
</Button>
|
|
164
|
+
<Button
|
|
165
|
+
variant="outline-secondary"
|
|
166
|
+
size="sm"
|
|
167
|
+
leadingIcon="plus"
|
|
168
|
+
onClick={() => onClick("inter-hotel")}
|
|
169
|
+
>
|
|
170
|
+
Add Inter-Hotel
|
|
171
|
+
</Button>
|
|
172
|
+
</div>
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// Handle adding transfer from round-trip mode (converts round-trip to custom and adds new transfer)
|
|
176
|
+
const handleAddTransferFromRoundTrip = (type: TransferType) => {
|
|
177
|
+
if (!roundTripData) {
|
|
178
|
+
// If no round trip data, just add a new transfer and switch to custom
|
|
179
|
+
const newTransfer: TransferLineData = {
|
|
180
|
+
id: generateTransferId(),
|
|
181
|
+
type,
|
|
182
|
+
};
|
|
183
|
+
setTransferLines([newTransfer]);
|
|
184
|
+
setMode("custom");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Convert roundtrip to two transfer lines
|
|
189
|
+
const arrivalTransfer: TransferLineData = {
|
|
190
|
+
id: generateTransferId(),
|
|
191
|
+
type: "arrival",
|
|
192
|
+
paxData: roundTripData.paxData,
|
|
193
|
+
transferDate: roundTripData.arrivalDate,
|
|
194
|
+
pickupPoint: roundTripData.pickupDropoffPoint,
|
|
195
|
+
dropoffPoint: roundTripData.accommodation,
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const departureTransfer: TransferLineData = {
|
|
199
|
+
id: generateTransferId(),
|
|
200
|
+
type: "departure",
|
|
201
|
+
paxData: roundTripData.paxData,
|
|
202
|
+
transferDate: roundTripData.departureDate,
|
|
203
|
+
pickupPoint: roundTripData.accommodation,
|
|
204
|
+
dropoffPoint: roundTripData.pickupDropoffPoint,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// Add the new transfer of the clicked type
|
|
208
|
+
const newTransfer: TransferLineData = {
|
|
209
|
+
id: generateTransferId(),
|
|
210
|
+
type,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Set all transfers and switch to custom mode
|
|
214
|
+
setTransferLines([arrivalTransfer, departureTransfer, newTransfer]);
|
|
215
|
+
setRoundTripData(undefined);
|
|
216
|
+
setMode("custom");
|
|
217
|
+
setError(null);
|
|
218
|
+
};
|
|
219
|
+
|
|
144
220
|
// Handle transfer line data change
|
|
145
221
|
const handleTransferLineChange = (id: string, data: TransferLineData) => {
|
|
146
222
|
setTransferLines((prevLines) =>
|
|
@@ -227,16 +303,23 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
227
303
|
|
|
228
304
|
{/* Content based on mode */}
|
|
229
305
|
{mode === "roundtrip" ? (
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
306
|
+
<>
|
|
307
|
+
<RoundTrip
|
|
308
|
+
id="roundtrip-main"
|
|
309
|
+
locations={locations}
|
|
310
|
+
paxData={roundTripData?.paxData}
|
|
311
|
+
arrivalDate={roundTripData?.arrivalDate}
|
|
312
|
+
departureDate={roundTripData?.departureDate}
|
|
313
|
+
pickupDropoffPoint={roundTripData?.pickupDropoffPoint?.id as string}
|
|
314
|
+
accommodation={roundTripData?.accommodation?.id as string}
|
|
315
|
+
onChange={setRoundTripData}
|
|
316
|
+
checkEmpty={error !== null}
|
|
317
|
+
/>
|
|
318
|
+
{/* Transfer type buttons for round-trip mode */}
|
|
319
|
+
<div className="search-bar-transfer__transfer-type">
|
|
320
|
+
{renderTransferTypeButtons(handleAddTransferFromRoundTrip)}
|
|
321
|
+
</div>
|
|
322
|
+
</>
|
|
240
323
|
) : (
|
|
241
324
|
<>
|
|
242
325
|
{/* Transfer type selector */}
|
|
@@ -244,32 +327,7 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
244
327
|
<Text size="lg" variant="bold" color="subtle" as="div" className="search-bar-transfer__transfer-type-label">
|
|
245
328
|
Select a transfer type you want to add
|
|
246
329
|
</Text>
|
|
247
|
-
|
|
248
|
-
<Button
|
|
249
|
-
variant="outline-secondary"
|
|
250
|
-
size="sm"
|
|
251
|
-
leadingIcon="plus"
|
|
252
|
-
onClick={() => handleAddTransfer("arrival")}
|
|
253
|
-
>
|
|
254
|
-
Add Arrival
|
|
255
|
-
</Button>
|
|
256
|
-
<Button
|
|
257
|
-
variant="outline-secondary"
|
|
258
|
-
size="sm"
|
|
259
|
-
leadingIcon="plus"
|
|
260
|
-
onClick={() => handleAddTransfer("departure")}
|
|
261
|
-
>
|
|
262
|
-
Add Departure
|
|
263
|
-
</Button>
|
|
264
|
-
<Button
|
|
265
|
-
variant="outline-secondary"
|
|
266
|
-
size="sm"
|
|
267
|
-
leadingIcon="plus"
|
|
268
|
-
onClick={() => handleAddTransfer("inter-hotel")}
|
|
269
|
-
>
|
|
270
|
-
Add Inter-Hotel
|
|
271
|
-
</Button>
|
|
272
|
-
</div>
|
|
330
|
+
{renderTransferTypeButtons(handleAddTransfer)}
|
|
273
331
|
</div>
|
|
274
332
|
|
|
275
333
|
{/* Transfer lines list */}
|
|
@@ -322,6 +380,7 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
322
380
|
onDataChange={(data) => handleTransferLineChange(line.id, data)}
|
|
323
381
|
onDelete={() => handleDeleteTransferLine(line.id)}
|
|
324
382
|
showDelete={transferLines.length > 1}
|
|
383
|
+
checkEmpty={error !== null}
|
|
325
384
|
/>
|
|
326
385
|
))}
|
|
327
386
|
|
|
@@ -362,15 +421,10 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
362
421
|
|
|
363
422
|
<div className="search-bar-transfer__cta">
|
|
364
423
|
{error && (
|
|
365
|
-
<
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
<Text size="sm" variant="bold" className="search-bar-transfer__error-text">
|
|
370
|
-
{error}
|
|
371
|
-
</Text>
|
|
372
|
-
</div>
|
|
373
|
-
</div>
|
|
424
|
+
<Toast
|
|
425
|
+
text={error}
|
|
426
|
+
type="danger"
|
|
427
|
+
/>
|
|
374
428
|
)}
|
|
375
429
|
<Button
|
|
376
430
|
variant="primary"
|
|
@@ -103,7 +103,12 @@ const NestedContent = <T extends TableRowData<T>>({
|
|
|
103
103
|
'table__row-clickable': onClickRow,
|
|
104
104
|
})}
|
|
105
105
|
onClick={(e) => onClickRow?.(e, child as T)}>
|
|
106
|
-
<TableCell<T>
|
|
106
|
+
<TableCell<T>
|
|
107
|
+
columns={columns}
|
|
108
|
+
row={child as T}
|
|
109
|
+
rowIndex={childIndex}
|
|
110
|
+
childIndex={childIndex}
|
|
111
|
+
/>
|
|
107
112
|
</tr>
|
|
108
113
|
))}
|
|
109
114
|
</tbody>
|
|
@@ -9,7 +9,8 @@ export type ColumnType<T = TableRowData> = {
|
|
|
9
9
|
cell: (
|
|
10
10
|
value: T[Extract<keyof T, string>],
|
|
11
11
|
rawData: T,
|
|
12
|
-
index?: number
|
|
12
|
+
index?: number,
|
|
13
|
+
childIndex?: number
|
|
13
14
|
) => React.ReactNode;
|
|
14
15
|
};
|
|
15
16
|
|
|
@@ -17,9 +18,10 @@ export interface TableCellProps<T = TableRowData> {
|
|
|
17
18
|
columns: ColumnType<T>[];
|
|
18
19
|
row: T;
|
|
19
20
|
rowIndex: number;
|
|
21
|
+
childIndex?: number;
|
|
20
22
|
}
|
|
21
23
|
export const TableCell = <T extends TableRowData>(props: TableCellProps<T>) => {
|
|
22
|
-
const { columns, row, rowIndex } = props;
|
|
24
|
+
const { columns, row, rowIndex, childIndex } = props;
|
|
23
25
|
return (
|
|
24
26
|
<>
|
|
25
27
|
{columns.map((column, columnIndex) => (
|
|
@@ -29,9 +31,11 @@ export const TableCell = <T extends TableRowData>(props: TableCellProps<T>) => {
|
|
|
29
31
|
column.width ? { minWidth: column.width, width: column.width } : undefined
|
|
30
32
|
}>
|
|
31
33
|
{column.key === 'actions' ? (
|
|
32
|
-
<div>
|
|
34
|
+
<div>
|
|
35
|
+
{column.cell({} as T[Extract<keyof T, string>], row, rowIndex, childIndex)}
|
|
36
|
+
</div>
|
|
33
37
|
) : (
|
|
34
|
-
column.cell(row[column.key], row, rowIndex)
|
|
38
|
+
column.cell(row[column.key], row, rowIndex, childIndex)
|
|
35
39
|
)}
|
|
36
40
|
</td>
|
|
37
41
|
))}
|