diff --git a/src/features/schedule/components/ScheduleSearchPage.tsx b/src/features/schedule/components/ScheduleSearchPage.tsx index e0c37f36..0c3f9e14 100644 --- a/src/features/schedule/components/ScheduleSearchPage.tsx +++ b/src/features/schedule/components/ScheduleSearchPage.tsx @@ -297,16 +297,6 @@ export const ScheduleSearchPage: FC = ({ params }) => { { - // Day group sections are keyed by `data-day=${ymd}` - // (see DayGroupedFlightList). Scroll the matching one - // into view; this stays a no-op if it's not rendered. - if (typeof document === "undefined") return; - const el = document.querySelector( - `[data-day="${dayYmd}"]`, - ); - if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); - }} /> {inbound && (
void; - /** Optional yyyy-MM-dd of the highlighted day within the week. */ - selectedDayYmd?: string; - /** Optional callback when a specific day tab is clicked. */ - onSelectDay?: (dayYmd: string) => void; } -interface DayEntry { - date: Date; +interface WeekEntry { + monday: Date; + sunday: Date; ymd: string; - dayNum: string; - weekday: string; + label: string; +} + +function startOfWeekMonday(d: Date): Date { + const out = new Date(d); + const day = out.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat + const diff = (day + 6) % 7; // distance back to Monday + out.setDate(out.getDate() - diff); + out.setHours(0, 0, 0, 0); + return out; +} + +function fmt(date: Date, fmt: Intl.DateTimeFormat): string { + return fmt.format(date).replace(/\.$/, ""); } function ymd(d: Date): string { @@ -39,67 +50,44 @@ function ymd(d: Date): string { return `${y}-${m}-${day}`; } -function parseYmd(s: string): Date | null { - if (!s || s.length !== 10) return null; - const y = parseInt(s.slice(0, 4), 10); - const m = parseInt(s.slice(5, 7), 10) - 1; - const d = parseInt(s.slice(8, 10), 10); - if (Number.isNaN(y) || Number.isNaN(m) || Number.isNaN(d)) return null; - return new Date(y, m, d); -} - -function shiftWeek(monday: Date, deltaWeeks: number): string { - const next = new Date(monday); - next.setDate(monday.getDate() + deltaWeeks * 7); - return ymd(next); -} - -function todayYmd(): string { - return ymd(new Date()); -} - -export const WeekTabs: FC = ({ - selectedMonday, - onNavigate, - selectedDayYmd, - onSelectDay, -}) => { +export const WeekTabs: FC = ({ selectedMonday, onNavigate }) => { const { language } = useLocale(); - // 'пн', 'вт', … — short weekday in active locale. Built once per - // locale; the `.replace(/\.$/, "")` strips Russian's trailing dot. - const weekdayFmt = useMemo( - () => new Intl.DateTimeFormat(language, { weekday: "short" }), + // Angular shows month abbreviated ("13 апр - 19 апр"). Build once + // per locale; the month part comes through in the locale's natural + // short form. + const dayMonthFmt = useMemo( + () => new Intl.DateTimeFormat(language, { day: "numeric", month: "short" }), [language], ); - const monday = useMemo(() => parseYmd(selectedMonday), [selectedMonday]); - - const days: DayEntry[] = useMemo(() => { - if (!monday) return []; - const out: DayEntry[] = []; - for (let i = 0; i < 7; i++) { - const d = new Date(monday); - d.setDate(monday.getDate() + i); + const weeks: WeekEntry[] = useMemo(() => { + const out: WeekEntry[] = []; + const today = new Date(); + const start = startOfWeekMonday(today); + start.setDate(start.getDate() - WEEKS_BEFORE * 7); + for (let i = 0; i < WEEKS_BEFORE + WEEKS_AFTER + 1; i++) { + const monday = new Date(start); + monday.setDate(start.getDate() + i * 7); + const sunday = new Date(monday); + sunday.setDate(monday.getDate() + 6); out.push({ - date: d, - ymd: ymd(d), - dayNum: String(d.getDate()), - weekday: weekdayFmt.format(d).replace(/\.$/, "").toLowerCase(), + monday, + sunday, + ymd: ymd(monday), + label: `${fmt(monday, dayMonthFmt)} - ${fmt(sunday, dayMonthFmt)}`, }); } return out; - }, [monday, weekdayFmt]); + }, [dayMonthFmt]); - if (!monday || days.length === 0) { - return null; - } + const initialPage = Math.max( + 0, + Math.floor(weeks.findIndex((w) => w.ymd === selectedMonday) / PAGE_SIZE), + ); + const [page, setPage] = useState(Number.isFinite(initialPage) ? initialPage : 0); + const totalPages = Math.max(1, Math.ceil(weeks.length / PAGE_SIZE)); - const today = todayYmd(); - const highlight = selectedDayYmd && days.some((d) => d.ymd === selectedDayYmd) - ? selectedDayYmd - : days.some((d) => d.ymd === today) - ? today - : days[0]!.ymd; + const visible = weeks.slice(page * PAGE_SIZE, page * PAGE_SIZE + PAGE_SIZE); return (