mautourco-components 0.2.103 → 0.2.105
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/molecules/LocationDropdown/LocationDropdown.js +11 -6
- package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +1 -0
- package/dist/components/organisms/PaxSelector/PaxSelector.js +3 -2
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +3 -1
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +2 -2
- package/dist/components/organisms/TransferLine/TransferLine.d.ts +2 -0
- package/dist/components/organisms/TransferLine/TransferLine.js +11 -4
- package/dist/lib/utils.js +10 -5
- package/dist/styles/components/organism/pax-selector.css +41 -14
- package/package.json +1 -1
- package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +52 -44
- package/src/components/organisms/PaxSelector/PaxSelector.tsx +10 -2
- package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +4 -0
- package/src/components/organisms/TransferLine/TransferLine.tsx +36 -13
- package/src/styles/components/organism/pax-selector.css +42 -17
|
@@ -29,6 +29,7 @@ var LocationDropdown = function (_a) {
|
|
|
29
29
|
var _q = useState(false), isOpen = _q[0], setIsOpen = _q[1];
|
|
30
30
|
var _r = useState(''), searchQuery = _r[0], setSearchQuery = _r[1];
|
|
31
31
|
var dropdownRef = useRef(null);
|
|
32
|
+
var dropdownPanelRef = useRef(null);
|
|
32
33
|
var inputRef = useRef(null);
|
|
33
34
|
var searchInputRef = useRef(null);
|
|
34
35
|
// Close dropdown when clicking outside
|
|
@@ -45,7 +46,11 @@ var LocationDropdown = function (_a) {
|
|
|
45
46
|
}, []);
|
|
46
47
|
// Scroll to input when dropdown opens (if scrollOnOpen is true)
|
|
47
48
|
useEffect(function () {
|
|
48
|
-
|
|
49
|
+
setTimeout(function () {
|
|
50
|
+
if (dropdownPanelRef.current) {
|
|
51
|
+
scrollIntoViewOnOpen(dropdownPanelRef, isOpen, scrollOnOpen);
|
|
52
|
+
}
|
|
53
|
+
}, 10);
|
|
49
54
|
}, [isOpen, scrollOnOpen]);
|
|
50
55
|
// Reset search when dropdown closes
|
|
51
56
|
useEffect(function () {
|
|
@@ -88,9 +93,7 @@ var LocationDropdown = function (_a) {
|
|
|
88
93
|
if (!searchQuery.trim())
|
|
89
94
|
return opts;
|
|
90
95
|
var query = searchQuery.toLowerCase();
|
|
91
|
-
return opts.filter(function (option) {
|
|
92
|
-
return option.label.toLowerCase().includes(query);
|
|
93
|
-
});
|
|
96
|
+
return opts.filter(function (option) { return option.label.toLowerCase().includes(query); });
|
|
94
97
|
};
|
|
95
98
|
var getSelectedOption = function () {
|
|
96
99
|
if (selectedValue) {
|
|
@@ -156,13 +159,15 @@ var LocationDropdown = function (_a) {
|
|
|
156
159
|
var displayText = selectedOption ? selectedOption.label : placeholder;
|
|
157
160
|
// Prepare all options (flat or grouped) and filter them
|
|
158
161
|
var allOptionsRaw = groups.length > 0 ? groups : [{ id: 'default', label: '', options: options }];
|
|
159
|
-
var allOptions = allOptionsRaw
|
|
162
|
+
var allOptions = allOptionsRaw
|
|
163
|
+
.map(function (group) { return (__assign(__assign({}, group), { options: filterOptions(group.options) })); })
|
|
164
|
+
.filter(function (group) { return group.options.length > 0; });
|
|
160
165
|
// Skeleton loader component
|
|
161
166
|
var SkeletonOption = function () { return (_jsxs("div", { className: "location-dropdown__option location-dropdown__option--skeleton", children: [_jsx("div", { className: "location-dropdown__skeleton-icon" }), _jsx("div", { className: "location-dropdown__skeleton-text" })] })); };
|
|
162
167
|
// Render skeleton loading state
|
|
163
168
|
var renderSkeletonLoading = function () { return (_jsx("div", { className: "location-dropdown__panel", children: _jsx("div", { className: "location-dropdown__content", style: { maxHeight: "".concat(maxHeight, "px") }, children: _jsx("div", { className: "location-dropdown__options-wrapper", children: _jsx("div", { className: "location-dropdown__group", children: _jsx("div", { className: "location-dropdown__group-options", children: __spreadArray([], Array(5), true).map(function (_, index) { return (_jsx(SkeletonOption, {}, "skeleton-".concat(index))); }) }) }) }) }) })); };
|
|
164
169
|
return (_jsxs("div", { ref: dropdownRef, className: "location-dropdown location-dropdown--".concat(type, " ").concat(disabled ? 'location-dropdown--disabled' : '', " ").concat(className), children: [label && (_jsx("div", { className: "location-dropdown__label", children: _jsx(Text, { size: "sm", variant: "medium", children: label }) })), _jsxs("div", { ref: inputRef, className: "location-dropdown__input location-dropdown__input--".concat(getDropdownState()), onClick: handleToggleDropdown, children: [_jsxs("div", { className: "location-dropdown__input-content", children: [_jsx(Icon, { name: getInputIcon(), size: "sm", className: "location-dropdown__input-icon ".concat(!selectedOption ? 'location-dropdown__input-icon--placeholder' : '') }), isOpen ? (_jsx("input", { ref: searchInputRef, type: "text", className: "location-dropdown__input-text ".concat(!selectedOption && !searchQuery ? 'location-dropdown__input-text--placeholder' : ''), placeholder: displayText, value: searchQuery, onChange: handleSearchChange, onClick: function (e) { return e.stopPropagation(); }, disabled: disabled, autoFocus: true })) : (_jsx("span", { className: "location-dropdown__input-text ".concat(!selectedOption ? 'location-dropdown__input-text--placeholder' : ''), children: displayText }))] }), _jsx(Icon, { name: "chevron-down", size: "sm", className: "location-dropdown__input-chevron" })] }), isOpen &&
|
|
165
|
-
(loading ? (renderSkeletonLoading()) : (_jsx("div", { className: "location-dropdown__panel", children: _jsx("div", { className: "location-dropdown__content", style: { maxHeight: "".concat(maxHeight, "px") }, children: _jsx("div", { className: "location-dropdown__options-wrapper", children: allOptions.length === 0 ? (_jsx("div", { className: "location-dropdown__no-results", children: _jsx(Text, { size: "sm", variant: "medium", children: "No locations found" }) })) : (allOptions.map(function (group, groupIndex) { return (_jsxs("div", { className: "location-dropdown__group", children: [showGroupTitles && group.label && groups.length > 0 && (_jsxs(_Fragment, { children: [groupIndex > 0 && _jsx("div", { className: "location-dropdown__divider" }), _jsx("div", { className: "location-dropdown__group-header", children: _jsx(Text, { size: "xs", variant: "bold", children: group.label }) })] })), _jsx("div", { className: "location-dropdown__group-options", children: group.options.map(function (option) {
|
|
170
|
+
(loading ? (renderSkeletonLoading()) : (_jsx("div", { className: "location-dropdown__panel", ref: dropdownPanelRef, children: _jsx("div", { className: "location-dropdown__content", style: { maxHeight: "".concat(maxHeight, "px") }, children: _jsx("div", { className: "location-dropdown__options-wrapper", children: allOptions.length === 0 ? (_jsx("div", { className: "location-dropdown__no-results", children: _jsx(Text, { size: "sm", variant: "medium", children: "No locations found" }) })) : (allOptions.map(function (group, groupIndex) { return (_jsxs("div", { className: "location-dropdown__group", children: [showGroupTitles && group.label && groups.length > 0 && (_jsxs(_Fragment, { children: [groupIndex > 0 && (_jsx("div", { className: "location-dropdown__divider" })), _jsx("div", { className: "location-dropdown__group-header", children: _jsx(Text, { size: "xs", variant: "bold", children: group.label }) })] })), _jsx("div", { className: "location-dropdown__group-options", children: group.options.map(function (option) {
|
|
166
171
|
var isSelected = effectiveSelectedValue === option.id;
|
|
167
172
|
var isDisabled = option.disabled || disabled;
|
|
168
173
|
return (_jsxs("div", { className: "location-dropdown__option ".concat(isSelected ? 'location-dropdown__option--selected' : '', " ").concat(isDisabled ? 'location-dropdown__option--disabled' : ''), onClick: function () { return !isDisabled && handleOptionSelect(option); }, children: [_jsx(Icon, { name: getOptionIcon(option, isSelected), size: "sm", className: "location-dropdown__option-icon" }), _jsx("span", { className: "location-dropdown__option-text", children: option.label })] }, option.id));
|
|
@@ -66,6 +66,7 @@ export interface PaxSelectorProps {
|
|
|
66
66
|
ageRange?: number[];
|
|
67
67
|
/** Whether to check if age inputs are empty and show error state */
|
|
68
68
|
checkEmpty?: boolean;
|
|
69
|
+
onPaxOpenChange?: () => void;
|
|
69
70
|
}
|
|
70
71
|
export declare const DEFAULT_PAX_DATA_WITH_ADULTS: PaxData;
|
|
71
72
|
export declare const CHILD_CATEGORY_AGES: number[];
|
|
@@ -183,7 +183,7 @@ var RoomEditor = function (_a) {
|
|
|
183
183
|
}) }, "infant-chunk-".concat(chunkIndex))); })] })] })), _jsx(ClientTypeSelector, { value: room.clientType, onChange: function (val) { return handleFieldChange('clientType', val); } })] })] }));
|
|
184
184
|
};
|
|
185
185
|
var PaxSelector = function (_a) {
|
|
186
|
-
var _b = _a.label, label = _b === void 0 ? 'Number of pax' : _b, value = _a.value, onChange = _a.onChange, onAddRoom = _a.onAddRoom, onDone = _a.onDone, _c = _a.placeholder, placeholder = _c === void 0 ? 'Select pax' : _c, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.maxAdults, maxAdults = _e === void 0 ? 10 : _e, _f = _a.maxTeens, maxTeens = _f === void 0 ? 10 : _f, _g = _a.maxChildren, maxChildren = _g === void 0 ? 10 : _g, _h = _a.maxInfants, maxInfants = _h === void 0 ? 10 : _h, _j = _a.showAddRoom, showAddRoom = _j === void 0 ? true : _j, _k = _a.multipleRooms, multipleRooms = _k === void 0 ? false : _k, defaultRooms = _a.defaultRooms, onRoomsChange = _a.onRoomsChange, onRemoveRoom = _a.onRemoveRoom, _l = _a.defaultPaxData, defaultPaxData = _l === void 0 ? DEFAULT_PAX_DATA_WITH_ADULTS : _l, _m = _a.ageRange, ageRange = _m === void 0 ? CHILD_CATEGORY_AGES : _m, _o = _a.scrollOnOpen, scrollOnOpen = _o === void 0 ? false : _o, _p = _a.disabled, disabled = _p === void 0 ? false : _p, _q = _a.checkEmpty, checkEmpty = _q === void 0 ? false : _q;
|
|
186
|
+
var _b = _a.label, label = _b === void 0 ? 'Number of pax' : _b, value = _a.value, onChange = _a.onChange, onAddRoom = _a.onAddRoom, onDone = _a.onDone, _c = _a.placeholder, placeholder = _c === void 0 ? 'Select pax' : _c, _d = _a.className, className = _d === void 0 ? '' : _d, _e = _a.maxAdults, maxAdults = _e === void 0 ? 10 : _e, _f = _a.maxTeens, maxTeens = _f === void 0 ? 10 : _f, _g = _a.maxChildren, maxChildren = _g === void 0 ? 10 : _g, _h = _a.maxInfants, maxInfants = _h === void 0 ? 10 : _h, _j = _a.showAddRoom, showAddRoom = _j === void 0 ? true : _j, _k = _a.multipleRooms, multipleRooms = _k === void 0 ? false : _k, defaultRooms = _a.defaultRooms, onRoomsChange = _a.onRoomsChange, onRemoveRoom = _a.onRemoveRoom, _l = _a.defaultPaxData, defaultPaxData = _l === void 0 ? DEFAULT_PAX_DATA_WITH_ADULTS : _l, _m = _a.ageRange, ageRange = _m === void 0 ? CHILD_CATEGORY_AGES : _m, _o = _a.scrollOnOpen, scrollOnOpen = _o === void 0 ? false : _o, _p = _a.disabled, disabled = _p === void 0 ? false : _p, _q = _a.checkEmpty, checkEmpty = _q === void 0 ? false : _q, onPaxOpenChange = _a.onPaxOpenChange;
|
|
187
187
|
var _r = useState(false), isOpen = _r[0], setIsOpen = _r[1];
|
|
188
188
|
var _s = useState(value || defaultPaxData || DEFAULT_PAX_DATA), internalData = _s[0], setInternalData = _s[1];
|
|
189
189
|
var _t = useState(defaultRooms || [__assign(__assign({}, DEFAULT_PAX_DATA), { roomId: '1' })]), rooms = _t[0], setRooms = _t[1];
|
|
@@ -312,7 +312,7 @@ var PaxSelector = function (_a) {
|
|
|
312
312
|
if (multipleRooms) {
|
|
313
313
|
return rooms.some(function (room) { return room.teens > 0 || room.children > 0 || room.infants > 0; });
|
|
314
314
|
}
|
|
315
|
-
return internalData.teens > 0 || internalData.children > 0 || internalData.infants > 0;
|
|
315
|
+
return (internalData.teens > 0 || internalData.children > 0 || internalData.infants > 0);
|
|
316
316
|
};
|
|
317
317
|
// Handle clicks outside the dropdown
|
|
318
318
|
useEffect(function () {
|
|
@@ -327,6 +327,7 @@ var PaxSelector = function (_a) {
|
|
|
327
327
|
if (isOpen) {
|
|
328
328
|
document.addEventListener('mousedown', handleClickOutside);
|
|
329
329
|
}
|
|
330
|
+
onPaxOpenChange === null || onPaxOpenChange === void 0 ? void 0 : onPaxOpenChange();
|
|
330
331
|
return function () {
|
|
331
332
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
332
333
|
};
|
|
@@ -33,6 +33,8 @@ export interface SearchBarTransferProps {
|
|
|
33
33
|
className?: string;
|
|
34
34
|
/** Whether to scroll to the input when the calendar opens */
|
|
35
35
|
scrollOnOpen?: boolean;
|
|
36
|
+
/** Callback when pax selector opens */
|
|
37
|
+
onPaxOpenChange?: () => void;
|
|
36
38
|
}
|
|
37
|
-
declare function SearchBarTransfer({ mode: initialMode, locations, defaultRoundTripData, defaultTransferLines, defaultSameVehicle, onSearch, onChange, onRemove, className, scrollOnOpen, }: SearchBarTransferProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
declare function SearchBarTransfer({ mode: initialMode, locations, defaultRoundTripData, defaultTransferLines, defaultSameVehicle, onSearch, onChange, onRemove, className, scrollOnOpen, onPaxOpenChange, }: SearchBarTransferProps): import("react/jsx-runtime").JSX.Element;
|
|
38
40
|
export default SearchBarTransfer;
|
|
@@ -32,7 +32,7 @@ import RoundTrip from '../RoundTrip/RoundTrip';
|
|
|
32
32
|
import TransferLine from '../TransferLine/TransferLine';
|
|
33
33
|
var transferIdCounter = 0;
|
|
34
34
|
function SearchBarTransfer(_a) {
|
|
35
|
-
var _b = _a.mode, initialMode = _b === void 0 ? 'roundtrip' : _b, _c = _a.locations, locations = _c === void 0 ? { options: [], groups: [] } : _c, defaultRoundTripData = _a.defaultRoundTripData, defaultTransferLines = _a.defaultTransferLines, _d = _a.defaultSameVehicle, defaultSameVehicle = _d === void 0 ? false : _d, onSearch = _a.onSearch, onChange = _a.onChange, onRemove = _a.onRemove, _e = _a.className, className = _e === void 0 ? '' : _e, _f = _a.scrollOnOpen, scrollOnOpen = _f === void 0 ? false : _f;
|
|
35
|
+
var _b = _a.mode, initialMode = _b === void 0 ? 'roundtrip' : _b, _c = _a.locations, locations = _c === void 0 ? { options: [], groups: [] } : _c, defaultRoundTripData = _a.defaultRoundTripData, defaultTransferLines = _a.defaultTransferLines, _d = _a.defaultSameVehicle, defaultSameVehicle = _d === void 0 ? false : _d, onSearch = _a.onSearch, onChange = _a.onChange, onRemove = _a.onRemove, _e = _a.className, className = _e === void 0 ? '' : _e, _f = _a.scrollOnOpen, scrollOnOpen = _f === void 0 ? false : _f, onPaxOpenChange = _a.onPaxOpenChange;
|
|
36
36
|
// Generate unique ID for transfer lines
|
|
37
37
|
var generateTransferId = function () {
|
|
38
38
|
transferIdCounter += 1;
|
|
@@ -377,7 +377,7 @@ function SearchBarTransfer(_a) {
|
|
|
377
377
|
onSearch === null || onSearch === void 0 ? void 0 : onSearch(data);
|
|
378
378
|
}
|
|
379
379
|
};
|
|
380
|
-
return (_jsxs("div", { className: "search-bar-transfer ".concat(className), children: [_jsxs("div", { className: "search-bar-transfer__header", children: [_jsx(Heading, { level: 5, variant: "bold", color: "accent", children: "Select your transfer details" }), _jsx("div", { className: "search-bar-transfer__mode-selector", children: _jsx(SegmentedButton, { options: modeOptions, value: mode, onChange: handleModeChange, name: "transfer-mode" }) })] }), mode === 'roundtrip' ? (_jsxs(_Fragment, { children: [_jsx(RoundTrip, { id: "roundtrip-main", locations: locations, paxData: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.paxData, arrivalDate: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.arrivalDate, departureDate: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.departureDate, pickupDropoffPoint: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.pickupDropoffPoint, accommodation: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.accommodation, onChange: setRoundTripData, checkEmpty: error !== null, scrollOnOpen: scrollOnOpen }, "roundtrip-".concat(validationTrigger)), _jsx("div", { className: "search-bar-transfer__transfer-type", children: renderTransferTypeButtons(handleAddTransferFromRoundTrip) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "search-bar-transfer__transfer-type", children: [_jsx(Text, { size: "lg", variant: "bold", color: "subtle", as: "div", className: "search-bar-transfer__transfer-type-label", children: "Select a transfer type you want to add" }), renderTransferTypeButtons(handleAddTransfer)] }), transferLines.length === 0 && (_jsx(TransferLine, { id: "placeholder-transfer", type: "inter-hotel", locations: locations, onDataChange: function () { }, showDelete: false, disabled: true, scrollOnOpen: scrollOnOpen })), transferLines.length > 0 && (_jsx("div", { className: "search-bar-transfer__transfer-lines", children: (function () {
|
|
380
|
+
return (_jsxs("div", { className: "search-bar-transfer ".concat(className), children: [_jsxs("div", { className: "search-bar-transfer__header", children: [_jsx(Heading, { level: 5, variant: "bold", color: "accent", children: "Select your transfer details" }), _jsx("div", { className: "search-bar-transfer__mode-selector", children: _jsx(SegmentedButton, { options: modeOptions, value: mode, onChange: handleModeChange, name: "transfer-mode" }) })] }), mode === 'roundtrip' ? (_jsxs(_Fragment, { children: [_jsx(RoundTrip, { id: "roundtrip-main", locations: locations, paxData: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.paxData, arrivalDate: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.arrivalDate, departureDate: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.departureDate, pickupDropoffPoint: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.pickupDropoffPoint, accommodation: roundTripData === null || roundTripData === void 0 ? void 0 : roundTripData.accommodation, onChange: setRoundTripData, checkEmpty: error !== null, scrollOnOpen: scrollOnOpen }, "roundtrip-".concat(validationTrigger)), _jsx("div", { className: "search-bar-transfer__transfer-type", children: renderTransferTypeButtons(handleAddTransferFromRoundTrip) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "search-bar-transfer__transfer-type", children: [_jsx(Text, { size: "lg", variant: "bold", color: "subtle", as: "div", className: "search-bar-transfer__transfer-type-label", children: "Select a transfer type you want to add" }), renderTransferTypeButtons(handleAddTransfer)] }), transferLines.length === 0 && (_jsx(TransferLine, { id: "placeholder-transfer", type: "inter-hotel", locations: locations, onDataChange: function () { }, showDelete: false, disabled: true, scrollOnOpen: scrollOnOpen, onPaxOpenChange: function () { } })), transferLines.length > 0 && (_jsx("div", { className: "search-bar-transfer__transfer-lines", children: (function () {
|
|
381
381
|
// Group transfers by type
|
|
382
382
|
var groupedTransfers = {
|
|
383
383
|
arrival: [],
|
|
@@ -54,6 +54,8 @@ export interface TransferLineProps {
|
|
|
54
54
|
disabled?: boolean;
|
|
55
55
|
/** Whether to scroll to the input when the calendar opens */
|
|
56
56
|
scrollOnOpen?: boolean;
|
|
57
|
+
/** Callback when pax selector opens */
|
|
58
|
+
onPaxOpenChange?: () => void;
|
|
57
59
|
}
|
|
58
60
|
declare const TransferLine: React.FC<TransferLineProps>;
|
|
59
61
|
export default TransferLine;
|
|
@@ -27,7 +27,7 @@ import LocationDropdown from '../../molecules/LocationDropdown/LocationDropdown'
|
|
|
27
27
|
import DateTimePicker from '../DateTimePicker/DateTimePicker';
|
|
28
28
|
import PaxSelector from '../PaxSelector/PaxSelector';
|
|
29
29
|
var TransferLine = function (_a) {
|
|
30
|
-
var id = _a.id, type = _a.type, paxData = _a.paxData, transferDate = _a.transferDate, pickupPoint = _a.pickupPoint, dropoffPoint = _a.dropoffPoint, _b = _a.locations, locations = _b === void 0 ? { options: [], groups: [] } : _b, onPaxChange = _a.onPaxChange, onDateChange = _a.onDateChange, onPickupChange = _a.onPickupChange, onDropoffChange = _a.onDropoffChange, onDataChange = _a.onDataChange, onDelete = _a.onDelete, _c = _a.showDelete, showDelete = _c === void 0 ? true : _c, _d = _a.showTitle, showTitle = _d === void 0 ? false : _d, _e = _a.className, className = _e === void 0 ? '' : _e, _f = _a.checkEmpty, checkEmpty = _f === void 0 ? false : _f, _g = _a.disabled, disabled = _g === void 0 ? false : _g, _h = _a.scrollOnOpen, scrollOnOpen = _h === void 0 ? false : _h;
|
|
30
|
+
var id = _a.id, type = _a.type, paxData = _a.paxData, transferDate = _a.transferDate, pickupPoint = _a.pickupPoint, dropoffPoint = _a.dropoffPoint, _b = _a.locations, locations = _b === void 0 ? { options: [], groups: [] } : _b, onPaxChange = _a.onPaxChange, onDateChange = _a.onDateChange, onPickupChange = _a.onPickupChange, onDropoffChange = _a.onDropoffChange, onDataChange = _a.onDataChange, onDelete = _a.onDelete, _c = _a.showDelete, showDelete = _c === void 0 ? true : _c, _d = _a.showTitle, showTitle = _d === void 0 ? false : _d, _e = _a.className, className = _e === void 0 ? '' : _e, _f = _a.checkEmpty, checkEmpty = _f === void 0 ? false : _f, _g = _a.disabled, disabled = _g === void 0 ? false : _g, _h = _a.scrollOnOpen, scrollOnOpen = _h === void 0 ? false : _h, onPaxOpenChange = _a.onPaxOpenChange;
|
|
31
31
|
var _j = useState(paxData), internalPaxData = _j[0], setInternalPaxData = _j[1];
|
|
32
32
|
var _k = useState(transferDate), internalTransferDate = _k[0], setInternalTransferDate = _k[1];
|
|
33
33
|
var _l = useState(null), internalPickupPoint = _l[0], setInternalPickupPoint = _l[1];
|
|
@@ -70,7 +70,11 @@ var TransferLine = function (_a) {
|
|
|
70
70
|
};
|
|
71
71
|
// Helper to check if value is LocationOption
|
|
72
72
|
var isLocationOption = function (value) {
|
|
73
|
-
return typeof value === 'object' &&
|
|
73
|
+
return (typeof value === 'object' &&
|
|
74
|
+
value !== null &&
|
|
75
|
+
'id' in value &&
|
|
76
|
+
'label' in value &&
|
|
77
|
+
'type' in value);
|
|
74
78
|
};
|
|
75
79
|
// Initialize location data from IDs, LocationOption objects, or set defaults
|
|
76
80
|
React.useEffect(function () {
|
|
@@ -194,7 +198,10 @@ var TransferLine = function (_a) {
|
|
|
194
198
|
var name = locationData.locationName.toLowerCase();
|
|
195
199
|
var id = String(locationData.id).toLowerCase();
|
|
196
200
|
var locType = 'accommodation';
|
|
197
|
-
if (name.includes('harbour') ||
|
|
201
|
+
if (name.includes('harbour') ||
|
|
202
|
+
name.includes('port') ||
|
|
203
|
+
id.includes('harbour') ||
|
|
204
|
+
id.includes('port')) {
|
|
198
205
|
locType = 'port';
|
|
199
206
|
}
|
|
200
207
|
else if (name.includes('airport') || id.includes('airport')) {
|
|
@@ -241,7 +248,7 @@ var TransferLine = function (_a) {
|
|
|
241
248
|
};
|
|
242
249
|
var defaultPickupOption = findLocationOption(pickupPoint, 'pickup');
|
|
243
250
|
var defaultDropoffOption = findLocationOption(dropoffPoint, 'dropoff');
|
|
244
|
-
return (_jsxs("div", { className: "transfer-line transfer-line--".concat(type, " ").concat(disabled ? 'transfer-line--disabled' : '', " ").concat(className), "data-transfer-id": id, children: [showTitle && (_jsxs("div", { className: "transfer-line__header", children: [_jsx(Icon, { name: getTypeIcon(), size: "sm", className: "transfer-line__header-icon" }), _jsx(Text, { size: "sm", variant: "medium", className: "transfer-line__header-label", children: getTypeLabel() })] })), _jsxs("div", { className: "transfer-line__content-container", children: [_jsxs("div", { className: "transfer-line__content", children: [_jsx("div", { className: "transfer-line__field transfer-line__field--pax ".concat(isPaxEmpty ? 'transfer-line__field--error' : ''), children: _jsx(PaxSelector, { label: "Number of pax", value: internalPaxData, onChange: handlePaxChange, placeholder: "2 pax", className: isPaxEmpty ? 'pax-selector--error' : '', disabled: disabled, scrollOnOpen: scrollOnOpen, checkEmpty: checkEmpty }) }), _jsxs("div", { className: "transfer-line__field transfer-line__field--date", children: [_jsx(Text, { size: "sm", variant: "regular", className: "transfer-line__field-label", children: "Transfer date" }), _jsx(DateTimePicker, { placeholder: "DD/MM/YYYY", mode: "calendar", iconPosition: "left", numberOfMonths: 1, iconBGFull: false, showChevron: true, onValueChange: handleDateChange, selectionMode: "single", defaultValue: internalTransferDate, inputClassName: "transfer-line__date-picker", state: isDateEmpty ? 'error' : undefined, disabled: disabled, scrollOnOpen: scrollOnOpen })] }), _jsx("div", { className: "transfer-line__field transfer-line__field--pickup", children: _jsx(LocationDropdown, { label: "Pick-up point", options: filterLocations('pickup').options, groups: filterLocations('pickup').groups, selectedValue: (internalPickupPoint === null || internalPickupPoint === void 0 ? void 0 : internalPickupPoint.id) || null, onSelectionChange: handlePickupChange, placeholder: "Select a pick-up point", direction: "pickup", type: type === 'inter-hotel'
|
|
251
|
+
return (_jsxs("div", { className: "transfer-line transfer-line--".concat(type, " ").concat(disabled ? 'transfer-line--disabled' : '', " ").concat(className), "data-transfer-id": id, children: [showTitle && (_jsxs("div", { className: "transfer-line__header", children: [_jsx(Icon, { name: getTypeIcon(), size: "sm", className: "transfer-line__header-icon" }), _jsx(Text, { size: "sm", variant: "medium", className: "transfer-line__header-label", children: getTypeLabel() })] })), _jsxs("div", { className: "transfer-line__content-container", children: [_jsxs("div", { className: "transfer-line__content", children: [_jsx("div", { className: "transfer-line__field transfer-line__field--pax ".concat(isPaxEmpty ? 'transfer-line__field--error' : ''), children: _jsx(PaxSelector, { label: "Number of pax", value: internalPaxData, onChange: handlePaxChange, placeholder: "2 pax", className: isPaxEmpty ? 'pax-selector--error' : '', disabled: disabled, scrollOnOpen: scrollOnOpen, checkEmpty: checkEmpty, onPaxOpenChange: onPaxOpenChange }) }), _jsxs("div", { className: "transfer-line__field transfer-line__field--date", children: [_jsx(Text, { size: "sm", variant: "regular", className: "transfer-line__field-label", children: "Transfer date" }), _jsx(DateTimePicker, { placeholder: "DD/MM/YYYY", mode: "calendar", iconPosition: "left", numberOfMonths: 1, iconBGFull: false, showChevron: true, onValueChange: handleDateChange, selectionMode: "single", defaultValue: internalTransferDate, inputClassName: "transfer-line__date-picker", state: isDateEmpty ? 'error' : undefined, disabled: disabled, scrollOnOpen: scrollOnOpen })] }), _jsx("div", { className: "transfer-line__field transfer-line__field--pickup", children: _jsx(LocationDropdown, { label: "Pick-up point", options: filterLocations('pickup').options, groups: filterLocations('pickup').groups, selectedValue: (internalPickupPoint === null || internalPickupPoint === void 0 ? void 0 : internalPickupPoint.id) || null, onSelectionChange: handlePickupChange, placeholder: "Select a pick-up point", direction: "pickup", type: type === 'inter-hotel'
|
|
245
252
|
? 'accommodation'
|
|
246
253
|
: type === 'arrival'
|
|
247
254
|
? 'airport-port'
|
package/dist/lib/utils.js
CHANGED
|
@@ -21,17 +21,22 @@ export function cn() {
|
|
|
21
21
|
export function scrollIntoViewOnOpen(elementRef, isOpen, scrollOnOpen, offset) {
|
|
22
22
|
if (offset === void 0) { offset = 20; }
|
|
23
23
|
if (isOpen && scrollOnOpen && elementRef.current) {
|
|
24
|
+
var bodyBottom_1 = document.body.clientHeight;
|
|
24
25
|
// Use setTimeout to ensure the dropdown is rendered before scrolling
|
|
25
26
|
setTimeout(function () {
|
|
26
27
|
if (elementRef.current) {
|
|
27
28
|
var elementTop = elementRef.current.getBoundingClientRect().top + window.pageYOffset;
|
|
29
|
+
var elementBottom = elementRef.current.getBoundingClientRect().bottom;
|
|
30
|
+
var realBottom = elementBottom + window.scrollY;
|
|
28
31
|
// Scroll to show the element with some padding from the top
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
if (realBottom > bodyBottom_1) {
|
|
33
|
+
window.scrollTo({
|
|
34
|
+
top: elementTop - offset,
|
|
35
|
+
behavior: 'smooth',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
33
38
|
}
|
|
34
|
-
},
|
|
39
|
+
}, 350);
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
/**
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
.pax-selector__label {
|
|
36
|
-
font-family:
|
|
36
|
+
font-family:
|
|
37
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
38
|
+
sans-serif;
|
|
37
39
|
font-size: 14px;
|
|
38
40
|
line-height: 1.5;
|
|
39
41
|
color: var(--input-color-label-default, #262626);
|
|
@@ -82,7 +84,9 @@
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
.pax-selector__input-text {
|
|
85
|
-
font-family:
|
|
87
|
+
font-family:
|
|
88
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
89
|
+
sans-serif;
|
|
86
90
|
font-weight: 500;
|
|
87
91
|
font-size: 14px;
|
|
88
92
|
line-height: 20px;
|
|
@@ -99,7 +103,7 @@
|
|
|
99
103
|
}
|
|
100
104
|
|
|
101
105
|
.pax-selector__chevron--open {
|
|
102
|
-
transform: rotate(180deg)!important;
|
|
106
|
+
transform: rotate(180deg) !important;
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
/* Disabled state */
|
|
@@ -139,7 +143,9 @@
|
|
|
139
143
|
border: 1px solid var(--color-border-subtle, #e5e5e5);
|
|
140
144
|
border-radius: 12px;
|
|
141
145
|
padding: 16px;
|
|
142
|
-
box-shadow:
|
|
146
|
+
box-shadow:
|
|
147
|
+
0px 4px 8px rgba(48, 54, 66, 0.1),
|
|
148
|
+
0px 1px 8px rgba(48, 54, 66, 0.11);
|
|
143
149
|
z-index: 100;
|
|
144
150
|
animation: pax-selector-dropdown-enter 0.2s ease-out;
|
|
145
151
|
}
|
|
@@ -168,7 +174,9 @@
|
|
|
168
174
|
background: none;
|
|
169
175
|
border: none;
|
|
170
176
|
cursor: pointer;
|
|
171
|
-
font-family:
|
|
177
|
+
font-family:
|
|
178
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
179
|
+
sans-serif;
|
|
172
180
|
font-weight: 500;
|
|
173
181
|
font-size: 14px;
|
|
174
182
|
line-height: 20px;
|
|
@@ -222,7 +230,9 @@
|
|
|
222
230
|
background: var(--stepper-color-cta-background-default, #ffffff);
|
|
223
231
|
color: var(--stepper-color-cta-foreground-default, #000000);
|
|
224
232
|
cursor: pointer;
|
|
225
|
-
box-shadow:
|
|
233
|
+
box-shadow:
|
|
234
|
+
0px 1px 8px rgba(48, 54, 66, 0.11),
|
|
235
|
+
0px 4px 8px rgba(48, 54, 66, 0.1);
|
|
226
236
|
transition: all 0.2s ease;
|
|
227
237
|
}
|
|
228
238
|
|
|
@@ -247,11 +257,16 @@
|
|
|
247
257
|
align-items: center;
|
|
248
258
|
justify-content: center;
|
|
249
259
|
min-width: 48px;
|
|
260
|
+
flex: 0 0 48px;
|
|
250
261
|
padding: 4px 24px;
|
|
251
262
|
background: var(--stepper-color-counter, #ffffff);
|
|
252
263
|
border-radius: 8px;
|
|
253
|
-
box-shadow:
|
|
254
|
-
|
|
264
|
+
box-shadow:
|
|
265
|
+
0px 0px 4px rgba(48, 54, 66, 0.11),
|
|
266
|
+
0px 2px 2px rgba(48, 54, 66, 0.1);
|
|
267
|
+
font-family:
|
|
268
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
269
|
+
sans-serif;
|
|
255
270
|
font-weight: 700;
|
|
256
271
|
font-size: 18px;
|
|
257
272
|
line-height: 24px;
|
|
@@ -266,7 +281,9 @@
|
|
|
266
281
|
}
|
|
267
282
|
|
|
268
283
|
.pax-selector__client-type-label {
|
|
269
|
-
font-family:
|
|
284
|
+
font-family:
|
|
285
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
286
|
+
sans-serif;
|
|
270
287
|
font-size: 14px;
|
|
271
288
|
line-height: 20px;
|
|
272
289
|
color: var(--input-color-label-default, #262626);
|
|
@@ -307,7 +324,9 @@
|
|
|
307
324
|
}
|
|
308
325
|
|
|
309
326
|
.pax-selector__client-type-text {
|
|
310
|
-
font-family:
|
|
327
|
+
font-family:
|
|
328
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
329
|
+
sans-serif;
|
|
311
330
|
font-weight: 400;
|
|
312
331
|
font-size: 14px;
|
|
313
332
|
line-height: 20px;
|
|
@@ -358,7 +377,9 @@
|
|
|
358
377
|
border: none;
|
|
359
378
|
cursor: pointer;
|
|
360
379
|
text-align: left;
|
|
361
|
-
font-family:
|
|
380
|
+
font-family:
|
|
381
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
382
|
+
sans-serif;
|
|
362
383
|
font-weight: 400;
|
|
363
384
|
font-size: 14px;
|
|
364
385
|
line-height: 20px;
|
|
@@ -390,7 +411,9 @@
|
|
|
390
411
|
background: none;
|
|
391
412
|
border: none;
|
|
392
413
|
cursor: pointer;
|
|
393
|
-
font-family:
|
|
414
|
+
font-family:
|
|
415
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
416
|
+
sans-serif;
|
|
394
417
|
font-weight: 700;
|
|
395
418
|
font-size: 14px;
|
|
396
419
|
line-height: 20px;
|
|
@@ -412,7 +435,9 @@
|
|
|
412
435
|
border: none;
|
|
413
436
|
border-radius: 9999px;
|
|
414
437
|
cursor: pointer;
|
|
415
|
-
font-family:
|
|
438
|
+
font-family:
|
|
439
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
440
|
+
sans-serif;
|
|
416
441
|
font-weight: 700;
|
|
417
442
|
font-size: 14px;
|
|
418
443
|
line-height: 20px;
|
|
@@ -509,7 +534,9 @@
|
|
|
509
534
|
border: 1px solid var(--chip-color-red-outline-foreground, #991b1b);
|
|
510
535
|
border-radius: 9999px;
|
|
511
536
|
cursor: pointer;
|
|
512
|
-
font-family:
|
|
537
|
+
font-family:
|
|
538
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
539
|
+
sans-serif;
|
|
513
540
|
font-weight: var(--font-weight-font-medium, 500);
|
|
514
541
|
font-size: 12px;
|
|
515
542
|
line-height: 16px;
|
package/package.json
CHANGED
|
@@ -64,6 +64,7 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
|
|
|
64
64
|
const [isOpen, setIsOpen] = useState(false);
|
|
65
65
|
const [searchQuery, setSearchQuery] = useState('');
|
|
66
66
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
67
|
+
const dropdownPanelRef = useRef<HTMLDivElement>(null);
|
|
67
68
|
const inputRef = useRef<HTMLDivElement>(null);
|
|
68
69
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
69
70
|
|
|
@@ -83,7 +84,11 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
|
|
|
83
84
|
|
|
84
85
|
// Scroll to input when dropdown opens (if scrollOnOpen is true)
|
|
85
86
|
useEffect(() => {
|
|
86
|
-
|
|
87
|
+
setTimeout(() => {
|
|
88
|
+
if (dropdownPanelRef.current) {
|
|
89
|
+
scrollIntoViewOnOpen(dropdownPanelRef, isOpen, scrollOnOpen);
|
|
90
|
+
}
|
|
91
|
+
}, 10);
|
|
87
92
|
}, [isOpen, scrollOnOpen]);
|
|
88
93
|
|
|
89
94
|
// Reset search when dropdown closes
|
|
@@ -129,11 +134,9 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
|
|
|
129
134
|
// Filter locations based on search query
|
|
130
135
|
const filterOptions = (opts: LocationOption[]): LocationOption[] => {
|
|
131
136
|
if (!searchQuery.trim()) return opts;
|
|
132
|
-
|
|
137
|
+
|
|
133
138
|
const query = searchQuery.toLowerCase();
|
|
134
|
-
return opts.filter((option) =>
|
|
135
|
-
option.label.toLowerCase().includes(query)
|
|
136
|
-
);
|
|
139
|
+
return opts.filter((option) => option.label.toLowerCase().includes(query));
|
|
137
140
|
};
|
|
138
141
|
|
|
139
142
|
const getSelectedOption = (): LocationOption | null => {
|
|
@@ -201,11 +204,14 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
|
|
|
201
204
|
const displayText = selectedOption ? selectedOption.label : placeholder;
|
|
202
205
|
|
|
203
206
|
// Prepare all options (flat or grouped) and filter them
|
|
204
|
-
const allOptionsRaw =
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
const allOptionsRaw =
|
|
208
|
+
groups.length > 0 ? groups : [{ id: 'default', label: '', options }];
|
|
209
|
+
const allOptions = allOptionsRaw
|
|
210
|
+
.map((group) => ({
|
|
211
|
+
...group,
|
|
212
|
+
options: filterOptions(group.options),
|
|
213
|
+
}))
|
|
214
|
+
.filter((group) => group.options.length > 0);
|
|
209
215
|
|
|
210
216
|
// Skeleton loader component
|
|
211
217
|
const SkeletonOption = () => (
|
|
@@ -284,7 +290,7 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
|
|
|
284
290
|
(loading ? (
|
|
285
291
|
renderSkeletonLoading()
|
|
286
292
|
) : (
|
|
287
|
-
<div className="location-dropdown__panel">
|
|
293
|
+
<div className="location-dropdown__panel" ref={dropdownPanelRef}>
|
|
288
294
|
<div
|
|
289
295
|
className="location-dropdown__content"
|
|
290
296
|
style={{ maxHeight: `${maxHeight}px` }}>
|
|
@@ -297,41 +303,43 @@ const LocationDropdown: React.FC<LocationDropdownProps> = ({
|
|
|
297
303
|
</div>
|
|
298
304
|
) : (
|
|
299
305
|
allOptions.map((group, groupIndex) => (
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
)}
|
|
311
|
-
|
|
312
|
-
<div className="location-dropdown__group-options">
|
|
313
|
-
{group.options.map((option) => {
|
|
314
|
-
const isSelected = effectiveSelectedValue === option.id;
|
|
315
|
-
const isDisabled = option.disabled || disabled;
|
|
316
|
-
|
|
317
|
-
return (
|
|
318
|
-
<div
|
|
319
|
-
key={option.id}
|
|
320
|
-
className={`location-dropdown__option ${isSelected ? 'location-dropdown__option--selected' : ''} ${isDisabled ? 'location-dropdown__option--disabled' : ''}`}
|
|
321
|
-
onClick={() => !isDisabled && handleOptionSelect(option)}>
|
|
322
|
-
<Icon
|
|
323
|
-
name={getOptionIcon(option, isSelected)}
|
|
324
|
-
size="sm"
|
|
325
|
-
className="location-dropdown__option-icon"
|
|
326
|
-
/>
|
|
327
|
-
<span className="location-dropdown__option-text">
|
|
328
|
-
{option.label}
|
|
329
|
-
</span>
|
|
306
|
+
<div key={group.id} className="location-dropdown__group">
|
|
307
|
+
{showGroupTitles && group.label && groups.length > 0 && (
|
|
308
|
+
<>
|
|
309
|
+
{groupIndex > 0 && (
|
|
310
|
+
<div className="location-dropdown__divider" />
|
|
311
|
+
)}
|
|
312
|
+
<div className="location-dropdown__group-header">
|
|
313
|
+
<Text size="xs" variant="bold">
|
|
314
|
+
{group.label}
|
|
315
|
+
</Text>
|
|
330
316
|
</div>
|
|
331
|
-
|
|
332
|
-
|
|
317
|
+
</>
|
|
318
|
+
)}
|
|
319
|
+
|
|
320
|
+
<div className="location-dropdown__group-options">
|
|
321
|
+
{group.options.map((option) => {
|
|
322
|
+
const isSelected = effectiveSelectedValue === option.id;
|
|
323
|
+
const isDisabled = option.disabled || disabled;
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<div
|
|
327
|
+
key={option.id}
|
|
328
|
+
className={`location-dropdown__option ${isSelected ? 'location-dropdown__option--selected' : ''} ${isDisabled ? 'location-dropdown__option--disabled' : ''}`}
|
|
329
|
+
onClick={() => !isDisabled && handleOptionSelect(option)}>
|
|
330
|
+
<Icon
|
|
331
|
+
name={getOptionIcon(option, isSelected)}
|
|
332
|
+
size="sm"
|
|
333
|
+
className="location-dropdown__option-icon"
|
|
334
|
+
/>
|
|
335
|
+
<span className="location-dropdown__option-text">
|
|
336
|
+
{option.label}
|
|
337
|
+
</span>
|
|
338
|
+
</div>
|
|
339
|
+
);
|
|
340
|
+
})}
|
|
341
|
+
</div>
|
|
333
342
|
</div>
|
|
334
|
-
</div>
|
|
335
343
|
))
|
|
336
344
|
)}
|
|
337
345
|
</div>
|
|
@@ -74,6 +74,7 @@ export interface PaxSelectorProps {
|
|
|
74
74
|
ageRange?: number[];
|
|
75
75
|
/** Whether to check if age inputs are empty and show error state */
|
|
76
76
|
checkEmpty?: boolean;
|
|
77
|
+
onPaxOpenChange?: () => void;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
const DEFAULT_PAX_DATA: PaxData = {
|
|
@@ -535,6 +536,7 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
535
536
|
scrollOnOpen = false,
|
|
536
537
|
disabled = false,
|
|
537
538
|
checkEmpty = false,
|
|
539
|
+
onPaxOpenChange,
|
|
538
540
|
}) => {
|
|
539
541
|
const [isOpen, setIsOpen] = useState(false);
|
|
540
542
|
const [internalData, setInternalData] = useState<PaxData>(
|
|
@@ -676,9 +678,13 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
676
678
|
// Check if there are any minors that need age specification
|
|
677
679
|
const hasMinorsWithoutAges = (): boolean => {
|
|
678
680
|
if (multipleRooms) {
|
|
679
|
-
return rooms.some(
|
|
681
|
+
return rooms.some(
|
|
682
|
+
(room) => room.teens > 0 || room.children > 0 || room.infants > 0
|
|
683
|
+
);
|
|
680
684
|
}
|
|
681
|
-
return
|
|
685
|
+
return (
|
|
686
|
+
internalData.teens > 0 || internalData.children > 0 || internalData.infants > 0
|
|
687
|
+
);
|
|
682
688
|
};
|
|
683
689
|
|
|
684
690
|
// Handle clicks outside the dropdown
|
|
@@ -696,6 +702,8 @@ const PaxSelector: React.FC<PaxSelectorProps> = ({
|
|
|
696
702
|
document.addEventListener('mousedown', handleClickOutside);
|
|
697
703
|
}
|
|
698
704
|
|
|
705
|
+
onPaxOpenChange?.();
|
|
706
|
+
|
|
699
707
|
return () => {
|
|
700
708
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
701
709
|
};
|
|
@@ -52,6 +52,8 @@ export interface SearchBarTransferProps {
|
|
|
52
52
|
className?: string;
|
|
53
53
|
/** Whether to scroll to the input when the calendar opens */
|
|
54
54
|
scrollOnOpen?: boolean;
|
|
55
|
+
/** Callback when pax selector opens */
|
|
56
|
+
onPaxOpenChange?: () => void;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
let transferIdCounter = 0;
|
|
@@ -67,6 +69,7 @@ function SearchBarTransfer({
|
|
|
67
69
|
onRemove,
|
|
68
70
|
className = '',
|
|
69
71
|
scrollOnOpen = false,
|
|
72
|
+
onPaxOpenChange,
|
|
70
73
|
}: SearchBarTransferProps) {
|
|
71
74
|
// Generate unique ID for transfer lines
|
|
72
75
|
const generateTransferId = () => {
|
|
@@ -557,6 +560,7 @@ function SearchBarTransfer({
|
|
|
557
560
|
showDelete={false}
|
|
558
561
|
disabled={true}
|
|
559
562
|
scrollOnOpen={scrollOnOpen}
|
|
563
|
+
onPaxOpenChange={() => {}}
|
|
560
564
|
/>
|
|
561
565
|
)}
|
|
562
566
|
|
|
@@ -3,9 +3,9 @@ import '../../../styles/components/organism/transfer-line.css';
|
|
|
3
3
|
import Icon from '../../atoms/Icon/Icon';
|
|
4
4
|
import { Text } from '../../atoms/Typography/Typography';
|
|
5
5
|
import LocationDropdown, {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
LocationData,
|
|
7
|
+
LocationGroup,
|
|
8
|
+
LocationOption,
|
|
9
9
|
} from '../../molecules/LocationDropdown/LocationDropdown';
|
|
10
10
|
import DateTimePicker from '../DateTimePicker/DateTimePicker';
|
|
11
11
|
import PaxSelector, { PaxData } from '../PaxSelector/PaxSelector';
|
|
@@ -66,6 +66,8 @@ export interface TransferLineProps {
|
|
|
66
66
|
disabled?: boolean;
|
|
67
67
|
/** Whether to scroll to the input when the calendar opens */
|
|
68
68
|
scrollOnOpen?: boolean;
|
|
69
|
+
/** Callback when pax selector opens */
|
|
70
|
+
onPaxOpenChange?: () => void;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
const TransferLine: React.FC<TransferLineProps> = ({
|
|
@@ -88,6 +90,7 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
88
90
|
checkEmpty = false,
|
|
89
91
|
disabled = false,
|
|
90
92
|
scrollOnOpen = false,
|
|
93
|
+
onPaxOpenChange,
|
|
91
94
|
}) => {
|
|
92
95
|
const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(paxData);
|
|
93
96
|
const [internalTransferDate, setInternalTransferDate] = useState<string | undefined>(
|
|
@@ -154,8 +157,16 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
154
157
|
};
|
|
155
158
|
|
|
156
159
|
// Helper to check if value is LocationOption
|
|
157
|
-
const isLocationOption = (
|
|
158
|
-
|
|
160
|
+
const isLocationOption = (
|
|
161
|
+
value: string | number | LocationOption | undefined
|
|
162
|
+
): value is LocationOption => {
|
|
163
|
+
return (
|
|
164
|
+
typeof value === 'object' &&
|
|
165
|
+
value !== null &&
|
|
166
|
+
'id' in value &&
|
|
167
|
+
'label' in value &&
|
|
168
|
+
'type' in value
|
|
169
|
+
);
|
|
159
170
|
};
|
|
160
171
|
|
|
161
172
|
// Initialize location data from IDs, LocationOption objects, or set defaults
|
|
@@ -276,25 +287,33 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
276
287
|
};
|
|
277
288
|
|
|
278
289
|
// Helper to convert LocationData to LocationOption
|
|
279
|
-
const toLocationOption = (
|
|
290
|
+
const toLocationOption = (
|
|
291
|
+
locationData: LocationData | null,
|
|
292
|
+
position: 'pickup' | 'dropoff'
|
|
293
|
+
): LocationOption | null => {
|
|
280
294
|
if (!locationData) return null;
|
|
281
|
-
|
|
295
|
+
|
|
282
296
|
// Try to find in the options to get the type
|
|
283
297
|
const { options, groups } = filterLocations(position);
|
|
284
298
|
const allLocations = getAllLocations(options, groups);
|
|
285
299
|
const found = allLocations.find((loc) => loc.id === locationData.id);
|
|
286
300
|
if (found) return found;
|
|
287
|
-
|
|
301
|
+
|
|
288
302
|
// If not found, infer the type
|
|
289
303
|
const name = locationData.locationName.toLowerCase();
|
|
290
304
|
const id = String(locationData.id).toLowerCase();
|
|
291
305
|
let locType: 'airport' | 'port' | 'accommodation' = 'accommodation';
|
|
292
|
-
if (
|
|
306
|
+
if (
|
|
307
|
+
name.includes('harbour') ||
|
|
308
|
+
name.includes('port') ||
|
|
309
|
+
id.includes('harbour') ||
|
|
310
|
+
id.includes('port')
|
|
311
|
+
) {
|
|
293
312
|
locType = 'port';
|
|
294
313
|
} else if (name.includes('airport') || id.includes('airport')) {
|
|
295
314
|
locType = 'airport';
|
|
296
315
|
}
|
|
297
|
-
|
|
316
|
+
|
|
298
317
|
return {
|
|
299
318
|
id: locationData.id,
|
|
300
319
|
label: locationData.locationName,
|
|
@@ -331,14 +350,17 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
331
350
|
const isDropoffEmpty = checkEmpty && !internalDropoffPoint;
|
|
332
351
|
|
|
333
352
|
// Helper function to find LocationOption from ID or LocationOption for defaultValue
|
|
334
|
-
const findLocationOption = (
|
|
353
|
+
const findLocationOption = (
|
|
354
|
+
value: string | number | LocationOption | undefined,
|
|
355
|
+
position: 'pickup' | 'dropoff'
|
|
356
|
+
): LocationOption | undefined => {
|
|
335
357
|
if (!value) return undefined;
|
|
336
|
-
|
|
358
|
+
|
|
337
359
|
// If value is already a LocationOption object, use it directly
|
|
338
360
|
if (isLocationOption(value)) {
|
|
339
361
|
return value;
|
|
340
362
|
}
|
|
341
|
-
|
|
363
|
+
|
|
342
364
|
// Otherwise, look up by ID in the locations
|
|
343
365
|
const { options, groups } = filterLocations(position);
|
|
344
366
|
const allLocations = getAllLocations(options, groups);
|
|
@@ -377,6 +399,7 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
377
399
|
disabled={disabled}
|
|
378
400
|
scrollOnOpen={scrollOnOpen}
|
|
379
401
|
checkEmpty={checkEmpty}
|
|
402
|
+
onPaxOpenChange={onPaxOpenChange}
|
|
380
403
|
/>
|
|
381
404
|
</div>
|
|
382
405
|
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
.pax-selector__label {
|
|
22
|
-
font-family:
|
|
22
|
+
font-family:
|
|
23
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
24
|
+
sans-serif;
|
|
23
25
|
font-size: 14px;
|
|
24
26
|
line-height: 1.5;
|
|
25
27
|
color: var(--input-color-label-default, #262626);
|
|
@@ -68,7 +70,9 @@
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
.pax-selector__input-text {
|
|
71
|
-
font-family:
|
|
73
|
+
font-family:
|
|
74
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
75
|
+
sans-serif;
|
|
72
76
|
font-weight: 500;
|
|
73
77
|
font-size: 14px;
|
|
74
78
|
line-height: 20px;
|
|
@@ -85,7 +89,7 @@
|
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
.pax-selector__chevron--open {
|
|
88
|
-
transform: rotate(180deg)!important;
|
|
92
|
+
transform: rotate(180deg) !important;
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/* Disabled state */
|
|
@@ -123,7 +127,9 @@
|
|
|
123
127
|
border: 1px solid var(--color-border-subtle, #e5e5e5);
|
|
124
128
|
border-radius: 12px;
|
|
125
129
|
padding: 16px;
|
|
126
|
-
box-shadow:
|
|
130
|
+
box-shadow:
|
|
131
|
+
0px 4px 8px rgba(48, 54, 66, 0.1),
|
|
132
|
+
0px 1px 8px rgba(48, 54, 66, 0.11);
|
|
127
133
|
z-index: 100;
|
|
128
134
|
animation: pax-selector-dropdown-enter 0.2s ease-out;
|
|
129
135
|
}
|
|
@@ -151,7 +157,9 @@
|
|
|
151
157
|
background: none;
|
|
152
158
|
border: none;
|
|
153
159
|
cursor: pointer;
|
|
154
|
-
font-family:
|
|
160
|
+
font-family:
|
|
161
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
162
|
+
sans-serif;
|
|
155
163
|
font-weight: 500;
|
|
156
164
|
font-size: 14px;
|
|
157
165
|
line-height: 20px;
|
|
@@ -204,7 +212,9 @@
|
|
|
204
212
|
background: var(--stepper-color-cta-background-default, #ffffff);
|
|
205
213
|
color: var(--stepper-color-cta-foreground-default, #000000);
|
|
206
214
|
cursor: pointer;
|
|
207
|
-
box-shadow:
|
|
215
|
+
box-shadow:
|
|
216
|
+
0px 1px 8px rgba(48, 54, 66, 0.11),
|
|
217
|
+
0px 4px 8px rgba(48, 54, 66, 0.1);
|
|
208
218
|
transition: all 0.2s ease;
|
|
209
219
|
}
|
|
210
220
|
|
|
@@ -229,11 +239,16 @@
|
|
|
229
239
|
align-items: center;
|
|
230
240
|
justify-content: center;
|
|
231
241
|
min-width: 48px;
|
|
242
|
+
flex: 0 0 48px;
|
|
232
243
|
padding: 4px 24px;
|
|
233
244
|
background: var(--stepper-color-counter, #ffffff);
|
|
234
245
|
border-radius: 8px;
|
|
235
|
-
box-shadow:
|
|
236
|
-
|
|
246
|
+
box-shadow:
|
|
247
|
+
0px 0px 4px rgba(48, 54, 66, 0.11),
|
|
248
|
+
0px 2px 2px rgba(48, 54, 66, 0.1);
|
|
249
|
+
font-family:
|
|
250
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
251
|
+
sans-serif;
|
|
237
252
|
font-weight: 700;
|
|
238
253
|
font-size: 18px;
|
|
239
254
|
line-height: 24px;
|
|
@@ -247,7 +262,9 @@
|
|
|
247
262
|
}
|
|
248
263
|
|
|
249
264
|
.pax-selector__client-type-label {
|
|
250
|
-
font-family:
|
|
265
|
+
font-family:
|
|
266
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
267
|
+
sans-serif;
|
|
251
268
|
font-size: 14px;
|
|
252
269
|
line-height: 20px;
|
|
253
270
|
color: var(--input-color-label-default, #262626);
|
|
@@ -288,7 +305,9 @@
|
|
|
288
305
|
}
|
|
289
306
|
|
|
290
307
|
.pax-selector__client-type-text {
|
|
291
|
-
font-family:
|
|
308
|
+
font-family:
|
|
309
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
310
|
+
sans-serif;
|
|
292
311
|
font-weight: 400;
|
|
293
312
|
font-size: 14px;
|
|
294
313
|
line-height: 20px;
|
|
@@ -339,7 +358,9 @@
|
|
|
339
358
|
border: none;
|
|
340
359
|
cursor: pointer;
|
|
341
360
|
text-align: left;
|
|
342
|
-
font-family:
|
|
361
|
+
font-family:
|
|
362
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
363
|
+
sans-serif;
|
|
343
364
|
font-weight: 400;
|
|
344
365
|
font-size: 14px;
|
|
345
366
|
line-height: 20px;
|
|
@@ -370,7 +391,9 @@
|
|
|
370
391
|
background: none;
|
|
371
392
|
border: none;
|
|
372
393
|
cursor: pointer;
|
|
373
|
-
font-family:
|
|
394
|
+
font-family:
|
|
395
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
396
|
+
sans-serif;
|
|
374
397
|
font-weight: 700;
|
|
375
398
|
font-size: 14px;
|
|
376
399
|
line-height: 20px;
|
|
@@ -392,7 +415,9 @@
|
|
|
392
415
|
border: none;
|
|
393
416
|
border-radius: 9999px;
|
|
394
417
|
cursor: pointer;
|
|
395
|
-
font-family:
|
|
418
|
+
font-family:
|
|
419
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
420
|
+
sans-serif;
|
|
396
421
|
font-weight: 700;
|
|
397
422
|
font-size: 14px;
|
|
398
423
|
line-height: 20px;
|
|
@@ -432,10 +457,9 @@
|
|
|
432
457
|
}
|
|
433
458
|
|
|
434
459
|
.pax-selector__age-groups {
|
|
435
|
-
|
|
460
|
+
@apply flex flex-wrap gap-4;
|
|
436
461
|
}
|
|
437
462
|
|
|
438
|
-
|
|
439
463
|
/* Multiple Rooms Styles */
|
|
440
464
|
.pax-selector__rooms {
|
|
441
465
|
display: flex;
|
|
@@ -485,7 +509,9 @@
|
|
|
485
509
|
border: 1px solid var(--chip-color-red-outline-foreground, #991b1b);
|
|
486
510
|
border-radius: 9999px;
|
|
487
511
|
cursor: pointer;
|
|
488
|
-
font-family:
|
|
512
|
+
font-family:
|
|
513
|
+
var(--font-font-family-body, 'Satoshi'), 'Satoshi', 'Inter', 'Segoe UI', 'system-ui',
|
|
514
|
+
sans-serif;
|
|
489
515
|
font-weight: var(--font-weight-font-medium, 500);
|
|
490
516
|
font-size: 12px;
|
|
491
517
|
line-height: 16px;
|
|
@@ -538,4 +564,3 @@
|
|
|
538
564
|
.pax-selector__dropdown::-webkit-scrollbar-thumb:hover {
|
|
539
565
|
background: var(--color-button-brand-background-secondary-hover, #115b5e);
|
|
540
566
|
}
|
|
541
|
-
|