diff --git a/src/features/schedule/components/ScheduleStartPage.tsx b/src/features/schedule/components/ScheduleStartPage.tsx index 6b323082..bfc331a2 100644 --- a/src/features/schedule/components/ScheduleStartPage.tsx +++ b/src/features/schedule/components/ScheduleStartPage.tsx @@ -7,17 +7,16 @@ * @module */ -import { type FC, useState, useCallback, useEffect, type FormEvent } from "react"; +import { type FC, useState, useCallback, type FormEvent } from "react"; import { useNavigate } from "@modern-js/runtime/router"; import { useLocale } from "@/i18n/useLocale.js"; import { Calendar } from "primereact/calendar"; import { Slider, type SliderChangeEvent } from "primereact/slider"; -import { AutoComplete, type AutoCompleteCompleteEvent } from "primereact/autocomplete"; import { useTranslation } from "@/i18n/provider.js"; -import { useCitySearch, type CitySuggestion } from "@/shared/hooks/useCitySearch.js"; import { PageLayout } from "@/ui/layout/PageLayout.js"; import { PageTabs } from "@/ui/layout/PageTabs.js"; import { SearchHistory } from "@/ui/layout/SearchHistory.js"; +import { CityAutocomplete } from "@/ui/city-autocomplete/index.js"; import { PopularRequestsPanel } from "@/features/popular-requests/components/PopularRequestsPanel.js"; import type { PopularRequest } from "@/features/popular-requests/types.js"; import { @@ -90,38 +89,13 @@ export const ScheduleStartPage: FC = () => { const today = new Date(); - const [departureAirport, setDepartureAirport] = useState(prefill.departure ?? ""); - const [arrivalAirport, setArrivalAirport] = useState(prefill.arrival ?? ""); + // State is the IATA city code (string). The shared CityAutocomplete + // resolves the code to a localized display name internally — same + // component used on OnlineBoard and FlightsMap, so the clear (×) + // button, regional picker, and airport→city resolution come for free. + const [departureCode, setDepartureCode] = useState(prefill.departure ?? ""); + const [arrivalCode, setArrivalCode] = useState(prefill.arrival ?? ""); - // Prefill arrives as a bare IATA code ("MOW"). Once dictionaries are - // loaded, upgrade each state slot to a `{code, name}` CitySuggestion - // so the PrimeReact AutoComplete renders "Москва" rather than the raw - // code. Mirrors Angular's CityAutocomplete.writeValue + getCityOrAirport. - useEffect(() => { - if (!dictionaries) return; - const resolve = (code: string): CitySuggestion | null => { - const upper = code.toUpperCase(); - const city = dictionaries.cityByCode.get(upper); - if (city) return { code: city.code, name: city.name }; - const airport = dictionaries.airportByCode.get(upper); - if (airport) { - const parentCode = airport.city_code?.toUpperCase(); - const parent = parentCode - ? dictionaries.cityByCode.get(parentCode) - : null; - if (parent) return { code: parent.code, name: parent.name }; - } - return null; - }; - setDepartureAirport((current) => { - if (typeof current !== "string" || !current) return current; - return resolve(current) ?? current; - }); - setArrivalAirport((current) => { - if (typeof current !== "string" || !current) return current; - return resolve(current) ?? current; - }); - }, [dictionaries]); // Start blank to match Angular's `ДД.ММ.ГГГГ - ДД.ММ.ГГГГ` placeholder // (the "current week" pre-fill was a React-only convenience that // pulled the date input out of parity). Submit handler defaults to @@ -135,28 +109,12 @@ export const ScheduleStartPage: FC = () => { const [returnDateTo, setReturnDateTo] = useState(null); const [returnTimeRange, setReturnTimeRange] = useState<[number, number]>([0, 1440]); - // City autocomplete search - const { suggestions: departureSuggestions, search: searchDeparture } = useCitySearch(); - const { suggestions: arrivalSuggestions, search: searchArrival } = useCitySearch(); - - const handleDepartureSearch = useCallback((event: AutoCompleteCompleteEvent) => { - void searchDeparture(event.query); - }, [searchDeparture]); - - const handleArrivalSearch = useCallback((event: AutoCompleteCompleteEvent) => { - void searchArrival(event.query); - }, [searchArrival]); - const handleSubmit = useCallback( (e: FormEvent) => { e.preventDefault(); - const dep = (typeof departureAirport === "string" - ? departureAirport.trim().toUpperCase() - : departureAirport.code); - const arr = (typeof arrivalAirport === "string" - ? arrivalAirport.trim().toUpperCase() - : arrivalAirport.code); + const dep = departureCode.trim().toUpperCase(); + const arr = arrivalCode.trim().toUpperCase(); if (!dep || !arr) return; // Empty dates default to the current week (today → today + 7) so @@ -202,7 +160,7 @@ export const ScheduleStartPage: FC = () => { void navigate(`/${locale}/${url}`); }, - [departureAirport, arrivalAirport, dateFrom, dateTo, timeRange, directOnly, isRoundTrip, returnDateFrom, returnDateTo, returnTimeRange, navigate, locale], + [departureCode, arrivalCode, dateFrom, dateTo, timeRange, directOnly, isRoundTrip, returnDateFrom, returnDateTo, returnTimeRange, navigate, locale], ); const handlePopularRequestClick = useCallback( @@ -240,31 +198,23 @@ export const ScheduleStartPage: FC = () => { data-testid="schedule-search-form" onSubmit={handleSubmit} > -
- - setDepartureAirport(e.value as CitySuggestion | string)} - placeholder={t("SHARED.CITY_PLACEHOLDER")} - className="input--filter" - inputClassName="input--filter" - inputId="schedule-departure" - data-testid="departure-input" - /> -
+
-
- - setArrivalAirport(e.value as CitySuggestion | string)} - placeholder={t("SHARED.CITY_PLACEHOLDER")} - className="input--filter" - inputClassName="input--filter" - inputId="schedule-arrival" - data-testid="arrival-input" - /> -
+