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.
Files changed (128) hide show
  1. package/dist/components/atoms/Icon/icons/BadgeAlertIcon.d.ts +4 -0
  2. package/dist/components/atoms/Icon/icons/BadgeAlertIcon.js +36 -0
  3. package/dist/components/atoms/Icon/icons/registry.d.ts +1 -0
  4. package/dist/components/atoms/Icon/icons/registry.js +2 -0
  5. package/dist/components/molecules/AccomodationDocket/AccomodationDocket.d.ts +5 -1
  6. package/dist/components/molecules/AccomodationDocket/AccomodationDocket.js +4 -3
  7. package/dist/components/molecules/Calendar/CalendarInput.js +2 -1
  8. package/dist/components/molecules/DateDisplay/DateDisplay.d.ts +4 -0
  9. package/dist/components/molecules/DateDisplay/DateDisplay.js +3 -5
  10. package/dist/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.css +50 -0
  11. package/dist/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.d.ts +2 -0
  12. package/dist/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.js +3 -2
  13. package/dist/components/molecules/DialogContentPolicy/DialogCancellationAccom.d.ts +2 -0
  14. package/dist/components/molecules/DialogContentPolicy/DialogCancellationAccom.js +2 -2
  15. package/dist/components/molecules/DialogContentPolicy/DialogCancellationExcursion.d.ts +2 -0
  16. package/dist/components/molecules/DialogContentPolicy/DialogCancellationExcursion.js +2 -2
  17. package/dist/components/molecules/DialogContentPolicy/DialogCancellationList.d.ts +1 -0
  18. package/dist/components/molecules/DialogContentPolicy/DialogCancellationList.js +14 -11
  19. package/dist/components/molecules/ExcursionDocket/ExcursionDocket.d.ts +4 -0
  20. package/dist/components/molecules/ExcursionDocket/ExcursionDocket.js +3 -2
  21. package/dist/components/molecules/LocationDropdown/LocationDropdown.d.ts +2 -0
  22. package/dist/components/molecules/LocationDropdown/LocationDropdown.js +9 -3
  23. package/dist/components/molecules/OtherServiceDocket/OtherServiceDocket.d.ts +4 -0
  24. package/dist/components/molecules/OtherServiceDocket/OtherServiceDocket.js +3 -2
  25. package/dist/components/molecules/Toast/Toast.d.ts +25 -0
  26. package/dist/components/molecules/Toast/Toast.js +29 -0
  27. package/dist/components/molecules/Toast/index.d.ts +2 -0
  28. package/dist/components/molecules/Toast/index.js +1 -0
  29. package/dist/components/molecules/TransferDocket/TransferDocket.d.ts +4 -0
  30. package/dist/components/molecules/TransferDocket/TransferDocket.js +3 -2
  31. package/dist/components/organisms/CancelService/CancelPolicy.d.ts +29 -0
  32. package/dist/components/organisms/CancelService/CancelPolicy.js +19 -0
  33. package/dist/components/organisms/CancelService/CancelService.d.ts +14 -0
  34. package/dist/components/organisms/CancelService/CancelService.js +23 -0
  35. package/dist/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.css +2143 -0
  36. package/dist/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.d.ts +14 -0
  37. package/dist/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.js +35 -0
  38. package/dist/components/organisms/CancelService/FromList.d.ts +12 -0
  39. package/dist/components/organisms/CancelService/FromList.js +29 -0
  40. package/dist/components/organisms/CarBookingCard/CarBookingCard.css +13 -1
  41. package/dist/components/organisms/CarBookingCard/CarBookingCard.d.ts +2 -0
  42. package/dist/components/organisms/CarBookingCard/CarBookingCard.js +4 -3
  43. package/dist/components/organisms/CarBookingCard/CarBookingCardSkeleton.css +2334 -0
  44. package/dist/components/organisms/CarBookingCard/CarBookingCardSkeleton.d.ts +19 -0
  45. package/dist/components/organisms/CarBookingCard/CarBookingCardSkeleton.js +35 -0
  46. package/dist/components/organisms/CarBookingCard/index.d.ts +4 -2
  47. package/dist/components/organisms/CarBookingCard/index.js +2 -1
  48. package/dist/components/organisms/DateTimePicker/DateTimePicker.d.ts +8 -0
  49. package/dist/components/organisms/DateTimePicker/DateTimePicker.js +20 -7
  50. package/dist/components/organisms/Docket/Docket.d.ts +25 -2
  51. package/dist/components/organisms/Docket/Docket.js +18 -10
  52. package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +2 -0
  53. package/dist/components/organisms/PaxSelector/PaxSelector.js +11 -5
  54. package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +4 -2
  55. package/dist/components/organisms/RoundTrip/RoundTrip.js +21 -11
  56. package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +2 -2
  57. package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +51 -8
  58. package/dist/components/organisms/Table/Table.js +1 -1
  59. package/dist/components/organisms/Table/TableCell.d.ts +2 -1
  60. package/dist/components/organisms/Table/TableCell.js +2 -2
  61. package/dist/components/organisms/Table/columns/booking-cancel-service-columns.d.ts +5 -0
  62. package/dist/components/organisms/Table/columns/booking-cancel-service-columns.js +182 -0
  63. package/dist/components/organisms/Table/columns/detail-resume-columns.d.ts +3 -1
  64. package/dist/components/organisms/Table/columns/detail-resume-columns.js +5 -3
  65. package/dist/components/organisms/Table/columns/index.d.ts +6 -1
  66. package/dist/components/organisms/Table/columns/index.js +2 -0
  67. package/dist/components/organisms/TransferLine/TransferLine.d.ts +4 -2
  68. package/dist/components/organisms/TransferLine/TransferLine.js +18 -9
  69. package/dist/components/ui/popover.d.ts +1 -1
  70. package/dist/components/ui/popover.js +5 -3
  71. package/dist/index.d.ts +15 -14
  72. package/dist/index.js +2 -1
  73. package/dist/lib/utils.d.ts +21 -0
  74. package/dist/lib/utils.js +114 -0
  75. package/dist/styles/components/molecule/calendarInput.css +40 -5
  76. package/dist/styles/components/molecule/location-dropdown.css +7 -5
  77. package/dist/styles/components/molecule/toast.css +2185 -0
  78. package/dist/styles/components/organism/docket.css +7 -1
  79. package/dist/styles/components/organism/pax-selector.css +12 -1
  80. package/dist/styles/components/organism/round-trip.css +4 -0
  81. package/dist/styles/components/organism/transfer-line.css +5 -1
  82. package/package.json +1 -1
  83. package/src/components/atoms/Icon/icons/BadgeAlertIcon.tsx +44 -0
  84. package/src/components/atoms/Icon/icons/registry.tsx +2 -0
  85. package/src/components/molecules/AccomodationDocket/AccomodationDocket.tsx +26 -6
  86. package/src/components/molecules/Calendar/CalendarInput.tsx +5 -2
  87. package/src/components/molecules/DateDisplay/DateDisplay.tsx +7 -7
  88. package/src/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.css +27 -0
  89. package/src/components/molecules/DialogContentPolicy/CancellationLayout/CancellationLayout.tsx +12 -1
  90. package/src/components/molecules/DialogContentPolicy/DialogCancellationAccom.tsx +9 -2
  91. package/src/components/molecules/DialogContentPolicy/DialogCancellationExcursion.tsx +10 -2
  92. package/src/components/molecules/DialogContentPolicy/DialogCancellationList.tsx +18 -11
  93. package/src/components/molecules/ExcursionDocket/ExcursionDocket.tsx +25 -5
  94. package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +11 -0
  95. package/src/components/molecules/OtherServiceDocket/OtherServiceDocket.tsx +25 -5
  96. package/src/components/molecules/Toast/Toast.tsx +49 -0
  97. package/src/components/molecules/Toast/index.ts +3 -0
  98. package/src/components/molecules/TransferDocket/TransferDocket.tsx +21 -3
  99. package/src/components/organisms/CancelService/CancelPolicy.tsx +68 -0
  100. package/src/components/organisms/CancelService/CancelService.tsx +30 -0
  101. package/src/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.css +56 -0
  102. package/src/components/organisms/CancelService/ConfirmDelete/ConfirmDelete.tsx +67 -0
  103. package/src/components/organisms/CancelService/FromList.tsx +50 -0
  104. package/src/components/organisms/CarBookingCard/CarBookingCard.css +13 -1
  105. package/src/components/organisms/CarBookingCard/CarBookingCard.tsx +40 -21
  106. package/src/components/organisms/CarBookingCard/CarBookingCardSkeleton.css +257 -0
  107. package/src/components/organisms/CarBookingCard/CarBookingCardSkeleton.tsx +112 -0
  108. package/src/components/organisms/CarBookingCard/index.ts +10 -15
  109. package/src/components/organisms/DateTimePicker/DateTimePicker.tsx +39 -3
  110. package/src/components/organisms/Docket/Docket.tsx +82 -20
  111. package/src/components/organisms/PaxSelector/PaxSelector.tsx +11 -0
  112. package/src/components/organisms/RoundTrip/RoundTrip.tsx +31 -10
  113. package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +108 -54
  114. package/src/components/organisms/SearchBarTransfer/index.ts +6 -0
  115. package/src/components/organisms/Table/Table.tsx +6 -1
  116. package/src/components/organisms/Table/TableCell.tsx +8 -4
  117. package/src/components/organisms/Table/columns/booking-cancel-service-columns.tsx +242 -0
  118. package/src/components/organisms/Table/columns/detail-resume-columns.tsx +19 -5
  119. package/src/components/organisms/Table/columns/index.ts +2 -0
  120. package/src/components/organisms/TransferLine/TransferLine.tsx +31 -10
  121. package/src/components/ui/popover.tsx +7 -7
  122. package/src/styles/components/molecule/calendarInput.css +33 -4
  123. package/src/styles/components/molecule/location-dropdown.css +6 -4
  124. package/src/styles/components/molecule/toast.css +93 -0
  125. package/src/styles/components/organism/docket.css +5 -1
  126. package/src/styles/components/organism/pax-selector.css +12 -1
  127. package/src/styles/components/organism/round-trip.css +4 -0
  128. 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
- AccomodationDocket as AccomodationDocketType,
6
- ExcursionDocket as ExcursionDocketType,
7
- OtherServiceDocket as OtherServiceDocketType,
8
- ServiceDocket,
9
- TransferDocket as TransferDocketType,
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
- * Handler for the "More options" button click
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
- * Handler for the "More options" button click
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
- {onMoreOptionsClick && (
209
- <Chip
210
- onClick={onMoreOptionsClick}
211
- trailingIcon="chevron-down"
212
- className="docket__header-more-options">
213
- More options
214
- </Chip>
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 key={`service-${index}`} data={service as TransferDocketType} />
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 title={title} onMoreOptionsClick={onMoreOptionsClick} />
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 title={title} onMoreOptionsClick={onMoreOptionsClick} />
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, { useState, useEffect } from "react";
2
- import Icon from "../../atoms/Icon/Icon";
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
- LocationOption,
8
- LocationGroup,
9
- LocationData,
5
+ LocationData,
6
+ LocationGroup,
7
+ LocationOption,
10
8
  } from "../../molecules/LocationDropdown/LocationDropdown";
11
- import "../../../styles/components/organism/round-trip.css";
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="round-trip__field round-trip__field--pax">
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={arrivalDate && departureDate ? [arrivalDate, departureDate] : undefined}
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, { useState, useEffect } from "react";
2
- import RoundTrip, { RoundTripData } from "../RoundTrip/RoundTrip";
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 "../../../styles/components/organism/search-bar-transfer.css";
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
- <RoundTrip
231
- id="roundtrip-main"
232
- locations={locations}
233
- paxData={roundTripData?.paxData}
234
- arrivalDate={roundTripData?.arrivalDate}
235
- departureDate={roundTripData?.departureDate}
236
- pickupDropoffPoint={roundTripData?.pickupDropoffPoint?.id as string}
237
- accommodation={roundTripData?.accommodation?.id as string}
238
- onChange={setRoundTripData}
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
- <div className="search-bar-transfer__add-buttons">
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
- <div className="search-bar-transfer__error">
366
- <div className="search-bar-transfer__error-bar" />
367
- <div className="search-bar-transfer__error-content">
368
- <Icon name="info" size="md" className="search-bar-transfer__error-icon" />
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"
@@ -3,3 +3,9 @@ export type { SearchBarTransferProps, SearchBarTransferData, TransferMode } from
3
3
 
4
4
 
5
5
 
6
+
7
+
8
+
9
+
10
+
11
+
@@ -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> columns={columns} row={child as T} rowIndex={childIndex} />
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>{column.cell({} as T[Extract<keyof T, string>], row, rowIndex)}</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
  ))}