feat(planner): scope the planned places filter to the selected day

With a day selected, the 'planned' filter now shows only that day's stops,
matching how the other filters follow the selection; with no day selected
it keeps showing the whole plan. 'unplanned' still uses the whole-trip
assigned set. Discussed in #2024.
This commit is contained in:
cartoone
2026-08-23 22:08:42 +02:00
committed by Maurice
parent fe5c6f182e
commit 1cb67d5e64
2 changed files with 31 additions and 3 deletions
@@ -680,6 +680,28 @@ describe('useTripPlanner — map derivations', () => {
expect(result.current.mapPlaces.map(p => p.id)).toEqual([1])
})
it('FE-TP-HOOK-111: the planned filter follows the selected day when one is selected', async () => {
const onDay7 = geo(1)
const onDay8 = geo(2)
seedTrip({
places: [onDay7, onDay8, geo(3)],
assignments: {
'7': [buildAssignment({ id: 10, day_id: 7, place: onDay7 })],
'8': [buildAssignment({ id: 11, day_id: 8, place: onDay8 })],
},
placesFilter: 'planned',
selectedDayId: 7,
})
const { result } = await renderPlanner()
expect(result.current.mapPlaces.map(p => p.id)).toEqual([1])
// No day selected → back to the whole plan
act(() => { useTripStore.setState({ selectedDayId: null }) })
expect(result.current.mapPlaces.map(p => p.id)).toEqual([1, 2])
})
it('FE-TP-HOOK-030: collapsing a day hides its stops unless another expanded day shows them', async () => {
const shared = geo(1)
seedTrip({
@@ -439,9 +439,15 @@ export function useTripPlanner() {
}
// Planned place IDs — needed by both the 'unplanned' filter (exclude them) and
// the new 'planned' filter (keep only them).
// the new 'planned' filter (keep only them). With a day selected, 'planned'
// follows it like the other filters do; with no day selected it keeps showing
// the whole plan (#2024). 'unplanned' always uses the whole-trip set — a place
// assigned to any day is not unplanned.
const plannedIds = placesFilter === 'unplanned' || placesFilter === 'planned'
? new Set(Object.values(assignments).flatMap(da => da.map(a => a.place?.id).filter(Boolean)))
? new Set((placesFilter === 'planned' && selectedDayId
? (assignments[String(selectedDayId)] || [])
: Object.values(assignments).flat()
).map(a => a.place?.id).filter(Boolean))
: null
return places.filter(p => {
@@ -460,7 +466,7 @@ export function useTripPlanner() {
if (placesFilter === 'planned' && plannedIds && !plannedIds.has(p.id)) return false
return true
})
}, [places, placesCategoryFilter, placesFilter, assignments, expandedDayIds])
}, [places, placesCategoryFilter, placesFilter, assignments, expandedDayIds, selectedDayId])
const { route, routeSegments, routeVias, routeInfo, setRoute, setRouteInfo, updateRouteForDay } = useRouteCalculation({ assignments } as any, selectedDayId, routeShown, routeProfile, tripAccommodations)