OnlineBoard search: render Купить/Онлайн регистрация in expanded row

Angular's board search results expansion shows [Купить] [Онлайн
регистрация] [Детали рейса]. React only rendered Details. Added a
`renderActions` prop on FlightCard/FlightList so the feature layer
can inject extra buttons without the ui layer importing from
features. OnlineBoardSearchPage wires it to FlightActions with
showShare=false (the row already has a dedicated share icon).

Visibility rules fall through to canBuyTicket / canRegister (same
as BoardDetailsHeader), so cancelled/past flights still hide the
Buy button and carriers without a registrationUrl still hide the
Online Registration button — matching Angular's per-flight gating.

Integration test mocks useAppSettings to avoid requiring the real
ApiClientProvider in flight-search.test.tsx.
This commit is contained in:
2026-04-20 18:27:31 +03:00
parent 2134447664
commit 9ff034d19f
4 changed files with 54 additions and 0 deletions
+14
View File
@@ -46,6 +46,13 @@ export interface FlightCardProps {
* pages to render the per-leg route diagram.
*/
renderExpandedBody?: (flight: ISimpleFlight) => ReactNode;
/**
* Extra action buttons rendered before the default share + details
* buttons in the expanded actions row. Used by the online-board
* search page to surface the same Купить / Онлайн регистрация
* buttons Angular shows on the search results expansion.
*/
renderActions?: (flight: ISimpleFlight) => ReactNode;
}
/** Extract the primary leg from a flight (first leg for multi-leg) */
@@ -116,6 +123,7 @@ export const FlightCard: FC<FlightCardProps> = ({
onViewDetails,
direction = "route",
renderExpandedBody,
renderActions,
}) => {
const { t } = useTranslation();
const { language } = useLocale();
@@ -415,6 +423,12 @@ export const FlightCard: FC<FlightCardProps> = ({
>
<img src="/assets/img/share.svg" alt="" aria-hidden="true" />
</button>
{/* Extra actions (Купить / Онлайн регистрация). Angular
renders Buy + Registration + Details here on every
expanded board row; the caller wires up FlightActions
via renderActions so the visibility rules live with
the feature instead of leaking into the ui layer. */}
{renderActions?.(flight)}
<button
type="button"
className="flight-card__details-btn"
+9
View File
@@ -33,6 +33,13 @@ export interface FlightListProps {
* default time/transition rows.
*/
renderExpandedBody?: (flight: ISimpleFlight) => ReactNode;
/**
* Extra action buttons rendered in the default expanded-body actions
* row, right before the share/details buttons. Threads down to each
* FlightCard for the online-board search page where Angular shows
* Купить / Онлайн регистрация alongside Детали рейса.
*/
renderActions?: (flight: ISimpleFlight) => ReactNode;
}
/**
@@ -49,6 +56,7 @@ export const FlightList: FC<FlightListProps> = ({
initialCurrentFlightId,
direction = "route",
renderExpandedBody,
renderActions,
}) => {
const { t } = useTranslation();
const cardRefs = useRef<Map<string, HTMLDivElement>>(new Map());
@@ -102,6 +110,7 @@ export const FlightList: FC<FlightListProps> = ({
? { onViewDetails: () => onFlightClick(flight) }
: {})}
{...(renderExpandedBody ? { renderExpandedBody } : {})}
{...(renderActions ? { renderActions } : {})}
/>
</div>
))}