mautourco-components 0.2.46 → 0.2.47
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/AgeSelector/AgeSelector.d.ts +20 -0
- package/dist/components/molecules/AgeSelector/AgeSelector.js +84 -0
- package/dist/components/molecules/LocationDropdown/LocationDropdown.js +1 -1
- package/dist/components/organisms/PaxSelector/PaxSelector.d.ts +5 -0
- package/dist/components/organisms/PaxSelector/PaxSelector.js +100 -114
- package/dist/components/organisms/RoundTrip/RoundTrip.d.ts +2 -0
- package/dist/components/organisms/RoundTrip/RoundTrip.js +7 -7
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.d.ts +4 -0
- package/dist/components/organisms/SearchBarTransfer/SearchBarTransfer.js +19 -57
- package/dist/components/organisms/TransferLine/TransferLine.d.ts +9 -5
- package/dist/components/organisms/TransferLine/TransferLine.js +52 -35
- package/dist/index.d.ts +19 -16
- package/dist/index.js +3 -1
- package/dist/styles/components/molecule/age-selector.css +216 -0
- package/dist/styles/components/molecule/calendarInput.css +25 -6
- package/dist/styles/components/molecule/location-dropdown.css +16 -4
- package/dist/styles/components/organism/pax-selector.css +27 -189
- package/dist/styles/components/organism/transfer-line.css +40 -0
- package/dist/styles/mautourco.css +1 -0
- package/package.json +1 -1
- package/src/components/molecules/AgeSelector/AgeSelector.tsx +172 -0
- package/src/components/molecules/LocationDropdown/LocationDropdown.tsx +1 -1
- package/src/components/organisms/PaxSelector/PaxSelector.tsx +132 -208
- package/src/components/organisms/RoundTrip/RoundTrip.tsx +7 -0
- package/src/components/organisms/SearchBarTransfer/SearchBarTransfer.tsx +34 -54
- package/src/components/organisms/TransferLine/TransferLine.tsx +107 -85
- package/src/styles/components/molecule/age-selector.css +136 -0
- package/src/styles/components/molecule/calendarInput.css +12 -4
- package/src/styles/components/molecule/location-dropdown.css +9 -2
- package/src/styles/components/organism/pax-selector.css +25 -186
- package/src/styles/components/organism/transfer-line.css +31 -0
|
@@ -40,8 +40,12 @@ export interface SearchBarTransferProps {
|
|
|
40
40
|
onSearch?: (data: SearchBarTransferData) => void;
|
|
41
41
|
/** Callback when data changes */
|
|
42
42
|
onChange?: (data: SearchBarTransferData) => void;
|
|
43
|
+
/** Callback when a transfer line is removed */
|
|
44
|
+
onRemove?: (index: number, transferLine: TransferLineData) => void;
|
|
43
45
|
/** Additional CSS classes */
|
|
44
46
|
className?: string;
|
|
47
|
+
/** Whether to scroll to the input when the calendar opens */
|
|
48
|
+
scrollOnOpen?: boolean;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
let transferIdCounter = 0;
|
|
@@ -54,7 +58,9 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
54
58
|
defaultSameVehicle = false,
|
|
55
59
|
onSearch,
|
|
56
60
|
onChange,
|
|
61
|
+
onRemove,
|
|
57
62
|
className = "",
|
|
63
|
+
scrollOnOpen = false,
|
|
58
64
|
}) => {
|
|
59
65
|
// Generate unique ID for transfer lines
|
|
60
66
|
const generateTransferId = () => {
|
|
@@ -101,27 +107,9 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
101
107
|
const transferMode = newMode as TransferMode;
|
|
102
108
|
if (transferMode === mode) return;
|
|
103
109
|
|
|
104
|
-
if (transferMode === "custom" && mode === "roundtrip"
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
id: generateTransferId(),
|
|
108
|
-
type: "arrival",
|
|
109
|
-
paxData: roundTripData.paxData,
|
|
110
|
-
transferDate: roundTripData.arrivalDate,
|
|
111
|
-
pickupPoint: roundTripData.pickupDropoffPoint,
|
|
112
|
-
dropoffPoint: roundTripData.accommodation,
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const departureTransfer: TransferLineData = {
|
|
116
|
-
id: generateTransferId(),
|
|
117
|
-
type: "departure",
|
|
118
|
-
paxData: roundTripData.paxData,
|
|
119
|
-
transferDate: roundTripData.departureDate,
|
|
120
|
-
pickupPoint: roundTripData.accommodation,
|
|
121
|
-
dropoffPoint: roundTripData.pickupDropoffPoint,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
setTransferLines([arrivalTransfer, departureTransfer]);
|
|
110
|
+
if (transferMode === "custom" && mode === "roundtrip") {
|
|
111
|
+
// When switching to custom mode, reset transfer lines (will show placeholder)
|
|
112
|
+
setTransferLines([]);
|
|
125
113
|
setRoundTripData(undefined);
|
|
126
114
|
} else if (transferMode === "roundtrip" && mode === "custom") {
|
|
127
115
|
// Reset everything when switching to roundtrip
|
|
@@ -172,46 +160,16 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
172
160
|
</div>
|
|
173
161
|
);
|
|
174
162
|
|
|
175
|
-
// Handle adding transfer from round-trip mode (
|
|
163
|
+
// Handle adding transfer from round-trip mode (switches to custom and adds new transfer)
|
|
176
164
|
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
165
|
// Add the new transfer of the clicked type
|
|
208
166
|
const newTransfer: TransferLineData = {
|
|
209
167
|
id: generateTransferId(),
|
|
210
168
|
type,
|
|
211
169
|
};
|
|
212
170
|
|
|
213
|
-
// Set
|
|
214
|
-
setTransferLines([
|
|
171
|
+
// Set the transfer and switch to custom mode
|
|
172
|
+
setTransferLines([newTransfer]);
|
|
215
173
|
setRoundTripData(undefined);
|
|
216
174
|
setMode("custom");
|
|
217
175
|
setError(null);
|
|
@@ -226,6 +184,13 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
226
184
|
|
|
227
185
|
// Handle transfer line deletion
|
|
228
186
|
const handleDeleteTransferLine = (id: string) => {
|
|
187
|
+
const index = transferLines.findIndex((line) => line.id === id);
|
|
188
|
+
const transferLine = transferLines.find((line) => line.id === id);
|
|
189
|
+
|
|
190
|
+
if (index !== -1 && transferLine) {
|
|
191
|
+
onRemove?.(index, transferLine);
|
|
192
|
+
}
|
|
193
|
+
|
|
229
194
|
setTransferLines((prevLines) => prevLines.filter((line) => line.id !== id));
|
|
230
195
|
};
|
|
231
196
|
|
|
@@ -314,6 +279,7 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
314
279
|
accommodation={roundTripData?.accommodation?.id as string}
|
|
315
280
|
onChange={setRoundTripData}
|
|
316
281
|
checkEmpty={error !== null}
|
|
282
|
+
scrollOnOpen={scrollOnOpen}
|
|
317
283
|
/>
|
|
318
284
|
{/* Transfer type buttons for round-trip mode */}
|
|
319
285
|
<div className="search-bar-transfer__transfer-type">
|
|
@@ -330,6 +296,19 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
330
296
|
{renderTransferTypeButtons(handleAddTransfer)}
|
|
331
297
|
</div>
|
|
332
298
|
|
|
299
|
+
{/* Show placeholder disabled transfer line when there are no transfers */}
|
|
300
|
+
{transferLines.length === 0 && (
|
|
301
|
+
<TransferLine
|
|
302
|
+
id="placeholder-transfer"
|
|
303
|
+
type="inter-hotel"
|
|
304
|
+
locations={locations}
|
|
305
|
+
onDataChange={() => {}}
|
|
306
|
+
showDelete={false}
|
|
307
|
+
disabled={true}
|
|
308
|
+
scrollOnOpen={scrollOnOpen}
|
|
309
|
+
/>
|
|
310
|
+
)}
|
|
311
|
+
|
|
333
312
|
{/* Transfer lines list */}
|
|
334
313
|
{transferLines.length > 0 && (
|
|
335
314
|
<div className="search-bar-transfer__transfer-lines">
|
|
@@ -381,6 +360,7 @@ const SearchBarTransfer: React.FC<SearchBarTransferProps> = ({
|
|
|
381
360
|
onDelete={() => handleDeleteTransferLine(line.id)}
|
|
382
361
|
showDelete={transferLines.length > 1}
|
|
383
362
|
checkEmpty={error !== null}
|
|
363
|
+
scrollOnOpen={scrollOnOpen}
|
|
384
364
|
/>
|
|
385
365
|
))}
|
|
386
366
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import React, { useState } from
|
|
2
|
-
import
|
|
3
|
-
import Icon from
|
|
4
|
-
import { Text } from
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import '../../../styles/components/organism/transfer-line.css';
|
|
3
|
+
import Icon from '../../atoms/Icon/Icon';
|
|
4
|
+
import { Text } from '../../atoms/Typography/Typography';
|
|
5
5
|
import LocationDropdown, {
|
|
6
6
|
LocationData,
|
|
7
7
|
LocationGroup,
|
|
8
8
|
LocationOption,
|
|
9
|
-
} from
|
|
10
|
-
import DateTimePicker from
|
|
11
|
-
import PaxSelector, { PaxData } from
|
|
9
|
+
} from '../../molecules/LocationDropdown/LocationDropdown';
|
|
10
|
+
import DateTimePicker from '../DateTimePicker/DateTimePicker';
|
|
11
|
+
import PaxSelector, { PaxData } from '../PaxSelector/PaxSelector';
|
|
12
12
|
|
|
13
|
-
export type TransferType =
|
|
13
|
+
export type TransferType = 'arrival' | 'departure' | 'inter-hotel';
|
|
14
14
|
|
|
15
15
|
// Re-export LocationData for convenience
|
|
16
16
|
export type { LocationData };
|
|
@@ -62,6 +62,10 @@ export interface TransferLineProps {
|
|
|
62
62
|
className?: string;
|
|
63
63
|
/** Whether to check if inputs are empty */
|
|
64
64
|
checkEmpty?: boolean;
|
|
65
|
+
/** Whether the transfer line is disabled (placeholder state) */
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
/** Whether to scroll to the input when the calendar opens */
|
|
68
|
+
scrollOnOpen?: boolean;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
const TransferLine: React.FC<TransferLineProps> = ({
|
|
@@ -79,22 +83,22 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
79
83
|
onDataChange,
|
|
80
84
|
onDelete,
|
|
81
85
|
showDelete = true,
|
|
82
|
-
|
|
83
|
-
className =
|
|
86
|
+
showTitle = false,
|
|
87
|
+
className = '',
|
|
84
88
|
checkEmpty = false,
|
|
89
|
+
disabled = false,
|
|
90
|
+
scrollOnOpen = false,
|
|
85
91
|
}) => {
|
|
86
|
-
const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(
|
|
87
|
-
|
|
92
|
+
const [internalPaxData, setInternalPaxData] = useState<PaxData | undefined>(paxData);
|
|
93
|
+
const [internalTransferDate, setInternalTransferDate] = useState<string | undefined>(
|
|
94
|
+
transferDate
|
|
95
|
+
);
|
|
96
|
+
const [internalPickupPoint, setInternalPickupPoint] = useState<LocationData | null>(
|
|
97
|
+
null
|
|
98
|
+
);
|
|
99
|
+
const [internalDropoffPoint, setInternalDropoffPoint] = useState<LocationData | null>(
|
|
100
|
+
null
|
|
88
101
|
);
|
|
89
|
-
const [internalTransferDate, setInternalTransferDate] = useState<
|
|
90
|
-
string | undefined
|
|
91
|
-
>(transferDate);
|
|
92
|
-
const [internalPickupPoint, setInternalPickupPoint] = useState<
|
|
93
|
-
LocationData | null
|
|
94
|
-
>(null);
|
|
95
|
-
const [internalDropoffPoint, setInternalDropoffPoint] = useState<
|
|
96
|
-
LocationData | null
|
|
97
|
-
>(null);
|
|
98
102
|
|
|
99
103
|
// Helper function to get all locations (from options and groups)
|
|
100
104
|
const getAllLocations = (
|
|
@@ -109,9 +113,9 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
109
113
|
const filterLocations = (position: 'pickup' | 'dropoff') => {
|
|
110
114
|
const allOptions = locations.options || [];
|
|
111
115
|
const allGroups = locations.groups || [];
|
|
112
|
-
|
|
116
|
+
|
|
113
117
|
let filterTypes: Array<'airport' | 'port' | 'accommodation'> = [];
|
|
114
|
-
|
|
118
|
+
|
|
115
119
|
if (type === 'arrival') {
|
|
116
120
|
filterTypes = position === 'pickup' ? ['airport', 'port'] : ['accommodation'];
|
|
117
121
|
} else if (type === 'departure') {
|
|
@@ -119,15 +123,15 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
119
123
|
} else if (type === 'inter-hotel') {
|
|
120
124
|
filterTypes = ['accommodation'];
|
|
121
125
|
}
|
|
122
|
-
|
|
123
|
-
const filteredOptions = allOptions.filter(opt => filterTypes.includes(opt.type));
|
|
126
|
+
|
|
127
|
+
const filteredOptions = allOptions.filter((opt) => filterTypes.includes(opt.type));
|
|
124
128
|
const filteredGroups = allGroups
|
|
125
|
-
.map(group => ({
|
|
129
|
+
.map((group) => ({
|
|
126
130
|
...group,
|
|
127
|
-
options: group.options.filter(opt => filterTypes.includes(opt.type))
|
|
131
|
+
options: group.options.filter((opt) => filterTypes.includes(opt.type)),
|
|
128
132
|
}))
|
|
129
|
-
.filter(group => group.options.length > 0);
|
|
130
|
-
|
|
133
|
+
.filter((group) => group.options.length > 0);
|
|
134
|
+
|
|
131
135
|
return { options: filteredOptions, groups: filteredGroups };
|
|
132
136
|
};
|
|
133
137
|
|
|
@@ -135,12 +139,17 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
135
139
|
const getDefaultLocation = (position: 'pickup' | 'dropoff'): LocationOption | null => {
|
|
136
140
|
const { options, groups } = filterLocations(position);
|
|
137
141
|
const allLocations = getAllLocations(options, groups);
|
|
138
|
-
|
|
142
|
+
|
|
139
143
|
// For arrival pickup or departure dropoff, default to first airport
|
|
140
|
-
if (
|
|
141
|
-
|
|
144
|
+
if (
|
|
145
|
+
(type === 'arrival' && position === 'pickup') ||
|
|
146
|
+
(type === 'departure' && position === 'dropoff')
|
|
147
|
+
) {
|
|
148
|
+
return (
|
|
149
|
+
allLocations.find((loc) => loc.type === 'airport') || allLocations[0] || null
|
|
150
|
+
);
|
|
142
151
|
}
|
|
143
|
-
|
|
152
|
+
|
|
144
153
|
return null;
|
|
145
154
|
};
|
|
146
155
|
|
|
@@ -148,7 +157,7 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
148
157
|
React.useEffect(() => {
|
|
149
158
|
const { options, groups } = filterLocations('pickup');
|
|
150
159
|
const allPickupLocations = getAllLocations(options, groups);
|
|
151
|
-
|
|
160
|
+
|
|
152
161
|
if (pickupPoint) {
|
|
153
162
|
const location = allPickupLocations.find((loc) => loc.id === pickupPoint);
|
|
154
163
|
if (location) {
|
|
@@ -175,7 +184,7 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
175
184
|
React.useEffect(() => {
|
|
176
185
|
const { options, groups } = filterLocations('dropoff');
|
|
177
186
|
const allDropoffLocations = getAllLocations(options, groups);
|
|
178
|
-
|
|
187
|
+
|
|
179
188
|
if (dropoffPoint) {
|
|
180
189
|
const location = allDropoffLocations.find((loc) => loc.id === dropoffPoint);
|
|
181
190
|
if (location) {
|
|
@@ -211,31 +220,38 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
211
220
|
};
|
|
212
221
|
onDataChange?.(completeData);
|
|
213
222
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
214
|
-
}, [
|
|
223
|
+
}, [
|
|
224
|
+
id,
|
|
225
|
+
type,
|
|
226
|
+
internalPaxData,
|
|
227
|
+
internalTransferDate,
|
|
228
|
+
internalPickupPoint,
|
|
229
|
+
internalDropoffPoint,
|
|
230
|
+
]);
|
|
215
231
|
|
|
216
232
|
const getTypeIcon = () => {
|
|
217
233
|
switch (type) {
|
|
218
|
-
case
|
|
219
|
-
return
|
|
220
|
-
case
|
|
221
|
-
return
|
|
222
|
-
case
|
|
223
|
-
return
|
|
234
|
+
case 'arrival':
|
|
235
|
+
return 'arrival';
|
|
236
|
+
case 'departure':
|
|
237
|
+
return 'departure';
|
|
238
|
+
case 'inter-hotel':
|
|
239
|
+
return 'building';
|
|
224
240
|
default:
|
|
225
|
-
return
|
|
241
|
+
return 'arrival';
|
|
226
242
|
}
|
|
227
243
|
};
|
|
228
244
|
|
|
229
245
|
const getTypeLabel = () => {
|
|
230
246
|
switch (type) {
|
|
231
|
-
case
|
|
232
|
-
return
|
|
233
|
-
case
|
|
234
|
-
return
|
|
235
|
-
case
|
|
236
|
-
return
|
|
247
|
+
case 'arrival':
|
|
248
|
+
return 'Arrival';
|
|
249
|
+
case 'departure':
|
|
250
|
+
return 'Departure';
|
|
251
|
+
case 'inter-hotel':
|
|
252
|
+
return 'Inter-Hotel';
|
|
237
253
|
default:
|
|
238
|
-
return
|
|
254
|
+
return 'Transfer';
|
|
239
255
|
}
|
|
240
256
|
};
|
|
241
257
|
|
|
@@ -261,13 +277,16 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
261
277
|
};
|
|
262
278
|
|
|
263
279
|
// Check if inputs are empty (when checkEmpty is true)
|
|
264
|
-
const isPaxEmpty =
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
280
|
+
const isPaxEmpty =
|
|
281
|
+
checkEmpty &&
|
|
282
|
+
(!internalPaxData ||
|
|
283
|
+
(internalPaxData.adults === 0 &&
|
|
284
|
+
internalPaxData.teens === 0 &&
|
|
285
|
+
internalPaxData.children === 0 &&
|
|
286
|
+
(internalPaxData.infants === undefined || internalPaxData.infants === 0)));
|
|
269
287
|
|
|
270
|
-
const isDateEmpty =
|
|
288
|
+
const isDateEmpty =
|
|
289
|
+
checkEmpty && (!internalTransferDate || internalTransferDate === '');
|
|
271
290
|
|
|
272
291
|
const isPickupEmpty = checkEmpty && !internalPickupPoint;
|
|
273
292
|
|
|
@@ -275,22 +294,13 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
275
294
|
|
|
276
295
|
return (
|
|
277
296
|
<div
|
|
278
|
-
className={`transfer-line transfer-line--${type} ${className}`}
|
|
279
|
-
data-transfer-id={id}
|
|
280
|
-
>
|
|
297
|
+
className={`transfer-line transfer-line--${type} ${disabled ? 'transfer-line--disabled' : ''} ${className}`}
|
|
298
|
+
data-transfer-id={id}>
|
|
281
299
|
{/* Transfer type header */}
|
|
282
300
|
{showTitle && (
|
|
283
301
|
<div className="transfer-line__header">
|
|
284
|
-
<Icon
|
|
285
|
-
|
|
286
|
-
size="sm"
|
|
287
|
-
className="transfer-line__header-icon"
|
|
288
|
-
/>
|
|
289
|
-
<Text
|
|
290
|
-
size="sm"
|
|
291
|
-
variant="medium"
|
|
292
|
-
className="transfer-line__header-label"
|
|
293
|
-
>
|
|
302
|
+
<Icon name={getTypeIcon()} size="sm" className="transfer-line__header-icon" />
|
|
303
|
+
<Text size="sm" variant="medium" className="transfer-line__header-label">
|
|
294
304
|
{getTypeLabel()}
|
|
295
305
|
</Text>
|
|
296
306
|
</div>
|
|
@@ -300,23 +310,22 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
300
310
|
<div className="transfer-line__content-container">
|
|
301
311
|
<div className="transfer-line__content">
|
|
302
312
|
{/* Number of pax */}
|
|
303
|
-
<div
|
|
313
|
+
<div
|
|
314
|
+
className={`transfer-line__field transfer-line__field--pax ${isPaxEmpty ? 'transfer-line__field--error' : ''}`}>
|
|
304
315
|
<PaxSelector
|
|
305
316
|
label="Number of pax"
|
|
306
317
|
value={internalPaxData}
|
|
307
318
|
onChange={handlePaxChange}
|
|
308
319
|
placeholder="2 pax"
|
|
309
320
|
className={isPaxEmpty ? 'pax-selector--error' : ''}
|
|
321
|
+
disabled={disabled}
|
|
322
|
+
scrollOnOpen={scrollOnOpen}
|
|
310
323
|
/>
|
|
311
324
|
</div>
|
|
312
325
|
|
|
313
326
|
{/* Transfer date */}
|
|
314
327
|
<div className="transfer-line__field transfer-line__field--date">
|
|
315
|
-
<Text
|
|
316
|
-
size="sm"
|
|
317
|
-
variant="regular"
|
|
318
|
-
className="transfer-line__field-label"
|
|
319
|
-
>
|
|
328
|
+
<Text size="sm" variant="regular" className="transfer-line__field-label">
|
|
320
329
|
Transfer date
|
|
321
330
|
</Text>
|
|
322
331
|
<DateTimePicker
|
|
@@ -331,6 +340,8 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
331
340
|
defaultValue={internalTransferDate}
|
|
332
341
|
inputClassName="transfer-line__date-picker"
|
|
333
342
|
state={isDateEmpty ? 'error' : undefined}
|
|
343
|
+
disabled={disabled}
|
|
344
|
+
scrollOnOpen={scrollOnOpen}
|
|
334
345
|
/>
|
|
335
346
|
</div>
|
|
336
347
|
|
|
@@ -344,9 +355,17 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
344
355
|
onSelectionChange={handlePickupChange}
|
|
345
356
|
placeholder="Select a pick-up point"
|
|
346
357
|
direction="pickup"
|
|
347
|
-
type={
|
|
358
|
+
type={
|
|
359
|
+
type === 'inter-hotel'
|
|
360
|
+
? 'accommodation'
|
|
361
|
+
: type === 'arrival'
|
|
362
|
+
? 'airport-port'
|
|
363
|
+
: 'accommodation'
|
|
364
|
+
}
|
|
348
365
|
showGroupTitles={false}
|
|
349
366
|
error={isPickupEmpty}
|
|
367
|
+
disabled={disabled}
|
|
368
|
+
scrollOnOpen={scrollOnOpen}
|
|
350
369
|
/>
|
|
351
370
|
</div>
|
|
352
371
|
|
|
@@ -360,26 +379,29 @@ const TransferLine: React.FC<TransferLineProps> = ({
|
|
|
360
379
|
onSelectionChange={handleDropoffChange}
|
|
361
380
|
placeholder="Select a drop-off point"
|
|
362
381
|
direction="dropoff"
|
|
363
|
-
type={
|
|
382
|
+
type={
|
|
383
|
+
type === 'inter-hotel'
|
|
384
|
+
? 'accommodation'
|
|
385
|
+
: type === 'departure'
|
|
386
|
+
? 'airport-port'
|
|
387
|
+
: 'accommodation'
|
|
388
|
+
}
|
|
364
389
|
showGroupTitles={false}
|
|
365
390
|
error={isDropoffEmpty}
|
|
391
|
+
disabled={disabled}
|
|
392
|
+
scrollOnOpen={scrollOnOpen}
|
|
366
393
|
/>
|
|
367
394
|
</div>
|
|
368
395
|
</div>
|
|
369
396
|
{/* Delete button */}
|
|
370
|
-
{showDelete && (
|
|
397
|
+
{showDelete && !disabled && (
|
|
371
398
|
<div className="transfer-line__delete">
|
|
372
399
|
<button
|
|
373
400
|
type="button"
|
|
374
401
|
className="transfer-line__delete-btn"
|
|
375
402
|
onClick={onDelete}
|
|
376
|
-
aria-label="Delete transfer line"
|
|
377
|
-
|
|
378
|
-
<Icon
|
|
379
|
-
name="delete"
|
|
380
|
-
size="sm"
|
|
381
|
-
className="transfer-line__delete-icon"
|
|
382
|
-
/>
|
|
403
|
+
aria-label="Delete transfer line">
|
|
404
|
+
<Icon name="delete" size="sm" className="transfer-line__delete-icon" />
|
|
383
405
|
</button>
|
|
384
406
|
</div>
|
|
385
407
|
)}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/* AgeSelector Component Styles */
|
|
2
|
+
|
|
3
|
+
.age-selector {
|
|
4
|
+
@apply relative flex flex-col gap-2 w-20;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/* Label */
|
|
8
|
+
.age-selector__label {
|
|
9
|
+
@apply text-[var(--dropdown-color-label-default,#262626)] text-sm font-normal;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.age-selector__required {
|
|
13
|
+
@apply text-[var(--chip-color-red-outline-foreground,#991b1b)];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Container */
|
|
17
|
+
.age-selector__container {
|
|
18
|
+
@apply relative w-full;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Input wrapper - matching Figma design */
|
|
22
|
+
.age-selector__input {
|
|
23
|
+
@apply flex items-center justify-between gap-2 w-full;
|
|
24
|
+
@apply bg-white border border-[#262626] rounded-xl;
|
|
25
|
+
@apply px-4 py-3;
|
|
26
|
+
@apply transition-all duration-200;
|
|
27
|
+
@apply cursor-default;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.age-selector__input:hover {
|
|
31
|
+
@apply border-[var(--dropdown-color-border-hover,#0f7173)];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.age-selector__input--open {
|
|
35
|
+
@apply border-[var(--dropdown-color-border-hover,#0f7173)];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.age-selector__input--default .age-selector__input-field::placeholder {
|
|
39
|
+
@apply text-[var(--dropdown-selector-color-filled-foreground-default,#737373)];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Input field */
|
|
43
|
+
.age-selector__input-field {
|
|
44
|
+
@apply flex-1 bg-transparent border-none outline-none;
|
|
45
|
+
@apply text-sm font-medium leading-5;
|
|
46
|
+
@apply text-[var(--dropdown-color-foreground-value,#262626)];
|
|
47
|
+
@apply cursor-text;
|
|
48
|
+
min-width: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.age-selector__input-field::placeholder {
|
|
52
|
+
@apply text-[var(--dropdown-selector-color-filled-foreground-default,#737373)];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Dropdown button */
|
|
56
|
+
.age-selector__dropdown-btn {
|
|
57
|
+
@apply flex items-center justify-center flex-shrink-0;
|
|
58
|
+
@apply bg-transparent border-none cursor-pointer;
|
|
59
|
+
@apply p-0 m-0;
|
|
60
|
+
@apply transition-all duration-200;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.age-selector__dropdown-btn:hover {
|
|
64
|
+
@apply opacity-80;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Icon */
|
|
68
|
+
.age-selector__icon {
|
|
69
|
+
@apply text-[var(--color-text-default,#262626)];
|
|
70
|
+
@apply transition-transform duration-200;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.age-selector__icon--open {
|
|
74
|
+
@apply rotate-180;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Dropdown menu */
|
|
78
|
+
.age-selector__dropdown {
|
|
79
|
+
@apply absolute top-full left-0 right-0 mt-1;
|
|
80
|
+
@apply bg-white border border-[var(--color-border-subtle,#e5e5e5)] rounded-xl;
|
|
81
|
+
@apply max-h-48 overflow-y-auto;
|
|
82
|
+
@apply z-50;
|
|
83
|
+
@apply shadow-lg;
|
|
84
|
+
animation: age-selector-dropdown-enter 0.15s ease-out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@keyframes age-selector-dropdown-enter {
|
|
88
|
+
from {
|
|
89
|
+
opacity: 0;
|
|
90
|
+
transform: translateY(-4px);
|
|
91
|
+
}
|
|
92
|
+
to {
|
|
93
|
+
opacity: 1;
|
|
94
|
+
transform: translateY(0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Dropdown option */
|
|
99
|
+
.age-selector__option {
|
|
100
|
+
@apply w-full px-3 py-2;
|
|
101
|
+
@apply text-sm font-medium leading-5;
|
|
102
|
+
@apply text-[var(--color-text-default,#262626)];
|
|
103
|
+
@apply bg-white cursor-pointer;
|
|
104
|
+
@apply transition-all duration-150;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.age-selector__option:hover {
|
|
108
|
+
@apply bg-[var(--dropdown-selector-color-select-item-background-hover,#115b5e)];
|
|
109
|
+
@apply text-white;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.age-selector__option--selected {
|
|
113
|
+
@apply bg-[var(--dropdown-selector-color-select-item-background-selected,#0f7173)];
|
|
114
|
+
@apply text-white;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.age-selector__option--selected:hover {
|
|
118
|
+
@apply bg-[var(--dropdown-selector-color-select-item-background-selected,#0f7173)];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Scrollbar styling */
|
|
122
|
+
.age-selector__dropdown::-webkit-scrollbar {
|
|
123
|
+
@apply w-1.5;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.age-selector__dropdown::-webkit-scrollbar-track {
|
|
127
|
+
@apply bg-[#f3f4f6] rounded;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.age-selector__dropdown::-webkit-scrollbar-thumb {
|
|
131
|
+
@apply bg-[#9ca3af] rounded;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.age-selector__dropdown::-webkit-scrollbar-thumb:hover {
|
|
135
|
+
@apply bg-[#6b7280];
|
|
136
|
+
}
|
|
@@ -158,19 +158,27 @@
|
|
|
158
158
|
|
|
159
159
|
/* Disabled state */
|
|
160
160
|
.calendar-input--disabled {
|
|
161
|
-
@apply border-[
|
|
161
|
+
@apply border-[#d1d5db] bg-[#fbfbfb] cursor-not-allowed;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
.calendar-input--disabled .calendar-input__field {
|
|
165
|
-
@apply cursor-not-allowed text-[
|
|
165
|
+
@apply cursor-not-allowed text-[#a3a3a3];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.calendar-input--disabled .calendar-input__field::placeholder {
|
|
169
|
+
@apply text-[#a3a3a3];
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
.calendar-input--disabled .calendar-input__icon-button {
|
|
169
|
-
@apply !bg-none !text-[
|
|
173
|
+
@apply !bg-none !text-[#a3a3a3] cursor-not-allowed;
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
.calendar-input--disabled .calendar-input__icon-button--full-bg {
|
|
173
|
-
@apply !bg-[
|
|
177
|
+
@apply !bg-[#d1d5db] !text-[#a3a3a3] cursor-not-allowed;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.calendar-input--disabled .calendar-input__chevron {
|
|
181
|
+
@apply text-[#a3a3a3];
|
|
174
182
|
}
|
|
175
183
|
|
|
176
184
|
/* Responsive design */
|
|
@@ -79,13 +79,20 @@
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
.location-dropdown__input--disabled {
|
|
82
|
-
@apply bg-[
|
|
82
|
+
@apply bg-[#fbfbfb] border-[#d1d5db] cursor-not-allowed;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
.location-dropdown__input--disabled .location-dropdown__input-text,
|
|
86
86
|
.location-dropdown__input--disabled .location-dropdown__input-icon,
|
|
87
87
|
.location-dropdown__input--disabled .location-dropdown__input-chevron {
|
|
88
|
-
@apply text-[
|
|
88
|
+
@apply text-[#a3a3a3];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Disabled label - override all text elements */
|
|
92
|
+
.location-dropdown--disabled .location-dropdown__label,
|
|
93
|
+
.location-dropdown--disabled .location-dropdown__label p,
|
|
94
|
+
.location-dropdown--disabled .location-dropdown__label * {
|
|
95
|
+
@apply text-[#a3a3a3] font-normal !important;
|
|
89
96
|
}
|
|
90
97
|
|
|
91
98
|
/* Dropdown Panel */
|