ScheduleFilter: add return-flight date range + time slider when round-trip (Angular parity)

This commit is contained in:
2026-04-20 13:26:35 +03:00
parent 9134a830da
commit e4c8948cdc
2 changed files with 116 additions and 2 deletions
@@ -54,6 +54,10 @@ export interface ScheduleFilterProps {
initialDateTo?: string;
initialTimeFrom?: string;
initialTimeTo?: string;
initialReturnDateFrom?: string;
initialReturnDateTo?: string;
initialReturnTimeFrom?: string;
initialReturnTimeTo?: string;
initialDirectOnly?: boolean;
initialReturnFlights?: boolean;
}
@@ -90,6 +94,10 @@ export const ScheduleFilter: FC<ScheduleFilterProps> = ({
initialDateTo,
initialTimeFrom,
initialTimeTo,
initialReturnDateFrom,
initialReturnDateTo,
initialReturnTimeFrom,
initialReturnTimeTo,
initialDirectOnly = false,
initialReturnFlights = false,
}) => {
@@ -111,6 +119,15 @@ export const ScheduleFilter: FC<ScheduleFilterProps> = ({
]);
const [directOnly, setDirectOnly] = useState(initialDirectOnly);
const [returnFlights, setReturnFlights] = useState(initialReturnFlights);
const initRetFrom = yyyymmddToDate(initialReturnDateFrom);
const initRetTo = yyyymmddToDate(initialReturnDateTo);
const [returnDateRange, setReturnDateRange] = useState<(Date | null)[]>(
initRetFrom && initRetTo ? [initRetFrom, initRetTo] : [null, null],
);
const [returnTimeRange, setReturnTimeRange] = useState<[number, number]>([
hhmmToMinutes(initialReturnTimeFrom, 0),
hhmmToMinutes(initialReturnTimeTo, 1440),
]);
// Mirrors Angular ScheduleFilterValidationService: a single inline
// error shown below the arrival input when the user submits with
// departure === arrival. Cleared whenever either city changes.
@@ -166,11 +183,53 @@ export const ScheduleFilter: FC<ScheduleFilterProps> = ({
: {}),
...(directOnly ? { connections: 0 } : {}),
};
const params: ScheduleParams = { type: "route", outbound };
let params: ScheduleParams;
if (returnFlights) {
// Default return range to week-after-outbound if the user
// turned the checkbox on but hasn't picked dates.
const retFromDate = returnDateRange[0] ?? (() => {
const d = new Date(to);
d.setDate(d.getDate() + 1);
return d;
})();
const retToDate = returnDateRange[1] ?? (() => {
const d = new Date(to);
d.setDate(d.getDate() + 7);
return d;
})();
const inbound = {
departure: arr,
arrival: dep,
dateFrom: dateToYyyymmdd(retFromDate),
dateTo: dateToYyyymmdd(retToDate),
...(returnTimeRange[0] !== 0 || returnTimeRange[1] !== 1440
? {
timeFrom: minutesToHhmm(returnTimeRange[0]),
timeTo: minutesToHhmm(returnTimeRange[1]),
}
: {}),
...(directOnly ? { connections: 0 } : {}),
};
params = { type: "roundtrip", outbound, inbound };
} else {
params = { type: "route", outbound };
}
const url = buildScheduleUrl(params);
void navigate(`/${locale}/${url}`);
},
[departure, arrival, dateRange, timeRange, directOnly, navigate, locale],
[
departure,
arrival,
dateRange,
timeRange,
directOnly,
returnFlights,
returnDateRange,
returnTimeRange,
navigate,
locale,
],
);
return (
@@ -291,6 +350,57 @@ export const ScheduleFilter: FC<ScheduleFilterProps> = ({
/>
<span>{t("SHARED.RETURN_FLIGHT_VIEW")}</span>
</label>
{returnFlights && (
<>
<div className="calendar">
<label className="label--filter">
{t("SHARED.RETURN_FLIGHT_DATE")}
</label>
<Calendar
value={returnDateRange}
onChange={(e) =>
setReturnDateRange(
(e.value as (Date | null)[]) ?? [null, null],
)
}
selectionMode="range"
minDate={scheduleMinDate}
maxDate={scheduleMaxDate}
dateFormat="dd.mm.yy"
placeholder={`${t("SHARED.DATE_FORMAT")} - ${t("SHARED.DATE_FORMAT")}`}
showIcon
className="input--filter"
data-testid="schedule-return-date-input"
inputId="schedule-return-date-input"
readOnlyInput
/>
</div>
<div className="wrapper--time-selector compact-view" data-testid="return-time-selector">
<div className="time-selector__label-value">
<div className="time-selector__label">
{t("SHARED.RETURN_FLIGHT_TIME")}
</div>
<div className="time-selector__value">
{minutesToTime(returnTimeRange[0])} {minutesToTime(returnTimeRange[1])}
</div>
</div>
<div className="time-selector">
<Slider
value={returnTimeRange}
onChange={(e: SliderChangeEvent) =>
setReturnTimeRange(e.value as [number, number])
}
range
min={0}
max={1440}
step={60}
/>
</div>
</div>
</>
)}
</div>
<div className="filter-button">
@@ -287,6 +287,10 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
initialDateTo={outbound.dateTo}
{...(outbound.timeFrom ? { initialTimeFrom: outbound.timeFrom } : {})}
{...(outbound.timeTo ? { initialTimeTo: outbound.timeTo } : {})}
{...(inbound?.dateFrom ? { initialReturnDateFrom: inbound.dateFrom } : {})}
{...(inbound?.dateTo ? { initialReturnDateTo: inbound.dateTo } : {})}
{...(inbound?.timeFrom ? { initialReturnTimeFrom: inbound.timeFrom } : {})}
{...(inbound?.timeTo ? { initialReturnTimeTo: inbound.timeTo } : {})}
initialDirectOnly={outbound.connections === 0}
initialReturnFlights={Boolean(inbound)}
/>