From e694ccf42b30936fec39e1b519f06d0fd4700a76 Mon Sep 17 00:00:00 2001 From: gnezim Date: Mon, 20 Apr 2026 16:51:06 +0300 Subject: [PATCH] =?UTF-8?q?ScheduleFlightBody=20"=D0=9A=D1=83=D0=BF=D0=B8?= =?UTF-8?q?=D1=82=D1=8C"=20button:=20wire=20onBuy=20=E2=86=92=20Aeroflot?= =?UTF-8?q?=20booking=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DayGroupedFlightList gains an optional `onBuy` prop that forwards to ScheduleFlightBody. ScheduleSearchPage implements handleBuy — matches BoardDetailsHeader.BuyTicketButton: opens `aeroflot.ru/sb/app/{lang}-{lang}#/search?routes={dep}.{yyyyMMdd}.{arr}` in a new tab, using the first leg's airportCode + scheduled-departure UTC for direct and multi-leg flights. Previously the Buy button rendered but its click was `onBuy?.()` with no handler wired, so nothing happened. The button text + wiring now mirror Angular's `buy-ticket-button.component`. --- .../components/DayGroupedFlightList.tsx | 6 ++++- .../components/ScheduleSearchPage.tsx | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/features/schedule/components/DayGroupedFlightList.tsx b/src/features/schedule/components/DayGroupedFlightList.tsx index acc72bd6..ede571dc 100644 --- a/src/features/schedule/components/DayGroupedFlightList.tsx +++ b/src/features/schedule/components/DayGroupedFlightList.tsx @@ -32,6 +32,8 @@ export interface DayGroupedFlightListProps { flights: ISimpleFlight[]; loading?: boolean; onFlightClick?: (flight: ISimpleFlight) => void; + /** Click handler for the `Купить` button inside each expanded flight body. */ + onBuy?: (flight: ISimpleFlight) => void; initialCurrentFlightId?: string | null; } @@ -125,6 +127,7 @@ export const DayGroupedFlightList: FC = ({ flights, loading, onFlightClick, + onBuy, initialCurrentFlightId, }) => { const { language } = useLocale(); @@ -236,9 +239,10 @@ export const DayGroupedFlightList: FC = ({ onFlightClick(f) } : {})} + {...(onBuy ? { onBuy: () => onBuy(f) } : {})} /> ), - [onFlightClick], + [onFlightClick, onBuy], ); if (loading) return ; diff --git a/src/features/schedule/components/ScheduleSearchPage.tsx b/src/features/schedule/components/ScheduleSearchPage.tsx index 2516e8b5..6d3711b2 100644 --- a/src/features/schedule/components/ScheduleSearchPage.tsx +++ b/src/features/schedule/components/ScheduleSearchPage.tsx @@ -142,6 +142,30 @@ export const ScheduleSearchPage: FC = ({ params }) => { [locale, navigate], ); + // `Купить` button — opens Aeroflot's booking flow in a new tab, same + // URL shape as BoardDetailsHeader's BuyTicketButton: + // https://www.aeroflot.ru/sb/app/{lang}-{lang}#/search?…&routes={dep}.{yyyyMMdd}.{arr} + const handleBuy = useCallback( + (flight: ISimpleFlight) => { + const legs = flight.routeType === "Direct" ? [flight.leg] : flight.legs; + const firstLeg = legs[0]; + const lastLeg = legs[legs.length - 1]; + if (!firstLeg || !lastLeg) return; + const dep = firstLeg.departure.scheduled.airportCode; + const arr = lastLeg.arrival.scheduled.airportCode; + const depUtc = firstLeg.departure.times.scheduledDeparture.utc; + const depDate = new Date(depUtc); + const yyyy = depDate.getFullYear().toString(); + const mm = (depDate.getMonth() + 1).toString().padStart(2, "0"); + const dd = depDate.getDate().toString().padStart(2, "0"); + const url = `https://www.aeroflot.ru/sb/app/${language}-${language}#/search?adults=1&cabin=economy&children=0&infants=0&routes=${dep}.${yyyy}${mm}${dd}.${arr}&autosearch=Y`; + if (typeof window !== "undefined") { + window.open(url, "_blank", "noopener,noreferrer"); + } + }, + [language], + ); + // Round-trip schedules render only one direction at a time, with a // `Туда / Обратно` switcher in the sticky header — matches Angular's // `schedule-direction-switch` (one-of-two button group). Default to @@ -394,6 +418,7 @@ export const ScheduleSearchPage: FC = ({ params }) => { flights={outboundSimple} loading={outboundLoading} onFlightClick={handleFlightClick} + onBuy={handleBuy} /> ) : ( @@ -402,6 +427,7 @@ export const ScheduleSearchPage: FC = ({ params }) => { flights={inboundSimple} loading={inboundLoading} onFlightClick={handleFlightClick} + onBuy={handleBuy} /> )}