fix(map): keep the overview frame when the trip is edited

This commit is contained in:
pipipiper
2026-09-28 11:24:02 +08:00
committed by Maurice
parent 7d22857de8
commit 71a8b24f8d
2 changed files with 77 additions and 11 deletions
@@ -32,9 +32,9 @@ const ASSIGNMENTS: AssignmentsMap = {
const render = (enabled = true, assignments: AssignmentsMap = ASSIGNMENTS, days = DAYS) =>
renderHook(
({ assignments: a }: { assignments: AssignmentsMap }) =>
useTripRouteOverview(7, days, a, [], [], 'driving', enabled),
{ initialProps: { assignments } },
({ enabled: on, assignments: a }: { enabled: boolean; assignments: AssignmentsMap }) =>
useTripRouteOverview(7, days, a, [], [], 'driving', on),
{ initialProps: { enabled, assignments } },
)
beforeEach(() => {
@@ -129,6 +129,7 @@ describe('useTripRouteOverview', () => {
// A new object identity with the same geometry: the plan memo re-runs, the
// routing round must not.
rerender({
enabled: true,
assignments: {
...ASSIGNMENTS,
'1': ASSIGNMENTS['1'].map(a => ({ ...a, place: { ...a.place, name: 'Renamed' } })),
@@ -183,7 +184,8 @@ describe('useTripRouteOverview', () => {
it('FE-MAP-TRO-011: keeps the frame it set on the straight lines until the round is over', async () => {
// A fresh `focusPoints` array is what tells the map to fit the camera. One per
// answering leg would take the map back from wherever the reader has panned to, so
// the frame changes exactly twice: on the straight lines, and on the finished roads.
// within a round the frame changes exactly once — on the straight lines — and the
// finished roads are framed only on an activation round (see TRO-012/013).
const answer: RouteAnswer = {
coordinates: [[48.86, 2.35], [48.87, 2.355], [48.88, 2.36]],
distance: 12000, duration: 900,
@@ -206,8 +208,51 @@ describe('useTripRouteOverview', () => {
await act(async () => { answers[1](answer) })
await waitFor(() => expect(result.current.loading).toBe(false))
// The finished result frames the roads themselves, which have more points than the
// straight lines had.
// straight lines had — the second of the two fits an activation makes.
expect(result.current.focusPoints).not.toBe(frame)
expect(result.current.focusPoints.length).toBeGreaterThan(frame.length)
})
it('FE-MAP-TRO-012: editing the trip does not reframe the map', async () => {
// Dropping a place onto a day re-plans the route. Publishing a fresh frame for
// that recompute yanked the camera mid-edit — the map zoomed out to the whole
// trip every time a place was dragged onto the plan.
const { result, rerender } = render()
await waitFor(() => expect(result.current.loading).toBe(false))
const frame = result.current.focusPoints
const totalBefore = result.current.totalDistance
rerender({
enabled: true,
assignments: {
...ASSIGNMENTS,
// The walking override on the middle stop makes the new leg a routing
// request of its own: neighbouring legs in one mode travel as a single
// chunk, which a third driving stop would have joined instead.
'2': [
ASSIGNMENTS['2'][0],
{ ...ASSIGNMENTS['2'][1], leg_transport_mode: 'walking' },
at(45.8, 4.9, 2, 2),
],
},
})
await waitFor(() => expect(result.current.loading).toBe(false))
// The recompute really happened — a third stop means a second leg on day 2.
expect(result.current.totalDistance).toBe(totalBefore + 12000)
// …and the camera frame is the one the activation published, unchanged.
expect(result.current.focusPoints).toBe(frame)
})
it('FE-MAP-TRO-013: switching the overview back on publishes a fresh frame', async () => {
const { result, rerender } = render()
await waitFor(() => expect(result.current.loading).toBe(false))
const frame = result.current.focusPoints
rerender({ enabled: false, assignments: ASSIGNMENTS })
rerender({ enabled: true, assignments: ASSIGNMENTS })
await waitFor(() => expect(result.current.loading).toBe(false))
expect(result.current.focusPoints).not.toBe(frame)
})
})