Transfer gaps 40px + always-visible Buy pill in schedule summary

The Пересадка wrapper bumps to $space-xxl (40px) margin: at 15px
the strip blended with the regular between-card gap from
`.schedule-details { gap: $space-l }` and read as a sibling card
rather than a separator. 40/40 mirrors Angular's breathing room.

FlightActions gains a `forceBuy` prop that bypasses the
canBuyTicket() status/window gate. The schedule summary passes it
because the Buy pill there is a generic 'open the Aeroflot booking
tool for this route' affordance — the user picks any date in the
booking flow, so hiding the button on a specific day's 'Cancelled'
status (as the Onlineboard detail page does) loses a useful entry
point. Board detail pages still pass the default (status-gated).
This commit is contained in:
2026-04-23 17:19:32 +03:00
parent d8118bafa8
commit fbd819c707
3 changed files with 18 additions and 2 deletions
@@ -19,6 +19,14 @@ export interface FlightActionsProps {
showShare?: boolean;
showRegister?: boolean;
showBuy?: boolean;
/**
* Skip the `canBuyTicket` status/window gate and always render the
* Buy pill. Used by the Schedule summary header where the Buy link
* is a generic "open the Aeroflot booking tool for this route"
* affordance — the user can then pick any date, so gating on a
* particular day's "Cancelled" status would hide a useful action.
*/
forceBuy?: boolean;
}
export const FlightActions: FC<FlightActionsProps> = ({
@@ -29,11 +37,13 @@ export const FlightActions: FC<FlightActionsProps> = ({
showShare = true,
showRegister = true,
showBuy = true,
forceBuy = false,
}) => {
const { flightStatusAvailableFromHours, buyTicketMinHours, buyTicketMaxHours } = useAppSettings();
const now = new Date();
const canBuy = showBuy && canBuyTicket(flight, now, buyTicketMinHours, buyTicketMaxHours);
const canBuy =
showBuy && (forceBuy || canBuyTicket(flight, now, buyTicketMinHours, buyTicketMaxHours));
const canReg = showRegister && canRegister(flight, AIRLINES);
const canStatus =
showStatus &&
@@ -49,7 +49,12 @@
// and the next flight's header, reading as a shared edge rather than
// a separator.
.schedule-details__transfer {
margin: vars.$space-l 0;
// $space-xxl (40px) so the strip reads unmistakably as a SEPARATOR.
// $space-l (15px) was physically present but visually indistinguishable
// from the regular between-card gap set by `.schedule-details { gap }`,
// so the Пересадка looked glued to its neighbours. 40/40 mirrors
// Angular's breathing room between `.multi-flight--details` blocks.
margin: vars.$space-xxl 0;
> .transfer-bar {
border-radius: vars.$border-radius;
@@ -512,6 +512,7 @@ export const ScheduleDetailsPage: FC<ScheduleDetailsPageProps> = ({
locale={locale}
showStatus={miniListCurrentFlight.routeType === "Direct"}
showRegister={false}
forceBuy
/>
<LastUpdate flight={miniListCurrentFlight} locale={locale} />
</div>