From 00738c8dbcc5436b343d0eb036eaf60413888dd8 Mon Sep 17 00:00:00 2001 From: Maurice Date: Wed, 17 Jun 2026 22:27:54 +0200 Subject: [PATCH] fix(planner): keep a reservation on its day when edited (#1237) Editing a booking forced its day_id to the globally selected day, which is null when editing from the Book tab - so the booking lost its day and vanished from the Plan. Preserve the reservation own day_id on edit instead. --- client/src/pages/TripPlannerPage.test.tsx | 19 ++++++++++++++----- .../src/pages/tripPlanner/useTripPlanner.ts | 5 ++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/client/src/pages/TripPlannerPage.test.tsx b/client/src/pages/TripPlannerPage.test.tsx index 9512c3ec..8f314c70 100644 --- a/client/src/pages/TripPlannerPage.test.tsx +++ b/client/src/pages/TripPlannerPage.test.tsx @@ -1160,10 +1160,13 @@ describe('TripPlannerPage', () => { }); describe('FE-PAGE-PLANNER-041: handleSaveReservation edit path covers update reservation', () => { - it('calls onEdit then onSave on ReservationModal to exercise the edit-reservation handler', async () => { + it('preserves the reservation day_id on edit so it stays in the Plan (#1237)', async () => { vi.useFakeTimers(); seedTripStore({ id: 42 }); + // Capture the update payload — tripActions is a snapshot of the store at mount. + const updateReservationSpy = vi.fn().mockResolvedValue({ id: 1, day_id: 7 }); + seedStore(useTripStore, { updateReservation: updateReservationSpy } as any); renderPlannerPage(42); @@ -1179,20 +1182,26 @@ describe('TripPlannerPage', () => { expect(screen.getByTestId('reservations-panel')).toBeInTheDocument(); }); - // Set editingReservation via captured onEdit prop (inline lambda in JSX) - const fakeReservation = { id: 1, trip_id: 42, name: 'Test', type: 'restaurant', status: 'confirmed' }; + // Edit a reservation that lives on day 7 (no day is selected — Book tab). + const fakeReservation = { id: 1, trip_id: 42, name: 'Test', type: 'other', status: 'confirmed', day_id: 7 }; await act(async () => { capturedReservationsPanelProps.current.onEdit?.(fakeReservation); }); - // Call onSave — now takes edit path (editingReservation is set) await act(async () => { await capturedReservationModalProps.current.onSave?.({ name: 'Updated Booking', - type: 'restaurant', + type: 'tour', status: 'confirmed', }); }); + + // The booking must keep its own day_id (not be nulled to the selected day). + expect(updateReservationSpy).toHaveBeenCalledWith( + expect.anything(), + 1, + expect.objectContaining({ day_id: 7 }), + ); }); }); diff --git a/client/src/pages/tripPlanner/useTripPlanner.ts b/client/src/pages/tripPlanner/useTripPlanner.ts index 03d6d094..aef9c6a6 100644 --- a/client/src/pages/tripPlanner/useTripPlanner.ts +++ b/client/src/pages/tripPlanner/useTripPlanner.ts @@ -568,7 +568,10 @@ export function useTripPlanner() { const handleSaveReservation = async (data: Record & { title: string }) => { try { if (editingReservation) { - const r = await tripActions.updateReservation(tripId, editingReservation.id, { ...data, day_id: selectedDayId || null }) + // Keep the reservation on its own day. Forcing selectedDayId here dropped + // the booking out of the Plan when edited from the Book tab (no day + // selected -> selectedDayId null -> day_id nulled). + const r = await tripActions.updateReservation(tripId, editingReservation.id, { ...data, day_id: editingReservation.day_id ?? null }) toast.success(t('trip.toast.reservationUpdated')) setShowReservationModal(false) setEditingReservation(null)