@travelswitchhq/flight-search-react 1.1.8 → 1.1.9

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/index.mjs CHANGED
@@ -54,7 +54,6 @@ var flightSearchWidgetStyles = `
54
54
  -webkit-font-smoothing: antialiased;
55
55
  -moz-osx-font-smoothing: grayscale;
56
56
  -webkit-tap-highlight-color: transparent;
57
- background: var(--sw-widget-bg);
58
57
  *,
59
58
  *::before,
60
59
  *::after {
@@ -170,10 +169,10 @@ var flightSearchWidgetStyles = `
170
169
  min-width: 0;
171
170
  overflow: visible;
172
171
  }
173
- .sw-srh-form-fieldsw-is-invalid {
172
+ .sw-srh-form-field.sw-is-invalid {
174
173
  box-shadow: inset 0 0 0 1px var(--sw-error);
175
174
  }
176
- .sw-srh-form-fieldsw-is-invalid label {
175
+ .sw-srh-form-field.sw-is-invalid label {
177
176
  color: var(--sw-error);
178
177
  }
179
178
  .sw-custom-dropdown.sw-has-error .sw-custom-dropdown-trigger {
@@ -182,7 +181,7 @@ var flightSearchWidgetStyles = `
182
181
  .sw-custom-dropdown.sw-has-error .sw-custom-dropdown-trigger::placeholder {
183
182
  color: var(--sw-error) !important;
184
183
  }
185
- .sw-form-field label {
184
+ .sw-srh-form-field label {
186
185
  display: block;
187
186
  width: 100%;
188
187
  margin: 0;
@@ -196,6 +195,13 @@ var flightSearchWidgetStyles = `
196
195
  text-overflow: ellipsis;
197
196
  text-align: initial;
198
197
  }
198
+ .sw-field-error {
199
+ margin: 2px 0 0;
200
+ color: #f60b0b !important;
201
+ font-size: 12px;
202
+ font-weight: 500;
203
+ line-height: 1.2;
204
+ }
199
205
  .p-button-label {
200
206
  flex: unset;
201
207
  }
@@ -291,6 +297,10 @@ padding-inline-start: 25px;
291
297
  border-radius: var(--sw-radius);
292
298
  box-shadow: var(--sw-widget-shadow);
293
299
  }
300
+ .p-autocomplete-panel ul {
301
+ margin-bottom: 0 !important;
302
+ padding-left: 0 !important;
303
+ }
294
304
  .sw-dropdown::-webkit-scrollbar {
295
305
  display: none;
296
306
  }
@@ -979,6 +989,9 @@ padding-inline-start: 25px;
979
989
  font-size: 12px;
980
990
  font-weight: 400;
981
991
  }
992
+ .sw-airline-autocomplete .p-autocomplete-loader {
993
+ display: none !important;
994
+ }
982
995
  .sw-fsrh-adv-cont {
983
996
  display: flex;
984
997
  align-items: center;
@@ -1461,6 +1474,10 @@ function formatDisplayDate(date) {
1461
1474
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) return "Select date";
1462
1475
  return date.toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" });
1463
1476
  }
1477
+ var isEmptyLocationValue = (value, placeholder) => {
1478
+ const trimmed = (value ?? "").trim();
1479
+ return trimmed.length === 0 || trimmed === placeholder;
1480
+ };
1464
1481
  function FlightSearchWidget({
1465
1482
  config,
1466
1483
  ssoUser
@@ -1523,6 +1540,8 @@ function FlightSearchWidget({
1523
1540
  const [isOriginDropdownOpen, setIsOriginDropdownOpen] = useState(false);
1524
1541
  const [isDestinationDropdownOpen, setIsDestinationDropdownOpen] = useState(false);
1525
1542
  const [isRoomsGuestsMenuOpen, setIsRoomsGuestsMenuOpen] = useState(false);
1543
+ const [roundTripMinDate, setRoundTripMinDate] = useState(/* @__PURE__ */ new Date());
1544
+ const [activeRoundTripField, setActiveRoundTripField] = useState("departure");
1526
1545
  const originDropdownRef = useRef(null);
1527
1546
  const firstOriginDesktopInputRef = useRef(null);
1528
1547
  const destinationDropdownRef = useRef(null);
@@ -1732,6 +1751,12 @@ function FlightSearchWidget({
1732
1751
  getAirlineListBySearch(value).then(setAirlineSuggestions);
1733
1752
  }, DEBOUNCE_MS);
1734
1753
  }, [getAirlineListBySearch]);
1754
+ useEffect(() => {
1755
+ if (typeof window === "undefined") return;
1756
+ if (window.matchMedia("(max-width: 768px)").matches) {
1757
+ setIsOriginDropdownOpen(false);
1758
+ }
1759
+ }, []);
1735
1760
  useEffect(() => () => {
1736
1761
  if (searchDebounceRef.current) clearTimeout(searchDebounceRef.current);
1737
1762
  if (airlineSearchDebounceRef.current) clearTimeout(airlineSearchDebounceRef.current);
@@ -1975,7 +2000,12 @@ function FlightSearchWidget({
1975
2000
  };
1976
2001
  const extractAirportCode = (location) => {
1977
2002
  const match = location.match(/\(([A-Z]{3})\)/);
1978
- return match ? match[1] : location;
2003
+ return match ? match[1] : location.trim();
2004
+ };
2005
+ const getComparableLocation = (location) => {
2006
+ const code = extractAirportCode(location).trim().toUpperCase();
2007
+ if (code.length === 3 && /^[A-Z]{3}$/.test(code)) return code;
2008
+ return location.trim().toLowerCase().replace(/\s+/g, " ");
1979
2009
  };
1980
2010
  const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1981
2011
  const formatDate = (date) => {
@@ -2136,13 +2166,22 @@ function FlightSearchWidget({
2136
2166
  const segmentsToValidate = isMultiCityOrCustom ? segments : segments.slice(0, 1);
2137
2167
  const nextErrors = {};
2138
2168
  segmentsToValidate.forEach((segment, index) => {
2139
- const originInvalid = !isValidLocationValue(segment.origin, "Origin");
2140
- const destinationInvalid = !isValidLocationValue(segment.destination, "Destination");
2169
+ const originValue = typeof segment.origin === "string" ? segment.origin : "";
2170
+ const destinationValue = typeof segment.destination === "string" ? segment.destination : "";
2171
+ const originInvalid = isEmptyLocationValue(originValue, "Origin");
2172
+ const destinationInvalid = isEmptyLocationValue(destinationValue, "Destination");
2141
2173
  if (originInvalid || destinationInvalid) {
2142
2174
  nextErrors[index] = {
2143
2175
  origin: originInvalid,
2144
2176
  destination: destinationInvalid
2145
2177
  };
2178
+ return;
2179
+ }
2180
+ if (getComparableLocation(originValue) === getComparableLocation(destinationValue)) {
2181
+ nextErrors[index] = {
2182
+ origin: true,
2183
+ destination: true
2184
+ };
2146
2185
  }
2147
2186
  });
2148
2187
  if (Object.keys(nextErrors).length > 0) {
@@ -2249,6 +2288,47 @@ function FlightSearchWidget({
2249
2288
  if (prev instanceof Date && !isNaN(prev.getTime())) return prev;
2250
2289
  return today;
2251
2290
  };
2291
+ const openRoundTripCalendar = (mode) => {
2292
+ const today = /* @__PURE__ */ new Date();
2293
+ const selectedDeparture = segments[0]?.dateRange?.[0] ?? segments[0]?.departureDate ?? null;
2294
+ const validDeparture = selectedDeparture instanceof Date && !isNaN(selectedDeparture.getTime()) ? selectedDeparture : today;
2295
+ setActiveRoundTripField(mode);
2296
+ setRoundTripMinDate(mode === "return" ? validDeparture : today);
2297
+ dateRangeCalendarRef.current?.show?.();
2298
+ mobileDateRangeCalendarRef.current?.show?.();
2299
+ };
2300
+ const applyRoundTripRangeChange = (range) => {
2301
+ setSegments((prev) => {
2302
+ const updated = [...prev];
2303
+ if (!updated[0]) return prev;
2304
+ const current = updated[0];
2305
+ const currentDeparture = current.dateRange?.[0] ?? current.departureDate ?? /* @__PURE__ */ new Date();
2306
+ if (activeRoundTripField === "return") {
2307
+ const pickedReturn = range?.[1] ?? range?.[0] ?? currentDeparture;
2308
+ const safeReturn = pickedReturn instanceof Date && pickedReturn.getTime() >= currentDeparture.getTime() ? pickedReturn : currentDeparture;
2309
+ updated[0] = {
2310
+ ...current,
2311
+ dateRange: [currentDeparture, safeReturn],
2312
+ departureDate: currentDeparture,
2313
+ returnDate: safeReturn
2314
+ };
2315
+ return updated;
2316
+ }
2317
+ updated[0] = {
2318
+ ...current,
2319
+ dateRange: range,
2320
+ departureDate: range?.[0] ?? /* @__PURE__ */ new Date(),
2321
+ returnDate: range?.[1] ?? /* @__PURE__ */ new Date()
2322
+ };
2323
+ return updated;
2324
+ });
2325
+ if (activeRoundTripField === "return") {
2326
+ setTimeout(() => {
2327
+ dateRangeCalendarRef.current?.hide?.();
2328
+ mobileDateRangeCalendarRef.current?.hide?.();
2329
+ }, 50);
2330
+ }
2331
+ };
2252
2332
  const renderFlightSegment = (index, segment, isMultiCityOrCustom) => {
2253
2333
  const canRemove = segments.length > 2 && index > 0 && isMultiCityOrCustom;
2254
2334
  const originRef = (el) => {
@@ -2388,10 +2468,7 @@ function FlightSearchWidget({
2388
2468
  renderAirportDropdown(0, "destination", destinationDropdownRef, isDestinationDropdownOpen, () => setIsDestinationDropdownOpen(true))
2389
2469
  ] }),
2390
2470
  (tripType === "round-trip" || tripType === "one-way") && /* @__PURE__ */ jsx("div", { className: "sw-srh-wrap sw-pos-rel mobiBox", children: tripType === "round-trip" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2391
- /* @__PURE__ */ jsxs("div", { style: { cursor: "pointer" }, onClick: () => {
2392
- dateRangeCalendarRef.current?.show?.();
2393
- mobileDateRangeCalendarRef.current?.show?.();
2394
- }, className: "sw-srh-form-field sw-com-cal", children: [
2471
+ /* @__PURE__ */ jsxs("div", { style: { cursor: "pointer" }, onClick: () => openRoundTripCalendar("departure"), className: "sw-srh-form-field sw-com-cal", children: [
2395
2472
  /* @__PURE__ */ jsxs("div", { children: [
2396
2473
  /* @__PURE__ */ jsx("label", { children: "Departure" }),
2397
2474
  /* @__PURE__ */ jsx("p", { children: segments[0]?.dateRange?.[0]?.toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" }) })
@@ -2405,23 +2482,15 @@ function FlightSearchWidget({
2405
2482
  appendTo: "self",
2406
2483
  selectionMode: "range",
2407
2484
  value: segments[0]?.dateRange ?? null,
2408
- minDate: /* @__PURE__ */ new Date(),
2485
+ minDate: roundTripMinDate,
2409
2486
  onChange: (e) => {
2410
2487
  const range = e.value;
2411
- setSegments((prev) => {
2412
- const u = [...prev];
2413
- if (!u[0]) return prev;
2414
- u[0] = {
2415
- ...u[0],
2416
- dateRange: range,
2417
- departureDate: range?.[0] ?? /* @__PURE__ */ new Date(),
2418
- returnDate: range?.[1] ?? /* @__PURE__ */ new Date()
2419
- };
2420
- return u;
2421
- });
2422
- if (range?.[0] && range?.[1]) setTimeout(() => {
2423
- dateRangeCalendarRef.current?.hide?.();
2424
- }, 150);
2488
+ applyRoundTripRangeChange(range);
2489
+ if (activeRoundTripField === "departure" && range?.[0] && range?.[1]) {
2490
+ setTimeout(() => {
2491
+ dateRangeCalendarRef.current?.hide?.();
2492
+ }, 150);
2493
+ }
2425
2494
  },
2426
2495
  dateFormat: "dd M yy",
2427
2496
  placeholder: "Select date range",
@@ -2437,20 +2506,10 @@ function FlightSearchWidget({
2437
2506
  appendTo: "self",
2438
2507
  selectionMode: "range",
2439
2508
  value: segments[0]?.dateRange ?? null,
2440
- minDate: /* @__PURE__ */ new Date(),
2509
+ minDate: roundTripMinDate,
2441
2510
  onChange: (e) => {
2442
2511
  const range = e.value;
2443
- setSegments((prev) => {
2444
- const u = [...prev];
2445
- if (!u[0]) return prev;
2446
- u[0] = {
2447
- ...u[0],
2448
- dateRange: range,
2449
- departureDate: range?.[0] ?? /* @__PURE__ */ new Date(),
2450
- returnDate: range?.[1] ?? /* @__PURE__ */ new Date()
2451
- };
2452
- return u;
2453
- });
2512
+ applyRoundTripRangeChange(range);
2454
2513
  },
2455
2514
  dateFormat: "dd M yy",
2456
2515
  placeholder: "Select date range",
@@ -2480,10 +2539,7 @@ function FlightSearchWidget({
2480
2539
  }
2481
2540
  )
2482
2541
  ] }),
2483
- /* @__PURE__ */ jsx("div", { style: { cursor: "pointer" }, className: "sw-srh-form-field sw-com-cal", onClick: () => {
2484
- dateRangeCalendarRef.current?.show?.();
2485
- mobileDateRangeCalendarRef.current?.show?.();
2486
- }, children: /* @__PURE__ */ jsxs("div", { children: [
2542
+ /* @__PURE__ */ jsx("div", { style: { cursor: "pointer" }, className: "sw-srh-form-field sw-com-cal", onClick: () => openRoundTripCalendar("return"), children: /* @__PURE__ */ jsxs("div", { children: [
2487
2543
  /* @__PURE__ */ jsx("label", { children: "Return" }),
2488
2544
  /* @__PURE__ */ jsx("p", { children: (segments[0]?.dateRange?.[1] ?? segments[0]?.dateRange?.[0])?.toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" }) })
2489
2545
  ] }) })
@@ -2744,6 +2800,7 @@ function FlightSearchWidget({
2744
2800
  /* @__PURE__ */ jsx(
2745
2801
  AutoComplete,
2746
2802
  {
2803
+ className: "sw-airline-autocomplete",
2747
2804
  value: selectedAirlines,
2748
2805
  suggestions: airlineSuggestions,
2749
2806
  completeMethod: (e) => {