From d07aa80093b0c69e3ab4213b2b9b09e7262fc1e7 Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 17 Sep 2026 13:31:43 +0200 Subject: [PATCH] fix(roadtrip): the stage map shows its own night pause, and only that one The moon pill marking where a travel day ends is back on the phone, filtered to the day on screen. The markers are built from the whole drive, which is right for the desktop rail and for the all-days view, but a stage draws one day: unfiltered, day 1 carried day 2's pill as well, sitting in the middle of a map that is otherwise entirely day 1. Two ends on a map that draws one is a question rather than a label. Off a stage the list is left alone, because in the all-days view every night does belong to a line that is drawn. The plan tab is unaffected either way: its vias come from the route calculation, which has no night pauses in it. This is what the map lost when the pills were dropped altogether: on a day whose drive ends somewhere other than its last stop, the pill is the only thing that says where. --- .../src/mobile/screens/trip/map/MMapArea.tsx | 29 ++++++++++--------- .../tests/unit/mobile/trip/MMapArea.test.tsx | 25 ++++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/client/src/mobile/screens/trip/map/MMapArea.tsx b/client/src/mobile/screens/trip/map/MMapArea.tsx index c3e6d4e9e..b3d5abea1 100644 --- a/client/src/mobile/screens/trip/map/MMapArea.tsx +++ b/client/src/mobile/screens/trip/map/MMapArea.tsx @@ -282,22 +282,25 @@ export default function MMapArea({ planner, shell }: MMapAreaProps) { * sets overlap: the same petrol station found twice would be two pins on one roof. */ /** - * The vias the phone map draws, minus the night pauses. + * The vias the phone map draws: on a stage, only the night that belongs to it. * - * A night pause is a pill with a moon and a day number, drawn beside the boundary where - * one travel day ends. On the desktop it is a handle: it carries a hint and can be - * dragged to move the boundary. A phone has no hover to explain it and no room to drag - * it, so all it does there is sit on the map, and it sits there for EVERY day at once — - * the markers come from the whole drive (`automaticPoints`), not from the stage on - * screen, so day 1 shows day 2's pill as well. Two labels the day filter does not reach - * read as part of the map rather than as a control. + * A night pause is a pill with a moon and a day number, drawn where one travel day + * ends. The markers are built from the WHOLE drive (`automaticPoints`), which is right + * for the desktop rail and for the all-days view here, but a stage shows one day: with + * the unfiltered list, day 1 carried day 2's pill as well, in the middle of a map that + * is otherwise entirely day 1. Two ends on a map that draws one is a question, not a + * label. * - * Both lists go through the same filter: the plan tab's vias carry night pauses too. + * So on a stage the pill is kept only where its day is the day on screen, and off a + * stage the list is left alone, because in the all-days view every night does belong to + * a line that is drawn. `nightPause.day` is the day number the marker was built from + * (see `useAutomaticDayPoints`), which is the same number the stage carries. */ - const mapVias = useMemo( - () => (onStage ? planner.roadtripMapVias : planner.routeVias)?.filter(v => !v.nightPause), - [onStage, planner.roadtripMapVias, planner.routeVias], - ) + const mapVias = useMemo(() => { + const vias = onStage ? planner.roadtripMapVias : planner.routeVias + if (!vias || !stage) return vias + return vias.filter(v => !v.nightPause || v.nightPause.day === stage.dayNumber) + }, [onStage, planner.roadtripMapVias, planner.routeVias, stage]) const pois = useMergedMapPois( onStage ? planner.roadtripCorridor.visible : null, diff --git a/client/tests/unit/mobile/trip/MMapArea.test.tsx b/client/tests/unit/mobile/trip/MMapArea.test.tsx index 7abe5b0d2..4b57af9b8 100644 --- a/client/tests/unit/mobile/trip/MMapArea.test.tsx +++ b/client/tests/unit/mobile/trip/MMapArea.test.tsx @@ -538,26 +538,27 @@ describe('MMapArea', () => { expect(mocks.props.focusPoints).toBe(shown) }) - it('FE-MOB-MAPAREA-036: the phone map draws no night pause, on either tab', () => { - // A night pause is the moon pill beside a day boundary. On the desktop it is a drag - // handle with a hint; a phone has neither hover nor room to drag, and the markers come - // from the whole drive rather than the stage, so day 1 showed day 2's pill too. - const nightPause = { day: 2, atPlace: false } - const vias = [ - { lat: 53.55, lng: 9.99, tone: 'default' as const, nightPause }, - { lat: 53.87, lng: 10.69, tone: 'default' as const, label: 'Rest stop' }, - ] + it('FE-MOB-MAPAREA-036: a stage keeps its own night pause and drops the other days', () => { + // A night pause is the moon pill where a travel day ends. The markers are built from + // the whole drive, so day 1 used to carry day 2's pill as well, in the middle of a map + // that draws day 1 only. `stagePlanner(3)` is day 1 of the drive (stageDay). + const own = { lat: 53.87, lng: 10.69, tone: 'default' as const, nightPause: { day: 1, atPlace: false } } + const other = { lat: 53.55, lng: 9.99, tone: 'default' as const, nightPause: { day: 2, atPlace: false } } + const plain = { lat: 53.6, lng: 10.2, tone: 'default' as const, label: 'Rest stop' } + const vias = [own, other, plain] const stage = renderArea( { trTab: 'roadtrip', mapFront: true }, { ...stagePlanner(3), roadtripMapVias: vias } as unknown as Partial, ) - expect(mocks.props.routeVias).toEqual([vias[1]]) + // Its own night and everything that is not one; day 2's pill stays off this map. + expect(mocks.props.routeVias).toEqual([own, plain]) stage.unmount() - // The plan tab's own vias carry night pauses too, so they go through the same filter. + // Off a stage the list is left alone: in the all-days view every night belongs to a + // line that is actually drawn. renderArea({ trTab: 'plan' }, { routeVias: vias }) - expect(mocks.props.routeVias).toEqual([vias[1]]) + expect(mocks.props.routeVias).toBe(vias) }) it('FE-MOB-MAPAREA-026: the map layer carries no credit corner on either tab', () => {