From b26777177219bf129b062a3f4027489a4f20de4d Mon Sep 17 00:00:00 2001 From: Maurice Date: Tue, 18 Aug 2026 17:27:38 +0200 Subject: [PATCH] fix(mobile): let the map show one day again Collapsing a day card has hidden that day's places from the map since #216, and it was the only way to reduce a busy map to one day. The phone shell does not render DayPlanSidebar, so when it replaced the desktop page on phones that control disappeared with it: expandedDayIds stayed null and every day's pins sat on top of each other with nothing to do about it (#1962). A day chip in map view now drives the same declutter the desktop chevron drives, rather than introducing a second filter. Entering the map focuses the selected day, tapping another chip moves the focus with it, and leaving the map clears it so the timeline is never looking at a filtered state. Unplanned places stay visible, exactly as the collapse path has always left them. --- client/src/mobile/screens/trip/MTripShell.tsx | 22 ++++++++++++-- .../unit/mobile/trip/MTripShell.test.tsx | 30 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/client/src/mobile/screens/trip/MTripShell.tsx b/client/src/mobile/screens/trip/MTripShell.tsx index b0931ed7c..624b1e715 100644 --- a/client/src/mobile/screens/trip/MTripShell.tsx +++ b/client/src/mobile/screens/trip/MTripShell.tsx @@ -225,6 +225,15 @@ export default function MTripShell({ if (trTab !== 'plan') planner.handleTabChange('plan') } + // Map focus on the selected day. Drives the same declutter the desktop sidebar's + // collapse chevron drives (#216) rather than adding a second filter — the phone + // lost that affordance when this shell replaced DayPlanSidebar, so a day's pins + // could not be told apart from the rest of the trip at all (#1962). Unplanned + // places stay visible either way, which is what the collapse path has always done. + const focusMapOnDay = (dayId: number | null) => { + planner.setExpandedDayIds(dayId == null ? null : new Set([dayId])) + } + const toggleView = () => { const next = view === 'plan' ? 'map' : 'plan' setView(next) @@ -234,6 +243,11 @@ export default function MTripShell({ if (next === 'map') { planner.setRouteShown(true) if (planner.selectedDayId != null) planner.handleSelectDay(planner.selectedDayId, false) + focusMapOnDay(planner.selectedDayId) + } else { + // Leaving the map: nothing is filtered while the timeline is up, so the next + // visit starts from the whole trip unless a day is picked again. + focusMapOnDay(null) } } @@ -267,8 +281,12 @@ export default function MTripShell({ if (dayId === planner.selectedDayId) openSheet('day', { dayId }) else { planner.handleSelectDay(dayId, view !== 'map') - // In map mode a day tap fits to that day's places AND draws its route. - if (view === 'map') planner.setRouteShown(true) + // In map mode a day tap fits to that day's places, draws its route and drops + // the other days' pins, so the day it framed is the day it shows. + if (view === 'map') { + planner.setRouteShown(true) + focusMapOnDay(dayId) + } } } diff --git a/client/tests/unit/mobile/trip/MTripShell.test.tsx b/client/tests/unit/mobile/trip/MTripShell.test.tsx index 5d731594e..271987acd 100644 --- a/client/tests/unit/mobile/trip/MTripShell.test.tsx +++ b/client/tests/unit/mobile/trip/MTripShell.test.tsx @@ -257,6 +257,36 @@ describe('MTripShell', () => { expect(planner.setRouteShown).toHaveBeenCalledWith(true) }) + // #1962 — the phone lost the desktop sidebar's collapse chevron, so the map showed + // every day's pins at once with no way to narrow it down. + it('FE-MOB-SHELL-040: entering the map focuses it on the selected day', () => { + const { planner } = renderShell() + fireEvent.click(screen.getByRole('button', { name: 'mobileTrip.mapView' })) + expect(planner.setExpandedDayIds).toHaveBeenCalledWith(new Set([11])) + }) + + it('FE-MOB-SHELL-041: a day tap in map mode moves the focus with it', () => { + const { planner } = renderShell() + fireEvent.click(screen.getByRole('button', { name: 'mobileTrip.mapView' })) + vi.mocked(planner.setExpandedDayIds).mockClear() + fireEvent.click(screen.getByRole('button', { name: 'Sun 3' })) + expect(planner.setExpandedDayIds).toHaveBeenCalledWith(new Set([12])) + }) + + it('FE-MOB-SHELL-042: a day tap in list mode leaves the map unfiltered', () => { + const { planner } = renderShell() + fireEvent.click(screen.getByRole('button', { name: 'Sun 3' })) + expect(planner.setExpandedDayIds).not.toHaveBeenCalled() + }) + + it('FE-MOB-SHELL-043: leaving the map clears the focus again', () => { + const { planner } = renderShell() + fireEvent.click(screen.getByRole('button', { name: 'mobileTrip.mapView' })) + vi.mocked(planner.setExpandedDayIds).mockClear() + fireEvent.click(screen.getByRole('button', { name: 'mobileTrip.listView' })) + expect(planner.setExpandedDayIds).toHaveBeenCalledWith(null) + }) + it('FE-MOB-SHELL-023: the dock only shows enabled tabs and marks the active one', () => { const { planner } = renderShell({ TRIP_TABS: [