mautourco-components 0.2.111 → 0.2.113
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/Chip/Chip.d.ts +1 -1
- package/dist/components/atoms/Chip/Chip.js +2 -2
- package/dist/components/molecules/LocationDropdown/LocationDropdown.d.ts +1 -0
- package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +5 -5
- package/dist/components/organisms/RoundTrip/RoundTrip.js +51 -32
- package/package.json +1 -1
- package/src/components/atoms/Chip/Chip.tsx +3 -3
- package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +1 -0
- package/src/components/organisms/RoundTrip/RoundTrip.tsx +97 -66
|
@@ -27,5 +27,5 @@ export interface ChipProps {
|
|
|
27
27
|
/** Icon externe */
|
|
28
28
|
externalIcon?: string;
|
|
29
29
|
}
|
|
30
|
-
declare
|
|
30
|
+
declare function Chip({ label, children, size, type, color, leadingIcon, trailingIcon, iconSize, className, isBlackText, externalIcon, onClick, }: ChipProps): import("react/jsx-runtime").JSX.Element;
|
|
31
31
|
export default Chip;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Icon from '../Icon/Icon';
|
|
3
3
|
import './Chip.css';
|
|
4
|
-
|
|
4
|
+
function Chip(_a) {
|
|
5
5
|
var label = _a.label, children = _a.children, _b = _a.size, size = _b === void 0 ? 'sm' : _b, _c = _a.type, type = _c === void 0 ? 'filled' : _c, _d = _a.color, color = _d === void 0 ? 'brand' : _d, leadingIcon = _a.leadingIcon, trailingIcon = _a.trailingIcon, _e = _a.iconSize, iconSize = _e === void 0 ? 'sm' : _e, _f = _a.className, className = _f === void 0 ? '' : _f, _g = _a.isBlackText, isBlackText = _g === void 0 ? false : _g, externalIcon = _a.externalIcon, onClick = _a.onClick;
|
|
6
6
|
var baseClasses = 'chip';
|
|
7
7
|
var sizeClass = "chip--".concat(size);
|
|
@@ -24,5 +24,5 @@ var Chip = function (_a) {
|
|
|
24
24
|
var hasTrailingIcon = Boolean(trailingIcon);
|
|
25
25
|
var content = label || children;
|
|
26
26
|
return (_jsxs("div", { className: chipClasses, onClick: onClick, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: [hasLeadingIcon && (_jsx("span", { className: "chip__icon chip__icon--leading", children: _jsx(Icon, { name: leadingIcon, size: iconSize }) })), externalIcon && (_jsx("img", { src: externalIcon, alt: "", className: "w-4 h-4 object-contain" })), _jsx("span", { className: "chip__label", children: content }), hasTrailingIcon && (_jsx("span", { className: "chip__icon chip__icon--trailing", children: _jsx(Icon, { name: trailingIcon, size: iconSize }) }))] }));
|
|
27
|
-
}
|
|
27
|
+
}
|
|
28
28
|
export default Chip;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import
|
|
3
|
-
import { LocationGroup, LocationOption } from
|
|
4
|
-
import { PaxData } from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import '../../../styles/components/organism/round-trip.css';
|
|
3
|
+
import { LocationGroup, LocationOption } from '../../molecules/LocationDropdown/LocationDropdown';
|
|
4
|
+
import { PaxData } from '../PaxSelector/PaxSelector';
|
|
5
5
|
export type { LocationOption };
|
|
6
6
|
export interface RoundTripTransfer {
|
|
7
|
-
type:
|
|
7
|
+
type: 'arrival' | 'departure';
|
|
8
8
|
paxData?: PaxData;
|
|
9
9
|
transferDate?: string;
|
|
10
10
|
pickupPoint?: LocationOption;
|
|
@@ -19,14 +19,14 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
19
19
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
20
20
|
};
|
|
21
21
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
|
-
import { useEffect, useState } from
|
|
23
|
-
import
|
|
24
|
-
import { Text } from
|
|
25
|
-
import LocationDropdown from
|
|
26
|
-
import DateTimePicker from
|
|
27
|
-
import PaxSelector from
|
|
22
|
+
import { useEffect, useState } from 'react';
|
|
23
|
+
import '../../../styles/components/organism/round-trip.css';
|
|
24
|
+
import { Text } from '../../atoms/Typography/Typography';
|
|
25
|
+
import LocationDropdown from '../../molecules/LocationDropdown/LocationDropdown';
|
|
26
|
+
import DateTimePicker from '../DateTimePicker/DateTimePicker';
|
|
27
|
+
import PaxSelector from '../PaxSelector/PaxSelector';
|
|
28
28
|
var RoundTrip = function (_a) {
|
|
29
|
-
var id = _a.id, paxData = _a.paxData, arrivalDate = _a.arrivalDate, departureDate = _a.departureDate, pickupDropoffPoint = _a.pickupDropoffPoint, accommodation = _a.accommodation, _b = _a.locations, locations = _b === void 0 ? { options: [], groups: [] } : _b, onPaxChange = _a.onPaxChange, onDatesChange = _a.onDatesChange, onPickupDropoffChange = _a.onPickupDropoffChange, onAccommodationChange = _a.onAccommodationChange, onChange = _a.onChange, _c = _a.className, className = _c === void 0 ?
|
|
29
|
+
var id = _a.id, paxData = _a.paxData, arrivalDate = _a.arrivalDate, departureDate = _a.departureDate, pickupDropoffPoint = _a.pickupDropoffPoint, accommodation = _a.accommodation, _b = _a.locations, locations = _b === void 0 ? { options: [], groups: [] } : _b, onPaxChange = _a.onPaxChange, onDatesChange = _a.onDatesChange, onPickupDropoffChange = _a.onPickupDropoffChange, onAccommodationChange = _a.onAccommodationChange, onChange = _a.onChange, _c = _a.className, className = _c === void 0 ? '' : _c, _d = _a.checkEmpty, checkEmpty = _d === void 0 ? false : _d, _e = _a.scrollOnOpen, scrollOnOpen = _e === void 0 ? false : _e;
|
|
30
30
|
var _f = useState(paxData), internalPaxData = _f[0], setInternalPaxData = _f[1];
|
|
31
31
|
var _g = useState(arrivalDate), internalArrivalDate = _g[0], setInternalArrivalDate = _g[1];
|
|
32
32
|
var _h = useState(departureDate), internalDepartureDate = _h[0], setInternalDepartureDate = _h[1];
|
|
@@ -42,18 +42,18 @@ var RoundTrip = function (_a) {
|
|
|
42
42
|
var allOptions = locations.options || [];
|
|
43
43
|
var allGroups = locations.groups || [];
|
|
44
44
|
// Filter for airport and port
|
|
45
|
-
var airportPortOptions = allOptions.filter(function (opt) { return opt.type ===
|
|
45
|
+
var airportPortOptions = allOptions.filter(function (opt) { return opt.type === 'airport' || opt.type === 'port'; });
|
|
46
46
|
// Filter for accommodations
|
|
47
|
-
var accommodationOptions = allOptions.filter(function (opt) { return opt.type ===
|
|
47
|
+
var accommodationOptions = allOptions.filter(function (opt) { return opt.type === 'accommodation'; });
|
|
48
48
|
// Create groups
|
|
49
49
|
var airportPortGroup = {
|
|
50
|
-
id:
|
|
51
|
-
label:
|
|
50
|
+
id: 'airport-port-group',
|
|
51
|
+
label: 'Airport & Port',
|
|
52
52
|
options: airportPortOptions,
|
|
53
53
|
};
|
|
54
54
|
var accommodationGroup = {
|
|
55
|
-
id:
|
|
56
|
-
label:
|
|
55
|
+
id: 'accommodation-group',
|
|
56
|
+
label: 'Accommodations',
|
|
57
57
|
options: accommodationOptions,
|
|
58
58
|
};
|
|
59
59
|
return {
|
|
@@ -65,10 +65,10 @@ var RoundTrip = function (_a) {
|
|
|
65
65
|
var allOptions = locations.options || [];
|
|
66
66
|
var allGroups = locations.groups || [];
|
|
67
67
|
// Filter for accommodations only
|
|
68
|
-
var accommodationOptions = allOptions.filter(function (opt) { return opt.type ===
|
|
68
|
+
var accommodationOptions = allOptions.filter(function (opt) { return opt.type === 'accommodation'; });
|
|
69
69
|
// Extract accommodation groups if they exist
|
|
70
70
|
var accommodationGroups = allGroups
|
|
71
|
-
.map(function (group) { return (__assign(__assign({}, group), { options: group.options.filter(function (opt) { return opt.type ===
|
|
71
|
+
.map(function (group) { return (__assign(__assign({}, group), { options: group.options.filter(function (opt) { return opt.type === 'accommodation'; }) })); })
|
|
72
72
|
.filter(function (group) { return group.options.length > 0; });
|
|
73
73
|
return {
|
|
74
74
|
options: accommodationOptions,
|
|
@@ -77,7 +77,11 @@ var RoundTrip = function (_a) {
|
|
|
77
77
|
};
|
|
78
78
|
// Helper to check if value is LocationOption
|
|
79
79
|
var isLocationOption = function (value) {
|
|
80
|
-
return typeof value === 'object' &&
|
|
80
|
+
return (typeof value === 'object' &&
|
|
81
|
+
value !== null &&
|
|
82
|
+
'id' in value &&
|
|
83
|
+
'label' in value &&
|
|
84
|
+
'type' in value);
|
|
81
85
|
};
|
|
82
86
|
// Initialize location data from IDs or LocationOption objects
|
|
83
87
|
useEffect(function () {
|
|
@@ -99,7 +103,7 @@ var RoundTrip = function (_a) {
|
|
|
99
103
|
}
|
|
100
104
|
else if (!internalPickupDropoffPoint) {
|
|
101
105
|
// Set default to first airport if available (only if not already set)
|
|
102
|
-
var defaultAirport = allLocations.find(function (loc) { return loc.type ===
|
|
106
|
+
var defaultAirport = allLocations.find(function (loc) { return loc.type === 'airport'; });
|
|
103
107
|
if (defaultAirport) {
|
|
104
108
|
setInternalPickupDropoffPoint(defaultAirport);
|
|
105
109
|
onPickupDropoffChange === null || onPickupDropoffChange === void 0 ? void 0 : onPickupDropoffChange(defaultAirport);
|
|
@@ -130,7 +134,7 @@ var RoundTrip = function (_a) {
|
|
|
130
134
|
useEffect(function () {
|
|
131
135
|
// Create arrival transfer
|
|
132
136
|
var arrivalTransfer = {
|
|
133
|
-
type:
|
|
137
|
+
type: 'arrival',
|
|
134
138
|
paxData: internalPaxData,
|
|
135
139
|
transferDate: internalArrivalDate,
|
|
136
140
|
pickupPoint: internalPickupDropoffPoint || undefined,
|
|
@@ -138,7 +142,7 @@ var RoundTrip = function (_a) {
|
|
|
138
142
|
};
|
|
139
143
|
// Create departure transfer
|
|
140
144
|
var departureTransfer = {
|
|
141
|
-
type:
|
|
145
|
+
type: 'departure',
|
|
142
146
|
paxData: internalPaxData,
|
|
143
147
|
transferDate: internalDepartureDate,
|
|
144
148
|
pickupPoint: internalAccommodation || undefined,
|
|
@@ -176,19 +180,26 @@ var RoundTrip = function (_a) {
|
|
|
176
180
|
};
|
|
177
181
|
// Helper to convert LocationData to LocationOption
|
|
178
182
|
var toLocationOption = function (locationData, locationType) {
|
|
183
|
+
var _a;
|
|
179
184
|
if (!locationData)
|
|
180
185
|
return null;
|
|
186
|
+
var locationName = (_a = locationData.locationName) !== null && _a !== void 0 ? _a : locationData.label;
|
|
181
187
|
// Try to find in the options to get the type
|
|
182
|
-
var
|
|
188
|
+
var _b = locationType === 'pickup-dropoff'
|
|
189
|
+
? getPickupDropoffOptions()
|
|
190
|
+
: getAccommodationOptions(), options = _b.options, groups = _b.groups;
|
|
183
191
|
var allLocations = getAllLocations(options, groups);
|
|
184
192
|
var found = allLocations.find(function (loc) { return loc.id === locationData.id; });
|
|
185
193
|
if (found)
|
|
186
194
|
return found;
|
|
187
195
|
// If not found, infer the type
|
|
188
|
-
var name =
|
|
196
|
+
var name = locationName.toLowerCase();
|
|
189
197
|
var id = String(locationData.id).toLowerCase();
|
|
190
198
|
var type = 'accommodation';
|
|
191
|
-
if (name.includes('harbour') ||
|
|
199
|
+
if (name.includes('harbour') ||
|
|
200
|
+
name.includes('port') ||
|
|
201
|
+
id.includes('harbour') ||
|
|
202
|
+
id.includes('port')) {
|
|
192
203
|
type = 'port';
|
|
193
204
|
}
|
|
194
205
|
else if (name.includes('airport') || id.includes('airport')) {
|
|
@@ -196,7 +207,7 @@ var RoundTrip = function (_a) {
|
|
|
196
207
|
}
|
|
197
208
|
return {
|
|
198
209
|
id: locationData.id,
|
|
199
|
-
label:
|
|
210
|
+
label: locationName,
|
|
200
211
|
type: type,
|
|
201
212
|
};
|
|
202
213
|
};
|
|
@@ -211,14 +222,18 @@ var RoundTrip = function (_a) {
|
|
|
211
222
|
onAccommodationChange === null || onAccommodationChange === void 0 ? void 0 : onAccommodationChange(locationOption);
|
|
212
223
|
};
|
|
213
224
|
// Check if inputs are empty (when checkEmpty is true)
|
|
214
|
-
var isPaxEmpty = checkEmpty &&
|
|
215
|
-
(internalPaxData
|
|
216
|
-
internalPaxData.
|
|
217
|
-
|
|
218
|
-
|
|
225
|
+
var isPaxEmpty = checkEmpty &&
|
|
226
|
+
(!internalPaxData ||
|
|
227
|
+
(internalPaxData.adults === 0 &&
|
|
228
|
+
internalPaxData.teens === 0 &&
|
|
229
|
+
internalPaxData.children === 0 &&
|
|
230
|
+
(internalPaxData.infants === undefined || internalPaxData.infants === 0)));
|
|
219
231
|
// Show error if checkEmpty is true and either date is missing
|
|
220
|
-
var isDateEmpty = checkEmpty &&
|
|
221
|
-
internalArrivalDate
|
|
232
|
+
var isDateEmpty = checkEmpty &&
|
|
233
|
+
(!internalArrivalDate ||
|
|
234
|
+
!internalDepartureDate ||
|
|
235
|
+
internalArrivalDate === '' ||
|
|
236
|
+
internalDepartureDate === '');
|
|
222
237
|
// Check if user filled one date but not the other (even without checkEmpty)
|
|
223
238
|
var hasPartialDates = function () {
|
|
224
239
|
if (!checkEmpty)
|
|
@@ -243,12 +258,16 @@ var RoundTrip = function (_a) {
|
|
|
243
258
|
return value;
|
|
244
259
|
}
|
|
245
260
|
// Otherwise, look up by ID in the locations
|
|
246
|
-
var _a = locationType === 'pickup-dropoff'
|
|
261
|
+
var _a = locationType === 'pickup-dropoff'
|
|
262
|
+
? getPickupDropoffOptions()
|
|
263
|
+
: getAccommodationOptions(), options = _a.options, groups = _a.groups;
|
|
247
264
|
var allLocations = getAllLocations(options, groups);
|
|
248
265
|
return allLocations.find(function (loc) { return loc.id === value; });
|
|
249
266
|
};
|
|
250
267
|
var defaultPickupDropoffOption = findLocationOption(pickupDropoffPoint, 'pickup-dropoff');
|
|
251
268
|
var defaultAccommodationOption = findLocationOption(accommodation, 'accommodation');
|
|
252
|
-
return (_jsx("div", { className: "round-trip ".concat(className), "data-round-trip-id": id, children: _jsxs("div", { className: "round-trip__content", children: [_jsx("div", { className: "round-trip__field round-trip__field--pax ".concat(isPaxEmpty ? 'round-trip__field--error' : ''), children: _jsx(PaxSelector, { label: "Number of pax", value: internalPaxData, onChange: handlePaxChange, placeholder: "2 pax", className: isPaxEmpty ? 'pax-selector--error' : '', scrollOnOpen: scrollOnOpen, checkEmpty: checkEmpty }) }), _jsxs("div", { className: "round-trip__field round-trip__field--dates", children: [_jsx(Text, { size: "sm", variant: "regular", className: "round-trip__field-label", children: "Arrival date - Departure date" }), _jsx(DateTimePicker, { placeholder: "DD/MM/YYYY - DD/MM/YYYY", mode: "calendar", iconPosition: "left", numberOfMonths: 2, iconBGFull: false, showChevron: true, onValueChange: handleDateRangeChange, selectionMode: "range", defaultValue: internalArrivalDate && internalDepartureDate
|
|
269
|
+
return (_jsx("div", { className: "round-trip ".concat(className), "data-round-trip-id": id, children: _jsxs("div", { className: "round-trip__content", children: [_jsx("div", { className: "round-trip__field round-trip__field--pax ".concat(isPaxEmpty ? 'round-trip__field--error' : ''), children: _jsx(PaxSelector, { label: "Number of pax", value: internalPaxData, onChange: handlePaxChange, placeholder: "2 pax", className: isPaxEmpty ? 'pax-selector--error' : '', scrollOnOpen: scrollOnOpen, checkEmpty: checkEmpty }) }), _jsxs("div", { className: "round-trip__field round-trip__field--dates", children: [_jsx(Text, { size: "sm", variant: "regular", className: "round-trip__field-label", children: "Arrival date - Departure date" }), _jsx(DateTimePicker, { placeholder: "DD/MM/YYYY - DD/MM/YYYY", mode: "calendar", iconPosition: "left", numberOfMonths: 2, iconBGFull: false, showChevron: true, onValueChange: handleDateRangeChange, selectionMode: "range", defaultValue: internalArrivalDate && internalDepartureDate
|
|
270
|
+
? [internalArrivalDate, internalDepartureDate]
|
|
271
|
+
: undefined, inputClassName: "round-trip__date-picker--input", state: isDateError() ? 'error' : undefined, scrollOnOpen: scrollOnOpen })] }), _jsx("div", { className: "round-trip__field round-trip__field--pickup-dropoff", children: _jsx(LocationDropdown, { label: "Pick up / Drop-off point", options: pickupDropoffOptions.options, groups: pickupDropoffOptions.groups, selectedValue: (internalPickupDropoffPoint === null || internalPickupDropoffPoint === void 0 ? void 0 : internalPickupDropoffPoint.id) || null, onSelectionChange: handlePickupDropoffChange, placeholder: "Select pick-up / drop-off point", direction: undefined, type: "airport-port", showGroupTitles: true, error: isPickupDropoffEmpty, scrollOnOpen: scrollOnOpen, defaultValue: defaultPickupDropoffOption }) }), _jsx("div", { className: "round-trip__field round-trip__field--accommodation", children: _jsx(LocationDropdown, { label: "Accommodation", options: accommodationOptions.options, groups: accommodationOptions.groups, selectedValue: (internalAccommodation === null || internalAccommodation === void 0 ? void 0 : internalAccommodation.id) || null, onSelectionChange: handleAccommodationChange, placeholder: "Select accommodation", direction: "dropoff", type: "accommodation", showGroupTitles: false, error: isAccommodationEmpty, scrollOnOpen: scrollOnOpen, defaultValue: defaultAccommodationOption }) })] }) }));
|
|
253
272
|
};
|
|
254
273
|
export default RoundTrip;
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@ export interface ChipProps {
|
|
|
29
29
|
externalIcon?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
function Chip({
|
|
33
33
|
label,
|
|
34
34
|
children,
|
|
35
35
|
size = 'sm',
|
|
@@ -42,7 +42,7 @@ const Chip: React.FC<ChipProps> = ({
|
|
|
42
42
|
isBlackText = false,
|
|
43
43
|
externalIcon,
|
|
44
44
|
onClick,
|
|
45
|
-
})
|
|
45
|
+
}: ChipProps) {
|
|
46
46
|
const baseClasses = 'chip';
|
|
47
47
|
const sizeClass = `chip--${size}`;
|
|
48
48
|
const typeClass = `chip--${type}`;
|
|
@@ -88,6 +88,6 @@ const Chip: React.FC<ChipProps> = ({
|
|
|
88
88
|
)}
|
|
89
89
|
</div>
|
|
90
90
|
);
|
|
91
|
-
}
|
|
91
|
+
}
|
|
92
92
|
|
|
93
93
|
export default Chip;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import React, { useEffect, useState } from
|
|
2
|
-
import
|
|
3
|
-
import { Text } from
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import '../../../styles/components/organism/round-trip.css';
|
|
3
|
+
import { Text } from '../../atoms/Typography/Typography';
|
|
4
4
|
import LocationDropdown, {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from
|
|
9
|
-
import DateTimePicker from
|
|
10
|
-
import PaxSelector, { PaxData } from
|
|
5
|
+
LocationData,
|
|
6
|
+
LocationGroup,
|
|
7
|
+
LocationOption,
|
|
8
|
+
} from '../../molecules/LocationDropdown/LocationDropdown';
|
|
9
|
+
import DateTimePicker from '../DateTimePicker/DateTimePicker';
|
|
10
|
+
import PaxSelector, { PaxData } from '../PaxSelector/PaxSelector';
|
|
11
11
|
|
|
12
12
|
// Re-export LocationOption for convenience
|
|
13
13
|
export type { LocationOption };
|
|
14
14
|
|
|
15
15
|
export interface RoundTripTransfer {
|
|
16
|
-
type:
|
|
16
|
+
type: 'arrival' | 'departure';
|
|
17
17
|
paxData?: PaxData;
|
|
18
18
|
transferDate?: string;
|
|
19
19
|
pickupPoint?: LocationOption;
|
|
@@ -79,19 +79,17 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
79
79
|
onPickupDropoffChange,
|
|
80
80
|
onAccommodationChange,
|
|
81
81
|
onChange,
|
|
82
|
-
className =
|
|
82
|
+
className = '',
|
|
83
83
|
checkEmpty = false,
|
|
84
84
|
scrollOnOpen = false,
|
|
85
85
|
}) => {
|
|
86
|
-
const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(
|
|
87
|
-
|
|
86
|
+
const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(paxData);
|
|
87
|
+
const [internalArrivalDate, setInternalArrivalDate] = useState<string | undefined>(
|
|
88
|
+
arrivalDate
|
|
89
|
+
);
|
|
90
|
+
const [internalDepartureDate, setInternalDepartureDate] = useState<string | undefined>(
|
|
91
|
+
departureDate
|
|
88
92
|
);
|
|
89
|
-
const [internalArrivalDate, setInternalArrivalDate] = useState<
|
|
90
|
-
string | undefined
|
|
91
|
-
>(arrivalDate);
|
|
92
|
-
const [internalDepartureDate, setInternalDepartureDate] = useState<
|
|
93
|
-
string | undefined
|
|
94
|
-
>(departureDate);
|
|
95
93
|
const [internalPickupDropoffPoint, setInternalPickupDropoffPoint] =
|
|
96
94
|
useState<LocationOption | null>(null);
|
|
97
95
|
const [internalAccommodation, setInternalAccommodation] =
|
|
@@ -113,32 +111,28 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
113
111
|
|
|
114
112
|
// Filter for airport and port
|
|
115
113
|
const airportPortOptions = allOptions.filter(
|
|
116
|
-
(opt) => opt.type ===
|
|
114
|
+
(opt) => opt.type === 'airport' || opt.type === 'port'
|
|
117
115
|
);
|
|
118
116
|
|
|
119
117
|
// Filter for accommodations
|
|
120
|
-
const accommodationOptions = allOptions.filter(
|
|
121
|
-
(opt) => opt.type === "accommodation"
|
|
122
|
-
);
|
|
118
|
+
const accommodationOptions = allOptions.filter((opt) => opt.type === 'accommodation');
|
|
123
119
|
|
|
124
120
|
// Create groups
|
|
125
121
|
const airportPortGroup: LocationGroup = {
|
|
126
|
-
id:
|
|
127
|
-
label:
|
|
122
|
+
id: 'airport-port-group',
|
|
123
|
+
label: 'Airport & Port',
|
|
128
124
|
options: airportPortOptions,
|
|
129
125
|
};
|
|
130
126
|
|
|
131
127
|
const accommodationGroup: LocationGroup = {
|
|
132
|
-
id:
|
|
133
|
-
label:
|
|
128
|
+
id: 'accommodation-group',
|
|
129
|
+
label: 'Accommodations',
|
|
134
130
|
options: accommodationOptions,
|
|
135
131
|
};
|
|
136
132
|
|
|
137
133
|
return {
|
|
138
134
|
options: [],
|
|
139
|
-
groups: [airportPortGroup, accommodationGroup].filter(
|
|
140
|
-
(g) => g.options.length > 0
|
|
141
|
-
),
|
|
135
|
+
groups: [airportPortGroup, accommodationGroup].filter((g) => g.options.length > 0),
|
|
142
136
|
};
|
|
143
137
|
};
|
|
144
138
|
|
|
@@ -147,15 +141,13 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
147
141
|
const allGroups = locations.groups || [];
|
|
148
142
|
|
|
149
143
|
// Filter for accommodations only
|
|
150
|
-
const accommodationOptions = allOptions.filter(
|
|
151
|
-
(opt) => opt.type === "accommodation"
|
|
152
|
-
);
|
|
144
|
+
const accommodationOptions = allOptions.filter((opt) => opt.type === 'accommodation');
|
|
153
145
|
|
|
154
146
|
// Extract accommodation groups if they exist
|
|
155
147
|
const accommodationGroups = allGroups
|
|
156
148
|
.map((group) => ({
|
|
157
149
|
...group,
|
|
158
|
-
options: group.options.filter((opt) => opt.type ===
|
|
150
|
+
options: group.options.filter((opt) => opt.type === 'accommodation'),
|
|
159
151
|
}))
|
|
160
152
|
.filter((group) => group.options.length > 0);
|
|
161
153
|
|
|
@@ -166,8 +158,16 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
166
158
|
};
|
|
167
159
|
|
|
168
160
|
// Helper to check if value is LocationOption
|
|
169
|
-
const isLocationOption = (
|
|
170
|
-
|
|
161
|
+
const isLocationOption = (
|
|
162
|
+
value: string | LocationOption | undefined
|
|
163
|
+
): value is LocationOption => {
|
|
164
|
+
return (
|
|
165
|
+
typeof value === 'object' &&
|
|
166
|
+
value !== null &&
|
|
167
|
+
'id' in value &&
|
|
168
|
+
'label' in value &&
|
|
169
|
+
'type' in value
|
|
170
|
+
);
|
|
171
171
|
};
|
|
172
172
|
|
|
173
173
|
// Initialize location data from IDs or LocationOption objects
|
|
@@ -185,15 +185,13 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
185
185
|
const allLocations = getAllLocations(options, groups);
|
|
186
186
|
|
|
187
187
|
if (pickupDropoffPoint) {
|
|
188
|
-
const location = allLocations.find(
|
|
189
|
-
(loc) => loc.id === pickupDropoffPoint
|
|
190
|
-
);
|
|
188
|
+
const location = allLocations.find((loc) => loc.id === pickupDropoffPoint);
|
|
191
189
|
if (location && internalPickupDropoffPoint?.id !== location.id) {
|
|
192
190
|
setInternalPickupDropoffPoint(location);
|
|
193
191
|
}
|
|
194
192
|
} else if (!internalPickupDropoffPoint) {
|
|
195
193
|
// Set default to first airport if available (only if not already set)
|
|
196
|
-
const defaultAirport = allLocations.find((loc) => loc.type ===
|
|
194
|
+
const defaultAirport = allLocations.find((loc) => loc.type === 'airport');
|
|
197
195
|
if (defaultAirport) {
|
|
198
196
|
setInternalPickupDropoffPoint(defaultAirport);
|
|
199
197
|
onPickupDropoffChange?.(defaultAirport);
|
|
@@ -228,7 +226,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
228
226
|
useEffect(() => {
|
|
229
227
|
// Create arrival transfer
|
|
230
228
|
const arrivalTransfer: RoundTripTransfer = {
|
|
231
|
-
type:
|
|
229
|
+
type: 'arrival',
|
|
232
230
|
paxData: internalPaxData,
|
|
233
231
|
transferDate: internalArrivalDate,
|
|
234
232
|
pickupPoint: internalPickupDropoffPoint || undefined,
|
|
@@ -237,7 +235,7 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
237
235
|
|
|
238
236
|
// Create departure transfer
|
|
239
237
|
const departureTransfer: RoundTripTransfer = {
|
|
240
|
-
type:
|
|
238
|
+
type: 'departure',
|
|
241
239
|
paxData: internalPaxData,
|
|
242
240
|
transferDate: internalDepartureDate,
|
|
243
241
|
pickupPoint: internalAccommodation || undefined,
|
|
@@ -279,28 +277,41 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
279
277
|
};
|
|
280
278
|
|
|
281
279
|
// Helper to convert LocationData to LocationOption
|
|
282
|
-
const toLocationOption = (
|
|
280
|
+
const toLocationOption = (
|
|
281
|
+
locationData: LocationData | null,
|
|
282
|
+
locationType: 'pickup-dropoff' | 'accommodation'
|
|
283
|
+
): LocationOption | null => {
|
|
283
284
|
if (!locationData) return null;
|
|
284
|
-
|
|
285
|
+
|
|
286
|
+
const locationName = locationData.locationName ?? locationData.label;
|
|
287
|
+
|
|
285
288
|
// Try to find in the options to get the type
|
|
286
|
-
const { options, groups } =
|
|
289
|
+
const { options, groups } =
|
|
290
|
+
locationType === 'pickup-dropoff'
|
|
291
|
+
? getPickupDropoffOptions()
|
|
292
|
+
: getAccommodationOptions();
|
|
287
293
|
const allLocations = getAllLocations(options, groups);
|
|
288
294
|
const found = allLocations.find((loc) => loc.id === locationData.id);
|
|
289
295
|
if (found) return found;
|
|
290
|
-
|
|
296
|
+
|
|
291
297
|
// If not found, infer the type
|
|
292
|
-
const name =
|
|
298
|
+
const name = locationName.toLowerCase();
|
|
293
299
|
const id = String(locationData.id).toLowerCase();
|
|
294
300
|
let type: 'airport' | 'port' | 'accommodation' = 'accommodation';
|
|
295
|
-
if (
|
|
301
|
+
if (
|
|
302
|
+
name.includes('harbour') ||
|
|
303
|
+
name.includes('port') ||
|
|
304
|
+
id.includes('harbour') ||
|
|
305
|
+
id.includes('port')
|
|
306
|
+
) {
|
|
296
307
|
type = 'port';
|
|
297
308
|
} else if (name.includes('airport') || id.includes('airport')) {
|
|
298
309
|
type = 'airport';
|
|
299
310
|
}
|
|
300
|
-
|
|
311
|
+
|
|
301
312
|
return {
|
|
302
313
|
id: locationData.id,
|
|
303
|
-
label:
|
|
314
|
+
label: locationName,
|
|
304
315
|
type,
|
|
305
316
|
};
|
|
306
317
|
};
|
|
@@ -318,23 +329,29 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
318
329
|
};
|
|
319
330
|
|
|
320
331
|
// Check if inputs are empty (when checkEmpty is true)
|
|
321
|
-
const isPaxEmpty =
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
332
|
+
const isPaxEmpty =
|
|
333
|
+
checkEmpty &&
|
|
334
|
+
(!internalPaxData ||
|
|
335
|
+
(internalPaxData.adults === 0 &&
|
|
336
|
+
internalPaxData.teens === 0 &&
|
|
337
|
+
internalPaxData.children === 0 &&
|
|
338
|
+
(internalPaxData.infants === undefined || internalPaxData.infants === 0)));
|
|
326
339
|
|
|
327
340
|
// Show error if checkEmpty is true and either date is missing
|
|
328
|
-
const isDateEmpty =
|
|
329
|
-
|
|
330
|
-
|
|
341
|
+
const isDateEmpty =
|
|
342
|
+
checkEmpty &&
|
|
343
|
+
(!internalArrivalDate ||
|
|
344
|
+
!internalDepartureDate ||
|
|
345
|
+
internalArrivalDate === '' ||
|
|
346
|
+
internalDepartureDate === '');
|
|
347
|
+
|
|
331
348
|
// Check if user filled one date but not the other (even without checkEmpty)
|
|
332
349
|
const hasPartialDates = (): boolean => {
|
|
333
350
|
if (!checkEmpty) return false;
|
|
334
351
|
if (!internalArrivalDate || !internalDepartureDate) return true;
|
|
335
352
|
return internalArrivalDate === internalDepartureDate;
|
|
336
353
|
};
|
|
337
|
-
|
|
354
|
+
|
|
338
355
|
const isDateError = (): boolean => {
|
|
339
356
|
return isDateEmpty || hasPartialDates();
|
|
340
357
|
};
|
|
@@ -347,27 +364,37 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
347
364
|
const accommodationOptions = getAccommodationOptions();
|
|
348
365
|
|
|
349
366
|
// Helper function to find LocationOption from ID or LocationOption for defaultValue
|
|
350
|
-
const findLocationOption = (
|
|
367
|
+
const findLocationOption = (
|
|
368
|
+
value: string | LocationOption | undefined,
|
|
369
|
+
locationType: 'pickup-dropoff' | 'accommodation'
|
|
370
|
+
): LocationOption | undefined => {
|
|
351
371
|
if (!value) return undefined;
|
|
352
|
-
|
|
372
|
+
|
|
353
373
|
// If value is already a LocationOption object, use it directly
|
|
354
374
|
if (isLocationOption(value)) {
|
|
355
375
|
return value;
|
|
356
376
|
}
|
|
357
|
-
|
|
377
|
+
|
|
358
378
|
// Otherwise, look up by ID in the locations
|
|
359
|
-
const { options, groups } =
|
|
379
|
+
const { options, groups } =
|
|
380
|
+
locationType === 'pickup-dropoff'
|
|
381
|
+
? getPickupDropoffOptions()
|
|
382
|
+
: getAccommodationOptions();
|
|
360
383
|
const allLocations = getAllLocations(options, groups);
|
|
361
384
|
return allLocations.find((loc) => loc.id === value);
|
|
362
385
|
};
|
|
363
386
|
|
|
364
|
-
const defaultPickupDropoffOption = findLocationOption(
|
|
387
|
+
const defaultPickupDropoffOption = findLocationOption(
|
|
388
|
+
pickupDropoffPoint,
|
|
389
|
+
'pickup-dropoff'
|
|
390
|
+
);
|
|
365
391
|
const defaultAccommodationOption = findLocationOption(accommodation, 'accommodation');
|
|
366
392
|
|
|
367
393
|
return (
|
|
368
394
|
<div className={`round-trip ${className}`} data-round-trip-id={id}>
|
|
369
395
|
<div className="round-trip__content">
|
|
370
|
-
<div
|
|
396
|
+
<div
|
|
397
|
+
className={`round-trip__field round-trip__field--pax ${isPaxEmpty ? 'round-trip__field--error' : ''}`}>
|
|
371
398
|
<PaxSelector
|
|
372
399
|
label="Number of pax"
|
|
373
400
|
value={internalPaxData}
|
|
@@ -392,7 +419,11 @@ const RoundTrip: React.FC<RoundTripProps> = ({
|
|
|
392
419
|
showChevron={true}
|
|
393
420
|
onValueChange={handleDateRangeChange}
|
|
394
421
|
selectionMode="range"
|
|
395
|
-
defaultValue={
|
|
422
|
+
defaultValue={
|
|
423
|
+
internalArrivalDate && internalDepartureDate
|
|
424
|
+
? [internalArrivalDate, internalDepartureDate]
|
|
425
|
+
: undefined
|
|
426
|
+
}
|
|
396
427
|
inputClassName="round-trip__date-picker--input"
|
|
397
428
|
state={isDateError() ? 'error' : undefined}
|
|
398
429
|
scrollOnOpen={scrollOnOpen}
|