fix(planner): keep a restored route toggle scoped to the selected day (#2019)

This commit is contained in:
Maurice
2026-09-01 14:42:03 +02:00
committed by Maurice
parent c59425947a
commit 0a3ba7a4d7
5 changed files with 42 additions and 6 deletions
@@ -46,7 +46,7 @@ export default function MMapArea({ planner, shell }: MMapAreaProps) {
dayPlaces={planner.dayPlaces}
route={planner.route}
routeVias={planner.routeVias}
showTransitRoutes={planner.routeShown}
showTransitRoutes={planner.transitRoutesShown}
// The route toggle belongs to one day, so the map needs that day to know
// which automated transports may ride it (#2019).
days={planner.days}
+2 -2
View File
@@ -259,7 +259,7 @@ function TripPlannerPageDesktop(): React.ReactElement | null {
transportModalDayId, setTransportModalDayId,
transportModalAutomated, setTransportModalAutomated, transitPrefill, setTransitPrefill, transitJourney, setTransitJourney,
reservationPrefill, transportPrefill, importReviewActive, advanceImportReview,
routeShown, setRouteShown, routeProfile, setRouteProfile, routeVias, fitKey, setFitKey,
routeShown, setRouteShown, transitRoutesShown, routeProfile, setRouteProfile, routeVias, fitKey, setFitKey,
mobileSidebarOpen, setMobileSidebarOpen, mobilePlanScrollTopRef, mobilePlacesScrollTopRef,
deletePlaceId, setDeletePlaceId, deletePlaceIds, setDeletePlaceIds,
visibleConnections, toggleConnection, allConnectionsShown, toggleAllConnections, mapTransportDetail, setMapTransportDetail,
@@ -365,7 +365,7 @@ function TripPlannerPageDesktop(): React.ReactElement | null {
dayPlaces={dayPlaces}
route={route}
routeVias={routeVias}
showTransitRoutes={routeShown}
showTransitRoutes={transitRoutesShown}
// The route toggle belongs to one day, so the map needs that day to
// know which automated transports may ride it (#2019).
days={days}
@@ -219,6 +219,7 @@ function baseState(): HookState {
advanceImportReview: vi.fn(),
routeShown: false,
setRouteShown: vi.fn(),
transitRoutesShown: false,
routeProfile: 'driving',
setRouteProfile: vi.fn(),
routeVias: [],
@@ -354,7 +355,7 @@ describe('TripPlannerPage — shell', () => {
describe('TripPlannerPage — plan tab', () => {
it('FE-PAGE-TPW-008: the map receives the filtered markers, the tile url, the panel widths and the selected day', () => {
renderPage()
renderPage({ transitRoutesShown: true })
expect(props('map').places).toEqual([place])
expect(props('map').tileUrl).toBe('https://tiles/{z}/{x}/{y}.png')
@@ -364,6 +365,9 @@ describe('TripPlannerPage — plan tab', () => {
// transport in the trip as soon as any day's route is on (#2019).
expect(props('map').days).toEqual([day])
expect(props('map').selectedDayId).toBe(7)
// Transit visibility rides the hook's day-aware derivation, not the raw
// toggle — routeShown is still false in this fixture (#2019).
expect(props('map').showTransitRoutes).toBe(true)
})
it('FE-PAGE-TPW-009: collapsed panels report a zero width to the map', () => {
@@ -1,4 +1,4 @@
// FE-TP-HOOK-001 to FE-TP-HOOK-110
// FE-TP-HOOK-001 to FE-TP-HOOK-115
import React from 'react'
import { renderHook, act, waitFor } from '@testing-library/react'
import { TranslationProvider } from '../../i18n/TranslationContext'
@@ -825,6 +825,32 @@ describe('useTripPlanner — connection visibility', () => {
expect(result.current.visibleConnections).toEqual([1])
})
it('FE-TP-HOOK-115: a persisted route toggle keeps transit routes off the map until a day is selected (#2019)', async () => {
localStorage.setItem('trek:day-route:42', 'true')
// The fixture action is a no-op; the derivation reads the store, so this
// one has to write the selection like the real slice does.
actions.setSelectedDay.mockImplementation(dayId => {
useTripStore.setState({ selectedDayId: dayId as number | null })
})
seedTrip()
const { result } = await renderPlanner()
// Trip re-entry: the toggle rehydrated but nothing selected a day yet.
expect(result.current.routeShown).toBe(true)
expect(result.current.transitRoutesShown).toBe(false)
act(() => { result.current.handleSelectDay(7) })
expect(result.current.transitRoutesShown).toBe(true)
// Clicking the selected day's header again deselects it — the whole trip's
// automated transports must not flood back.
act(() => { result.current.handleSelectDay(null) })
expect(result.current.transitRoutesShown).toBe(false)
localStorage.removeItem('trek:day-route:42')
})
})
describe('useTripPlanner — selection handlers', () => {
@@ -306,6 +306,12 @@ export function useTripPlanner() {
const autoShowRoute = useCallback(() => {
setRouteChoice(prev => (prev === null ? true : prev))
}, [])
// What the planner maps actually draw. The persisted toggle can rehydrate as
// true while no day is selected yet (trip re-entry resets the selection, and
// a second click on the day header clears it) — without a day context the
// per-day transit filter is off, so the map would draw every automated
// transport in the trip (#2019).
const transitRoutesShown = routeShown && selectedDayId != null
const [routeProfile, setRouteProfile] = useState<string>('driving')
const [fitKey, setFitKey] = useState<number>(0)
const initialFitTripId = useRef<number | null>(null)
@@ -1067,7 +1073,7 @@ export function useTripPlanner() {
transportModalDayId, setTransportModalDayId,
transportModalAutomated, setTransportModalAutomated, transitPrefill, setTransitPrefill, transitJourney, setTransitJourney,
reservationPrefill, transportPrefill, importReviewActive, startImportReview, advanceImportReview,
routeShown, setRouteShown, autoShowRoute, routeProfile, setRouteProfile, routeVias, fitKey, setFitKey,
routeShown, setRouteShown, autoShowRoute, transitRoutesShown, routeProfile, setRouteProfile, routeVias, fitKey, setFitKey,
mobileSidebarOpen, setMobileSidebarOpen, mobilePlanScrollTopRef, mobilePlacesScrollTopRef,
deletePlaceId, setDeletePlaceId, deletePlaceIds, setDeletePlaceIds,
visibleConnections, toggleConnection, allConnectionsShown, toggleAllConnections, mapTransportDetail, setMapTransportDetail,