mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
feat(planner): reach a hotel's booking from the plan, not only its place
A booked stay's pill in the day head gets a second target that opens the booking; the name still opens the place. The place panel of a hotel, on the desktop and on the phone, lists the stay booked for it next to the bookings pinned to the stop. (#2363)
This commit is contained in:
@@ -4338,6 +4338,44 @@ describe('DayPlanSidebar', () => {
|
||||
expect(onPlaceClick).toHaveBeenCalledWith(8)
|
||||
})
|
||||
|
||||
it('FE-PLANNER-DAYPLAN-176b: a booked stay opens its booking from the pill, the name still opens the place (#2363)', async () => {
|
||||
const user = userEvent.setup()
|
||||
const days = [
|
||||
buildDay({ id: 10, date: '2025-06-01', title: 'Day 1' }),
|
||||
buildDay({ id: 11, date: '2025-06-02', title: 'Day 2' }),
|
||||
]
|
||||
const accommodations: Accommodation[] = [
|
||||
{ id: 3, trip_id: 1, start_day_id: 10, end_day_id: 11, place_id: 9, place_lat: 51.5, place_lng: -0.12, place_name: 'Booked Hotel' },
|
||||
{ id: 4, trip_id: 1, start_day_id: 10, end_day_id: 11, place_id: 8, place_lat: 51.5, place_lng: -0.12, place_name: 'Unbooked Hotel' },
|
||||
]
|
||||
const stay = buildReservation({ id: 610, type: 'hotel', title: 'Booked Hotel stay', accommodation_id: 3 } as any)
|
||||
const onPlaceClick = vi.fn()
|
||||
const onOpenBooking = vi.fn()
|
||||
render(<DayPlanSidebar {...makeDefaultProps({ days, accommodations, reservations: [stay], onPlaceClick, onOpenBooking })} />)
|
||||
|
||||
const header = dayHeader('Day 1')
|
||||
const bookingButtons = header.querySelectorAll('[data-dp="day-pill-booking"]')
|
||||
// Only the stay that has a booking gets the second target.
|
||||
expect(bookingButtons).toHaveLength(1)
|
||||
expect(bookingButtons[0]).toHaveAccessibleName('Open booking')
|
||||
await user.click(bookingButtons[0] as HTMLElement)
|
||||
expect(onOpenBooking).toHaveBeenCalledWith(stay)
|
||||
expect(onPlaceClick).not.toHaveBeenCalled()
|
||||
|
||||
await user.click(within(header).getByText('Booked Hotel'))
|
||||
expect(onPlaceClick).toHaveBeenCalledWith(9)
|
||||
})
|
||||
|
||||
it('FE-PLANNER-DAYPLAN-176c: without a booking detail to open, the stay pill has no booking button', () => {
|
||||
const days = [buildDay({ id: 10, date: '2025-06-01', title: 'Day 1' }), buildDay({ id: 11, date: '2025-06-02', title: 'Day 2' })]
|
||||
const accommodations: Accommodation[] = [
|
||||
{ id: 3, trip_id: 1, start_day_id: 10, end_day_id: 11, place_id: 9, place_lat: 51.5, place_lng: -0.12, place_name: 'Booked Hotel' },
|
||||
]
|
||||
const stay = buildReservation({ id: 610, type: 'hotel', title: 'Booked Hotel stay', accommodation_id: 3 } as any)
|
||||
render(<DayPlanSidebar {...makeDefaultProps({ days, accommodations, reservations: [stay] })} />)
|
||||
expect(dayHeader('Day 1').querySelector('[data-dp="day-pill-booking"]')).toBeNull()
|
||||
})
|
||||
|
||||
it('FE-PLANNER-DAYPLAN-177: clicking an active rental badge opens its booking detail', async () => {
|
||||
const user = userEvent.setup()
|
||||
const days = [
|
||||
|
||||
@@ -1898,16 +1898,32 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP
|
||||
const pending = pendingStays.has(acc.id)
|
||||
const named = state ? `${state}: ${accName}` : accName
|
||||
const tip = pending ? `${named} (${t('reservations.pending')})` : named
|
||||
// The name opens the place, as before; a stay with a booking gets a
|
||||
// second target in the same pill that opens the booking (#2363).
|
||||
const stayBooking = onOpenBooking
|
||||
? reservations.find(r => r.accommodation_id != null && Number(r.accommodation_id) === acc.id)
|
||||
: undefined
|
||||
return (
|
||||
<Tooltip key={acc.id} label={tip}>
|
||||
<button type="button" data-dp="day-pill" data-pending={pending || undefined}
|
||||
onClick={e => { e.stopPropagation(); if ((acc as any).place_id) onPlaceClick((acc as any).place_id) }}
|
||||
className={`inline-flex min-w-0 max-w-full items-center gap-1 rounded-full px-2 py-[2px] font-geist font-normal text-content-secondary hover:text-content ${pending ? 'border border-dashed border-warning bg-warning-soft' : 'bg-surface-card shadow-sm'}`}
|
||||
style={{ ...fs(10.5), cursor: (acc as any).place_id ? 'pointer' : 'default' }}>
|
||||
<Hotel size={11} strokeWidth={2} className={`flex-none ${iconTone}`} />
|
||||
<span className="truncate">{accName}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
<span key={acc.id} className={`inline-flex min-w-0 max-w-full items-stretch overflow-hidden rounded-full ${pending ? 'border border-dashed border-warning bg-warning-soft' : 'bg-surface-card shadow-sm'}`}>
|
||||
<Tooltip label={tip}>
|
||||
<button type="button" data-dp="day-pill" data-pending={pending || undefined}
|
||||
onClick={e => { e.stopPropagation(); if ((acc as any).place_id) onPlaceClick((acc as any).place_id) }}
|
||||
className={`inline-flex min-w-0 items-center gap-1 py-[2px] font-geist font-normal text-content-secondary hover:text-content ${stayBooking ? 'pl-2 pr-1.5' : 'px-2'}`}
|
||||
style={{ ...fs(10.5), cursor: (acc as any).place_id ? 'pointer' : 'default' }}>
|
||||
<Hotel size={11} strokeWidth={2} className={`flex-none ${iconTone}`} />
|
||||
<span className="truncate">{accName}</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{stayBooking && (
|
||||
<Tooltip label={t('day.openStayBooking')}>
|
||||
<button type="button" data-dp="day-pill-booking" aria-label={t('day.openStayBooking')}
|
||||
onClick={e => { e.stopPropagation(); onOpenBooking!(stayBooking) }}
|
||||
className="flex flex-none items-center border-l border-edge-faint pl-1.5 pr-2 text-content-faint hover:text-content">
|
||||
<Ticket size={11} strokeWidth={2} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
{/* Active rental car badges */}
|
||||
|
||||
@@ -430,6 +430,20 @@ describe('PlaceInspector', () => {
|
||||
expect(screen.getByText('Museum Ticket')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('FE-PLANNER-INSPECTOR-030h: a hotel shows the stay booked for it and opens that booking (#2363)', () => {
|
||||
const onOpenBooking = vi.fn();
|
||||
const stay = buildReservation({
|
||||
id: 540, title: 'Hotel Adlon, 3 nights', status: 'confirmed', type: 'hotel', assignment_id: null,
|
||||
accommodation_place_id: place.id,
|
||||
} as any);
|
||||
const elsewhere = buildReservation({ id: 541, title: 'Other hotel', type: 'hotel', accommodation_place_id: place.id + 1 } as any);
|
||||
render(<PlaceInspector {...defaultProps} reservations={[stay, elsewhere]} onOpenBooking={onOpenBooking} />);
|
||||
|
||||
expect(screen.queryByText('Other hotel')).toBeNull();
|
||||
fireEvent.click(screen.getByText('Hotel Adlon, 3 nights').closest('[role="button"]') as HTMLElement);
|
||||
expect(onOpenBooking).toHaveBeenCalledWith(stay);
|
||||
});
|
||||
|
||||
it('FE-PLANNER-INSPECTOR-030g: every booking on the stop gets its own strip (#2201)', () => {
|
||||
const onEditReservation = vi.fn();
|
||||
const parking = buildReservation({
|
||||
|
||||
@@ -34,7 +34,7 @@ import { useTripStore } from '../../store/tripStore'
|
||||
import { useCanDo } from '../../store/permissionsStore'
|
||||
import { formatDistance, formatElevation } from '../../utils/units'
|
||||
import { navigationTargetLabel, getNavigationTargets, openNavigationTarget } from './placeNavigation'
|
||||
import { TRANSPORT_TYPES, getAssignmentReservations } from '../../utils/dayMerge'
|
||||
import { TRANSPORT_TYPES, getPlaceBookings } from '../../utils/dayMerge'
|
||||
import { NavigationMenu } from '../shared/NavigationMenu'
|
||||
import { resolveOpenNow, resolvePlaceTimeZone, placeWeekdayIndex, type OpeningPeriod } from './placeOpenState'
|
||||
import { convertHoursLine } from './placeHoursFormat'
|
||||
@@ -479,7 +479,7 @@ export default function PlaceInspector({
|
||||
|
||||
{/* Bookings + participants — trip-only (collections have no days) */}
|
||||
{mode === 'trip' && (
|
||||
<PlaceBookingsAndPeople selectedAssignmentId={selectedAssignmentId} reservations={reservations}
|
||||
<PlaceBookingsAndPeople selectedAssignmentId={selectedAssignmentId} placeId={place.id} reservations={reservations}
|
||||
assignments={assignments} selectedDayId={selectedDayId} tripMembers={tripMembers}
|
||||
timeFormat={timeFormat} onSetParticipants={onSetParticipants}
|
||||
onEditTransport={onEditTransport} onEditReservation={onEditReservation} onOpenBooking={onOpenBooking} />
|
||||
@@ -758,6 +758,7 @@ function InspectorHead({ place, category, openNow, phone, rating, ratingCount, p
|
||||
|
||||
interface PlaceBookingsAndPeopleProps {
|
||||
selectedAssignmentId: number | null
|
||||
placeId: number
|
||||
reservations: Reservation[]
|
||||
assignments: AssignmentsMap
|
||||
selectedDayId: number | null
|
||||
@@ -770,10 +771,10 @@ interface PlaceBookingsAndPeopleProps {
|
||||
}
|
||||
|
||||
/** The bookings pinned to this stop and who joins it, side by side from sm up. */
|
||||
function PlaceBookingsAndPeople({ selectedAssignmentId, reservations, assignments, selectedDayId,
|
||||
function PlaceBookingsAndPeople({ selectedAssignmentId, placeId, reservations, assignments, selectedDayId,
|
||||
tripMembers, timeFormat, onSetParticipants, onEditTransport, onEditReservation, onOpenBooking }: PlaceBookingsAndPeopleProps) {
|
||||
const { t } = useTranslation()
|
||||
const linked = getAssignmentReservations<Reservation>(reservations, selectedAssignmentId)
|
||||
const linked = getPlaceBookings<Reservation>(reservations, selectedAssignmentId, placeId)
|
||||
const assignment = selectedAssignmentId ? (assignments[String(selectedDayId)] || []).find(a => a.id === selectedAssignmentId) : null
|
||||
const currentParticipants = assignment?.participants || []
|
||||
const participantIds = currentParticipants.map(p => p.user_id)
|
||||
|
||||
@@ -24,7 +24,7 @@ import { openFile } from '../../../../utils/fileDownload'
|
||||
import { filesForPlace } from '../../../../utils/placeFiles'
|
||||
import { navigationTargetLabel, getNavigationTargets, openNavigationTarget } from '../../../../components/Planner/placeNavigation'
|
||||
import { NavigationMenu } from '../../../../components/shared/NavigationMenu'
|
||||
import { getAssignmentReservations } from '../../../../utils/dayMerge'
|
||||
import { getPlaceBookings } from '../../../../utils/dayMerge'
|
||||
import type { Assignment, Day, Reservation, TripMember } from '../../../../types'
|
||||
import { ActionCircle, Eyebrow, INNER_CLS } from './MTripSheetUi'
|
||||
|
||||
@@ -92,8 +92,9 @@ export default function MPlaceSheet({ planner, shell }: MTripSheetsProps) {
|
||||
// The bookings attached to that assignment. The desktop inspector shows this
|
||||
// strip; the phone sheet never did, so a booking reached from a map marker was
|
||||
// just as unreachable here, only invisibly so (#2012). All of them, because a
|
||||
// stop can carry a parking pass next to its tickets (#2201).
|
||||
const linkedReservations = getAssignmentReservations(planner.reservations, assignmentInDay?.id)
|
||||
// stop can carry a parking pass next to its tickets (#2201). A hotel also lists
|
||||
// the stay booked for it, the way back to its booking (#2363).
|
||||
const linkedReservations = getPlaceBookings(planner.reservations, assignmentInDay?.id, place?.id)
|
||||
// A ferry or a flight has its own form — the reservation modal cannot hold one.
|
||||
// Resolved up front so a user without the matching right gets no button at all,
|
||||
// rather than one that does nothing (#2012).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { parseTimeToMinutes, getSpanPhase, hidesOnMiddleDay, getTransportRouteEndpoints, getDisplayTimeForDay, getTransportForDay, getAssignmentReservations, getMergedItems, rideSeatKey, stayStartingOn, storedRideSlot, timedSlot } from './dayMerge'
|
||||
import { parseTimeToMinutes, getSpanPhase, hidesOnMiddleDay, getTransportRouteEndpoints, getDisplayTimeForDay, getTransportForDay, getAssignmentReservations, getPlaceBookings, getMergedItems, rideSeatKey, stayStartingOn, storedRideSlot, timedSlot } from './dayMerge'
|
||||
|
||||
describe('parseTimeToMinutes', () => {
|
||||
it('parses HH:MM string', () => {
|
||||
@@ -199,6 +199,28 @@ describe('getTransportForDay', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('getPlaceBookings (#2363)', () => {
|
||||
const reservations = [
|
||||
{ id: 1, assignment_id: 42, reservation_time: '2025-06-01T10:00:00' },
|
||||
{ id: 2, assignment_id: null, reservation_time: '2025-06-01T15:00:00', accommodation_place_id: 9 },
|
||||
{ id: 3, assignment_id: 42, reservation_time: '2025-06-01T09:00:00', accommodation_place_id: 9 },
|
||||
{ id: 4, assignment_id: null, reservation_time: null, accommodation_place_id: 8 },
|
||||
]
|
||||
|
||||
it('adds the stay booked for a hotel after the bookings pinned to the stop, each once', () => {
|
||||
expect(getPlaceBookings(reservations, 42, 9).map(r => r.id)).toEqual([3, 1, 2])
|
||||
})
|
||||
|
||||
it('finds the stay even when no stop is open, as from the pill in the day head', () => {
|
||||
expect(getPlaceBookings(reservations, null, 9).map(r => r.id)).toEqual([2, 3])
|
||||
})
|
||||
|
||||
it('without a place it is the pinned list alone', () => {
|
||||
expect(getPlaceBookings(reservations, 42, null).map(r => r.id)).toEqual([3, 1])
|
||||
expect(getPlaceBookings(reservations, null, 7)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('getAssignmentReservations', () => {
|
||||
it('returns every booking pinned to the assignment, not just the first (#2201)', () => {
|
||||
const reservations = [
|
||||
|
||||
@@ -267,6 +267,25 @@ export function getAssignmentReservations<T extends {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* The bookings that belong to a place: the ones pinned to the open stop, and the
|
||||
* stay booked for it when the place is a hotel (#2363). Without the second, a
|
||||
* hotel opened from its pill in the day head showed the place but no route to its
|
||||
* booking. Pinned ones keep their order and come first.
|
||||
*/
|
||||
export function getPlaceBookings<T extends {
|
||||
id: number
|
||||
assignment_id?: number | null
|
||||
reservation_time?: string | null
|
||||
accommodation_place_id?: number | null
|
||||
}>(reservations: T[], assignmentId: number | null | undefined, placeId: number | null | undefined): T[] {
|
||||
const pinned = getAssignmentReservations(reservations, assignmentId)
|
||||
if (placeId == null) return pinned
|
||||
const pinnedIds = new Set(pinned.map(r => r.id))
|
||||
const stays = reservations.filter(r => r.accommodation_place_id === placeId && !pinnedIds.has(r.id))
|
||||
return [...pinned, ...stays]
|
||||
}
|
||||
|
||||
/**
|
||||
* Order items chronologically: anything with a time (a place's place_time, a
|
||||
* transport/leg display time, a timed note) sorts by that time. An item WITHOUT a
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'تسجيل الوصول',
|
||||
'day.checkInUntil': 'حتى',
|
||||
'day.checkOut': 'تسجيل المغادرة',
|
||||
'day.openStayBooking': 'فتح الحجز',
|
||||
'day.confirmation': 'التأكيد',
|
||||
'day.editAccommodation': 'تعديل الإقامة',
|
||||
'day.reservations': 'الحجوزات',
|
||||
|
||||
@@ -23,6 +23,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Giriş',
|
||||
'day.checkInUntil': 'Qədər',
|
||||
'day.checkOut': 'Çıxış',
|
||||
'day.openStayBooking': 'Rezervasiyanı aç',
|
||||
'day.confirmation': 'Təsdiq',
|
||||
'day.editAccommodation': 'Yaşayış yerini redaktə et',
|
||||
'day.reservations': 'Rezervasiyalar',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Até',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Abrir reserva',
|
||||
'day.confirmation': 'Confirmação',
|
||||
'day.editAccommodation': 'Editar hospedagem',
|
||||
'day.reservations': 'Reservas',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': "Registre d'entrada",
|
||||
'day.checkInUntil': 'Fins a',
|
||||
'day.checkOut': 'Registre de sortida',
|
||||
'day.openStayBooking': 'Obre la reserva',
|
||||
'day.confirmation': 'Confirmació',
|
||||
'day.editAccommodation': "Edita l'allotjament",
|
||||
'day.reservations': 'Reserves',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Do',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Otevřít rezervaci',
|
||||
'day.confirmation': 'Potvrzení',
|
||||
'day.editAccommodation': 'Upravit ubytování',
|
||||
'day.reservations': 'Rezervace',
|
||||
|
||||
@@ -20,6 +20,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Bis',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Buchung öffnen',
|
||||
'day.confirmation': 'Bestätigung',
|
||||
'day.editAccommodation': 'Unterkunft bearbeiten',
|
||||
'day.reservations': 'Reservierungen',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Until',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Open booking',
|
||||
'day.confirmation': 'Confirmation',
|
||||
'day.editAccommodation': 'Edit accommodation',
|
||||
'day.reservations': 'Reservations',
|
||||
|
||||
@@ -20,6 +20,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Registro de entrada',
|
||||
'day.checkInUntil': 'Hasta',
|
||||
'day.checkOut': 'Registro de salida',
|
||||
'day.openStayBooking': 'Abrir reserva',
|
||||
'day.confirmation': 'Confirmación',
|
||||
'day.editAccommodation': 'Editar alojamiento',
|
||||
'day.reservations': 'Reservas',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Sisseregistreerimine',
|
||||
'day.checkInUntil': 'Kuni',
|
||||
'day.checkOut': 'Väljaregistreerimine',
|
||||
'day.openStayBooking': 'Ava broneering',
|
||||
'day.confirmation': 'Kinnitus',
|
||||
'day.editAccommodation': 'Muuda majutust',
|
||||
'day.reservations': 'Broneeringud',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Arrivée',
|
||||
'day.checkInUntil': "Jusqu'à",
|
||||
'day.checkOut': 'Départ',
|
||||
'day.openStayBooking': 'Ouvrir la réservation',
|
||||
'day.confirmation': 'Confirmation',
|
||||
'day.editAccommodation': "Modifier l'hébergement",
|
||||
'day.reservations': 'Réservations',
|
||||
|
||||
@@ -20,6 +20,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Έως',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Άνοιγμα κράτησης',
|
||||
'day.confirmation': 'Επιβεβαίωση',
|
||||
'day.editAccommodation': 'Επεξεργασία διαμονής',
|
||||
'day.reservations': 'Κρατήσεις',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Bejelentkezés',
|
||||
'day.checkInUntil': 'Eddig',
|
||||
'day.checkOut': 'Kijelentkezés',
|
||||
'day.openStayBooking': 'Foglalás megnyitása',
|
||||
'day.confirmation': 'Visszaigazolás',
|
||||
'day.editAccommodation': 'Szállás szerkesztése',
|
||||
'day.reservations': 'Foglalások',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Sampai',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Buka pemesanan',
|
||||
'day.confirmation': 'Konfirmasi',
|
||||
'day.editAccommodation': 'Edit akomodasi',
|
||||
'day.reservations': 'Reservasi',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Fino a',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Apri prenotazione',
|
||||
'day.confirmation': 'Conferma',
|
||||
'day.editAccommodation': 'Modifica alloggio',
|
||||
'day.reservations': 'Prenotazioni',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'チェックイン',
|
||||
'day.checkInUntil': 'チェックイン期限',
|
||||
'day.checkOut': 'チェックアウト',
|
||||
'day.openStayBooking': '予約を開く',
|
||||
'day.confirmation': '確認',
|
||||
'day.editAccommodation': '宿泊先を編集',
|
||||
'day.reservations': '予約',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': '체크인',
|
||||
'day.checkInUntil': '까지',
|
||||
'day.checkOut': '체크아웃',
|
||||
'day.openStayBooking': '예약 열기',
|
||||
'day.confirmation': '확인',
|
||||
'day.editAccommodation': '숙박 편집',
|
||||
'day.reservations': '예약',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Inchecken',
|
||||
'day.checkInUntil': 'Tot',
|
||||
'day.checkOut': 'Uitchecken',
|
||||
'day.openStayBooking': 'Boeking openen',
|
||||
'day.confirmation': 'Bevestiging',
|
||||
'day.editAccommodation': 'Accommodatie bewerken',
|
||||
'day.reservations': 'Reserveringen',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Zameldowanie',
|
||||
'day.checkInUntil': 'Do',
|
||||
'day.checkOut': 'Wymeldowanie',
|
||||
'day.openStayBooking': 'Otwórz rezerwację',
|
||||
'day.confirmation': 'Potwierdzenie',
|
||||
'day.editAccommodation': 'Edytuj zakwaterowanie',
|
||||
'day.reservations': 'Rezerwacje',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Заезд',
|
||||
'day.checkInUntil': 'До',
|
||||
'day.checkOut': 'Выезд',
|
||||
'day.openStayBooking': 'Открыть бронирование',
|
||||
'day.confirmation': 'Подтверждение',
|
||||
'day.editAccommodation': 'Редактировать жильё',
|
||||
'day.reservations': 'Бронирования',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Check-in',
|
||||
'day.checkInUntil': 'Do',
|
||||
'day.checkOut': 'Check-out',
|
||||
'day.openStayBooking': 'Otvoriť rezerváciu',
|
||||
'day.confirmation': 'Potvrdenie',
|
||||
'day.editAccommodation': 'Upraviť ubytovanie',
|
||||
'day.reservations': 'Rezervácie',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Incheckning',
|
||||
'day.checkInUntil': 'Tills',
|
||||
'day.checkOut': 'Utcheckning',
|
||||
'day.openStayBooking': 'Öppna bokning',
|
||||
'day.confirmation': 'Bekräftelse',
|
||||
'day.editAccommodation': 'Redigera boende',
|
||||
'day.reservations': 'Bokningar',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': "เช็คอิน",
|
||||
'day.checkInUntil': "เช็กอินได้ถึง",
|
||||
'day.checkOut': "เช็คเอาท์",
|
||||
'day.openStayBooking': 'เปิดการจอง',
|
||||
'day.confirmation': "การยืนยัน",
|
||||
'day.editAccommodation': "แก้ไขที่พัก",
|
||||
'day.reservations': "การจอง",
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Giriş',
|
||||
'day.checkInUntil': 'Kadar',
|
||||
'day.checkOut': 'Çıkış yapmak',
|
||||
'day.openStayBooking': 'Rezervasyonu aç',
|
||||
'day.confirmation': 'Onay kodu',
|
||||
'day.editAccommodation': 'Konaklamayı düzenle',
|
||||
'day.reservations': 'Rezervasyonlar',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Заїзд',
|
||||
'day.checkInUntil': 'До',
|
||||
'day.checkOut': 'Виїзд',
|
||||
'day.openStayBooking': 'Відкрити бронювання',
|
||||
'day.confirmation': 'Підтвердження',
|
||||
'day.editAccommodation': 'Редагувати проживання',
|
||||
'day.reservations': 'Бронювання',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': 'Nhận phòng',
|
||||
'day.checkInUntil': 'Cho đến khi',
|
||||
'day.checkOut': 'Trả phòng',
|
||||
'day.openStayBooking': 'Mở đặt chỗ',
|
||||
'day.confirmation': 'Xác nhận',
|
||||
'day.editAccommodation': 'Chỉnh sửa chỗ ở',
|
||||
'day.reservations': 'Đặt chỗ',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': '入住',
|
||||
'day.checkInUntil': '截止',
|
||||
'day.checkOut': '退房',
|
||||
'day.openStayBooking': '開啟預訂',
|
||||
'day.confirmation': '確認號',
|
||||
'day.editAccommodation': '編輯住宿',
|
||||
'day.reservations': '預訂',
|
||||
|
||||
@@ -19,6 +19,7 @@ const day: TranslationStrings = {
|
||||
'day.checkIn': '入住',
|
||||
'day.checkInUntil': '截止',
|
||||
'day.checkOut': '退房',
|
||||
'day.openStayBooking': '打开预订',
|
||||
'day.confirmation': '确认号',
|
||||
'day.editAccommodation': '编辑住宿',
|
||||
'day.reservations': '预订',
|
||||
|
||||
Reference in New Issue
Block a user