mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 14:36:31 +00:00
fix(planner): a booked hotel stays in the place list when road trip stops are hidden in Days
Since 4.3.0 every lodging booking types its place as 'hotel', and 'hotel' is one of the road trip stop types. With "Show in Days too" switched off, Days dropped every such place from the trip's place list, so a hotel vanished from the sidebar, from the booking's own place picker and from the Days map the moment it was booked, and a click on it in the day list found nothing. Nothing was deleted: road trip mode kept showing it. Days now leaves out only road trip stops nobody booked. A lodging place stays, and so does any place a stay or a booking points at, on the desktop and on the phone. Trips planned on 4.3.1 show their hotels again without any change to their data. An imported GPX or KML track is no longer offered as the place of a stay, in the booking form, the day's hotel picker and the phone's sheets. A stay that already names a track keeps showing it.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// FE-PLANNER-DAYDETAIL-001 to FE-PLANNER-DAYDETAIL-084
|
||||
// FE-PLANNER-DAYDETAIL-001 to FE-PLANNER-DAYDETAIL-085
|
||||
import React from 'react';
|
||||
import { fireEvent, render, screen, waitFor, within, act } from '../../../tests/helpers/render';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
@@ -520,6 +520,15 @@ describe('DayDetailPanel', () => {
|
||||
expect(await screen.findByText('102 Quai de Jemmapes')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-DAYDETAIL-085: the hotel picker leaves out imported tracks', async () => {
|
||||
const hotel = buildPlace({ id: 10, name: 'Hotel du Nord' });
|
||||
const track = buildPlace({ id: 12, name: 'Canal Saint-Martin walk', route_geometry: '[[48.87,2.36],[48.88,2.37]]' });
|
||||
render(<DayDetailPanel {...defaultProps} places={[hotel, track]} />);
|
||||
await userEvent.click(await screen.findByText(/Add accommodation/i));
|
||||
await screen.findByText('Hotel du Nord');
|
||||
expect(screen.queryByText('Canal Saint-Martin walk')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-DAYDETAIL-030: selecting a place in hotel picker enables save button', async () => {
|
||||
const place = buildPlace({ id: 10, name: 'Maison Blanche' });
|
||||
server.use(
|
||||
|
||||
@@ -21,6 +21,7 @@ import type { Day, Place, Category, Reservation, AssignmentsMap } from '../../ty
|
||||
import { isDayInAccommodationRange } from '../../utils/dayOrder'
|
||||
import { formatClockTime, splitReservationDateTime } from '../../utils/formatters'
|
||||
import { useDayDetail } from './useDayDetail'
|
||||
import { stayPlaces } from '../../utils/stayPlaces'
|
||||
|
||||
const WEATHER_ICON_MAP = {
|
||||
Clear: Sun, Clouds: Cloud, Rain: CloudRain, Drizzle: CloudDrizzle,
|
||||
@@ -660,7 +661,8 @@ function HotelPickerModal({ showHotelPicker, setShowHotelPicker, font, t, hotelD
|
||||
{/* Place List */}
|
||||
<div style={{ maxHeight: 250, overflowY: 'auto' }}>
|
||||
{(() => {
|
||||
const filtered = hotelCategoryFilter ? places.filter(p => p.category_id === hotelCategoryFilter) : places
|
||||
const offered = stayPlaces<Place>(places, hotelForm.place_id)
|
||||
const filtered = hotelCategoryFilter ? offered.filter(p => p.category_id === hotelCategoryFilter) : offered
|
||||
return filtered.length === 0 ? (
|
||||
<div style={{ padding: 20, textAlign: 'center', fontSize: 'calc(12px * var(--fs-scale-body, 1))', color: 'var(--text-faint)' }}>{t('day.noPlacesForHotel')}</div>
|
||||
) : filtered.map(p => (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// FE-PLANNER-RESMODAL-001 to FE-PLANNER-RESMODAL-100
|
||||
// FE-PLANNER-RESMODAL-001 to FE-PLANNER-RESMODAL-102
|
||||
import { render, screen, waitFor, fireEvent, within, act } from '../../../tests/helpers/render';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
@@ -627,6 +627,29 @@ describe('ReservationModal', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('FE-PLANNER-RESMODAL-101: an imported track is not offered as the place of a stay', async () => {
|
||||
const hotel = buildPlace({ id: 21, name: 'Hotel Adler' });
|
||||
const track = buildPlace({ id: 22, name: 'Rheinsteig', route_geometry: '[[50.1,7.6],[50.2,7.7]]' });
|
||||
render(<ReservationModal {...defaultProps} places={[hotel, track]} />);
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /Accommodation/i }));
|
||||
const field = screen.getAllByText('Accommodation').find(el => el.tagName === 'LABEL')!.parentElement!;
|
||||
await userEvent.click(within(field).getByRole('button'));
|
||||
|
||||
expect(screen.getByText('Hotel Adler')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Rheinsteig')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-RESMODAL-102: a stay already booked at a track still shows that track', () => {
|
||||
const track = buildPlace({ id: 22, name: 'Rheinsteig', route_geometry: '[[50.1,7.6],[50.2,7.7]]' });
|
||||
const days = [buildDay({ id: 1 }), buildDay({ id: 2 })];
|
||||
const accommodations = [{ id: 7, trip_id: 1, place_id: 22, start_day_id: 1, end_day_id: 2 }];
|
||||
const res = buildReservation({ id: 9, type: 'hotel', title: 'Hut', accommodation_id: 7 });
|
||||
render(<ReservationModal {...defaultProps} days={days} places={[track]} accommodations={accommodations as never} reservation={res} />);
|
||||
|
||||
expect(screen.getByText('Rheinsteig')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-RESMODAL-043: hover styles applied to file picker items', async () => {
|
||||
const res = buildReservation({ id: 5 });
|
||||
const unattachedFile = buildTripFile({ id: 99, original_name: 'invoice.pdf' });
|
||||
|
||||
@@ -24,6 +24,7 @@ import type { TripMember } from '../Budget/BudgetPanelMemberChips'
|
||||
import type { BookingExpenseRequest } from './BookingCostsSection.types'
|
||||
import type { BookingReviewDraft } from './parsedItemToDraft'
|
||||
import { typeToCostCategory } from '@trek/shared'
|
||||
import { stayPlaces } from '../../utils/stayPlaces'
|
||||
|
||||
const TYPE_OPTIONS = [
|
||||
{ value: 'hotel', labelKey: 'reservations.type.hotel', Icon: Hotel },
|
||||
@@ -601,7 +602,7 @@ export function ReservationModal({ isOpen, onClose, onSave, reservation, days, p
|
||||
placeholder={t('reservations.meta.pickHotel')}
|
||||
options={[
|
||||
{ value: '', label: '—' },
|
||||
...places.map(p => ({ value: p.id, label: p.name })),
|
||||
...stayPlaces(places, form.hotel_place_id).map(p => ({ value: p.id, label: p.name })),
|
||||
]}
|
||||
searchable
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user