ScheduleFilter: wire time range slider to schedule URL + seed from URL

This commit is contained in:
2026-04-20 12:21:04 +03:00
parent ce57c982da
commit 62d3d68c1b
2 changed files with 42 additions and 11 deletions
@@ -26,6 +26,12 @@ function minutesToTime(minutes: number): string {
return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`;
}
function minutesToHhmm(minutes: number): string {
const h = Math.floor(minutes / 60);
const m = minutes % 60;
return `${String(h).padStart(2, "0")}${String(m).padStart(2, "0")}`;
}
function dateToYyyymmdd(value: Date): string {
const y = value.getFullYear().toString();
const m = (value.getMonth() + 1).toString().padStart(2, "0");
@@ -46,15 +52,27 @@ export interface ScheduleFilterProps {
initialArrival?: string;
initialDateFrom?: string;
initialDateTo?: string;
initialTimeFrom?: string;
initialTimeTo?: string;
initialDirectOnly?: boolean;
initialReturnFlights?: boolean;
}
function hhmmToMinutes(value: string | undefined, fallback: number): number {
if (!value || value.length !== 4) return fallback;
const h = Number(value.slice(0, 2));
const m = Number(value.slice(2, 4));
if (Number.isNaN(h) || Number.isNaN(m)) return fallback;
return h * 60 + m;
}
export const ScheduleFilter: FC<ScheduleFilterProps> = ({
initialDeparture,
initialArrival,
initialDateFrom,
initialDateTo,
initialTimeFrom,
initialTimeTo,
initialDirectOnly = false,
initialReturnFlights = false,
}) => {
@@ -70,7 +88,10 @@ export const ScheduleFilter: FC<ScheduleFilterProps> = ({
const [dateRange, setDateRange] = useState<(Date | null)[]>(
initFrom && initTo ? [initFrom, initTo] : [null, null],
);
const [timeRange, setTimeRange] = useState<[number, number]>([0, 1440]);
const [timeRange, setTimeRange] = useState<[number, number]>([
hhmmToMinutes(initialTimeFrom, 0),
hhmmToMinutes(initialTimeTo, 1440),
]);
const [directOnly, setDirectOnly] = useState(initialDirectOnly);
const [returnFlights, setReturnFlights] = useState(initialReturnFlights);
@@ -97,20 +118,28 @@ export const ScheduleFilter: FC<ScheduleFilterProps> = ({
const from = dateRange[0] ?? monday;
const to = dateRange[1] ?? sunday;
const params: ScheduleParams = {
type: "route",
outbound: {
departure: dep,
arrival: arr,
dateFrom: dateToYyyymmdd(from),
dateTo: dateToYyyymmdd(to),
...(directOnly ? { connections: 0 } : {}),
},
const outbound = {
departure: dep,
arrival: arr,
dateFrom: dateToYyyymmdd(from),
dateTo: dateToYyyymmdd(to),
// Only include time range when it's been narrowed from the full
// day — Angular spreads `...this.timeRange` which is undefined
// until the user interacts with the slider, so the URL stays
// clean for the default 00:0024:00 case.
...(timeRange[0] !== 0 || timeRange[1] !== 1440
? {
timeFrom: minutesToHhmm(timeRange[0]),
timeTo: minutesToHhmm(timeRange[1]),
}
: {}),
...(directOnly ? { connections: 0 } : {}),
};
const params: ScheduleParams = { type: "route", outbound };
const url = buildScheduleUrl(params);
void navigate(`/${locale}/${url}`);
},
[departure, arrival, dateRange, directOnly, navigate, locale],
[departure, arrival, dateRange, timeRange, directOnly, navigate, locale],
);
return (
@@ -285,6 +285,8 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
initialArrival={outbound.arrival}
initialDateFrom={outbound.dateFrom}
initialDateTo={outbound.dateTo}
{...(outbound.timeFrom ? { initialTimeFrom: outbound.timeFrom } : {})}
{...(outbound.timeTo ? { initialTimeTo: outbound.timeTo } : {})}
initialDirectOnly={outbound.connections === 0}
initialReturnFlights={Boolean(inbound)}
/>