Fix map route reset after city reselection

This commit is contained in:
2026-04-30 08:39:14 +03:00
parent a81587d9a7
commit be0d5e686b
4 changed files with 66 additions and 23 deletions
@@ -178,7 +178,12 @@ export const FlightsMapFilter: FC<FlightsMapFilterProps> = ({
});
return;
}
onChange({ ...value, departure: code, arrival: undefined });
onChange({
...value,
departure: code,
arrival: undefined,
connections: false,
});
}}
dictionaries={dictionaries}
onLocate={handleLocate}
@@ -196,7 +201,11 @@ export const FlightsMapFilter: FC<FlightsMapFilterProps> = ({
placeholder={t("FLIGHTS-MAP.FILTER_ARRIVAL_PLACEHOLDER")}
value={value.arrival ?? ""}
onChange={(code) => {
onChange({ ...value, arrival: code || undefined });
onChange({
...value,
arrival: code || undefined,
connections: code ? value.connections : false,
});
}}
dictionaries={dictionaries}
testIdPrefix="fm-arrival"
@@ -910,6 +910,32 @@ describe("§4.1.24.4: interactive map click sequence", () => {
expect(filterValue["arrival"]).toBeUndefined();
});
it("4.1.24-R39: third click returns to spider mode with connections reset", () => {
searchState.routes = [{ route: ["MOW", "LED"], isDirect: true }];
setMapFilter({
departure: "MOW",
arrival: "LED",
date: null,
showInternal: false,
showInternational: false,
showTransfers: true,
});
render(<FlightsMapStartPage />);
act(() => {
(lastMapCanvasProps!["onMarkerClick"] as (id: string) => void)("MOW");
});
const filterValue = lastMapFilterProps!["value"] as Record<string, unknown>;
expect(filterValue["departure"]).toBe("MOW");
expect(filterValue["arrival"]).toBeUndefined();
expect(filterValue["connections"]).toBe(false);
const polylines = lastMapCanvasProps!["polylines"] as Array<{ cityIds: string[] }>;
expect(polylines).toHaveLength(1);
expect(polylines[0]!.cityIds).toEqual(["MOW", "LED"]);
});
it("4.1.24-R37: buy-ticket popup appears after second click (arrival set)", () => {
render(<FlightsMapStartPage />);
act(() => {
@@ -146,6 +146,19 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
filterState.connections ? 1 : 0,
);
const persistFilterState = useCallback((newState: IFlightsMapFilterState) => {
setFilterState(newState);
// TZ §4.1.8 / 4.1.1-R26: persist map filter independently from Board/Schedule.
setMapFilter({
departure: newState.departure ?? null,
arrival: newState.arrival ?? null,
date: newState.date ?? null,
showInternal: newState.domestic,
showInternational: newState.international,
showTransfers: newState.connections,
});
}, []);
// Sync user toggle → effective.
useEffect(() => {
setEffectiveConnections(filterState.connections ? 1 : 0);
@@ -160,7 +173,7 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
arrival: filterState.arrival,
dateFrom: todayYmd,
dateTo: addMonthsYyyymmdd(todayYmd, 6),
connections: effectiveConnections,
connections: filterState.arrival ? effectiveConnections : 0,
};
}, [filterState.departure, filterState.arrival, effectiveConnections, todayYmd]);
@@ -172,7 +185,7 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
date: todayYmd,
departure: filterState.departure,
arrival: filterState.arrival,
connections: filterState.connections,
connections: filterState.arrival ? filterState.connections : false,
};
}, [filterState.departure, filterState.arrival, filterState.connections, todayYmd]);
@@ -197,39 +210,33 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
// Reflect fallback in the UI toggle once.
useEffect(() => {
if (effectiveConnections === 1 && !filterState.connections) {
if (filterState.arrival && effectiveConnections === 1 && !filterState.connections) {
setFilterState((prev) => ({ ...prev, connections: true }));
}
}, [effectiveConnections, filterState.connections]);
}, [effectiveConnections, filterState.arrival, filterState.connections]);
const handleFilterChange = useCallback((newState: IFlightsMapFilterState) => {
setFilterState(newState);
// TZ §4.1.8 / 4.1.1-R26: persist map filter independently from Board/Schedule.
setMapFilter({
departure: newState.departure ?? null,
arrival: newState.arrival ?? null,
date: newState.date ?? null,
showInternal: newState.domestic,
showInternational: newState.international,
showTransfers: newState.connections,
});
}, []);
persistFilterState(newState);
}, [persistFilterState]);
const handleMarkerClick = useCallback(
(markerId: string) => {
if (!filterState.departure) {
setFilterState((prev): IFlightsMapFilterState => ({ ...prev, departure: markerId }));
persistFilterState({ ...filterState, departure: markerId });
} else if (!filterState.arrival && markerId !== filterState.departure) {
setFilterState((prev): IFlightsMapFilterState => ({ ...prev, arrival: markerId }));
persistFilterState({ ...filterState, arrival: markerId });
} else {
setFilterState((prev): IFlightsMapFilterState => ({
...prev,
persistFilterState({
...filterState,
departure: markerId,
arrival: undefined,
}));
// Angular fetchAndDrawSpider forces connections=false before drawing.
// Keep the disabled UI state and spider-mode route rendering aligned.
connections: false,
});
}
},
[filterState.departure, filterState.arrival],
[filterState, persistFilterState],
);
const markers = useMemo<IMapMarker[]>(() => {
@@ -50,6 +50,7 @@ export function useFlightsMapSearch(
let cancelled = false;
setLoading(true);
setError(null);
setRoutes([]);
searchDestinations(client, paramsRef.current)
.then((response: IDestinationsResponse) => {