fix(planner): default a new accommodation to checking out the next day

The hotel picker pre-filled "Apply to days" with the same day for check-in
and check-out — a stay that ends the day it begins. New accommodations now
default to the following day for check-out; the last trip day keeps the
same-day range, and editing still seeds from the stored range.
This commit is contained in:
Maurice
2026-07-13 16:17:34 +02:00
parent cfebf57505
commit 61a49f1ea6
2 changed files with 32 additions and 2 deletions
@@ -564,6 +564,30 @@ describe('DayDetailPanel', () => {
});
});
it('FE-PLANNER-DAYDETAIL-067: hotel picker defaults check-out to the day AFTER check-in', async () => {
const day2 = buildDay({ id: 2, trip_id: 1, date: '2025-06-16', title: 'Day 2' });
const day3 = buildDay({ id: 3, trip_id: 1, date: '2025-06-17', title: 'Day 3' });
render(<DayDetailPanel {...defaultProps} days={[day, day2, day3]} />);
await userEvent.click(await screen.findByText(/Add accommodation/i));
await waitFor(() => {
const portal = document.body.querySelector('[style*="z-index: 99999"]');
// Closed selects render only their chosen label: check-in on the opened
// day, check-out on the following one — nobody stays a few hours.
expect(portal?.textContent).toContain('Day in Paris');
expect(portal?.textContent).toContain('Day 2');
expect(portal?.textContent).not.toContain('Day 3');
});
});
it('FE-PLANNER-DAYDETAIL-068: hotel picker falls back to a same-day range on the last trip day', async () => {
render(<DayDetailPanel {...defaultProps} days={[day]} />);
await userEvent.click(await screen.findByText(/Add accommodation/i));
await waitFor(() => {
const portal = document.body.querySelector('[style*="z-index: 99999"]');
expect(portal?.textContent?.match(/Day in Paris/g)).toHaveLength(2);
});
});
it('FE-PLANNER-DAYDETAIL-034: accommodation with all fields shows full details grid', async () => {
server.use(
http.get('/api/trips/1/accommodations', () =>
@@ -11,7 +11,13 @@ export function useDayDetail(day: any, days: any, tripId: any, lat: any, lng: an
const [dayAccommodations, setDayAccommodations] = useState<any[]>([])
const [accommodations, setAccommodations] = useState([])
const [showHotelPicker, setShowHotelPicker] = useState(false)
const [hotelDayRange, setHotelDayRange] = useState({ start: day?.id, end: day?.id })
// A stay virtually never checks out the day it checks in — default the range
// to check-out on the next day, unless the trip ends here.
const defaultHotelDayRange = (d: any) => {
const idx = (days || []).findIndex((x: any) => x.id === d?.id)
return { start: d?.id, end: (idx >= 0 && days[idx + 1]?.id) || d?.id }
}
const [hotelDayRange, setHotelDayRange] = useState(() => defaultHotelDayRange(day))
const [hotelCategoryFilter, setHotelCategoryFilter] = useState('')
const [hotelForm, setHotelForm] = useState({ check_in: '', check_in_end: '', check_out: '', confirmation: '', place_id: null })
@@ -38,7 +44,7 @@ export function useDayDetail(day: any, days: any, tripId: any, lat: any, lng: an
.catch(() => {})
}, [tripId, day?.id])
useEffect(() => { if (day) setHotelDayRange({ start: day.id, end: day.id }) }, [day?.id])
useEffect(() => { if (day) setHotelDayRange(defaultHotelDayRange(day)) }, [day?.id])
const handleSelectPlace = (placeId) => {
setHotelForm(f => ({ ...f, place_id: placeId }))