From b8728078c4d3c6344c27b11420d0c992ad2c4fb5 Mon Sep 17 00:00:00 2001 From: Maurice <61554723+mauriceboe@users.noreply.github.com> Date: Tue, 21 Jul 2026 16:02:53 +0200 Subject: [PATCH] feat(reservations): add a parking booking type (#1444) (#1642) * feat(reservations): add a parking booking type (#1444) * feat(reservations): parking type option, icon and color across the UI * test(reservations): cover the parking booking type * docs(reservations): document the parking booking type --- client/src/components/PDF/TripPDF.tsx | 6 +++--- client/src/components/Planner/DayDetailPanel.tsx | 6 +++--- .../components/Planner/DayPlanSidebar.constants.ts | 4 ++-- .../components/Planner/ReservationModal.test.tsx | 14 ++++++++++++++ client/src/components/Planner/ReservationModal.tsx | 3 ++- .../src/components/Planner/ReservationsPanel.tsx | 3 ++- .../screens/trip/sheets/MReservationSheet.tsx | 3 ++- .../src/mobile/screens/trip/tabs/bookingsModel.ts | 1 + client/src/pages/DashboardPage.tsx | 4 ++-- server/src/mcp/tools/reservations.ts | 8 ++++---- server/tests/unit/mcp/tools-reservations.test.ts | 14 ++++++++++++++ shared/src/budget/budget.schema.ts | 1 + shared/src/i18n/ar/reservations.ts | 1 + shared/src/i18n/br/reservations.ts | 1 + shared/src/i18n/ca/reservations.ts | 1 + shared/src/i18n/cs/reservations.ts | 1 + shared/src/i18n/de/reservations.ts | 1 + shared/src/i18n/en/reservations.ts | 1 + shared/src/i18n/es/reservations.ts | 1 + shared/src/i18n/fr/reservations.ts | 1 + shared/src/i18n/gr/reservations.ts | 1 + shared/src/i18n/hu/reservations.ts | 1 + shared/src/i18n/id/reservations.ts | 1 + shared/src/i18n/it/reservations.ts | 1 + shared/src/i18n/ja/reservations.ts | 1 + shared/src/i18n/ko/reservations.ts | 1 + shared/src/i18n/nl/reservations.ts | 1 + shared/src/i18n/pl/reservations.ts | 1 + shared/src/i18n/ru/reservations.ts | 1 + shared/src/i18n/sv/reservations.ts | 1 + shared/src/i18n/tr/reservations.ts | 1 + shared/src/i18n/uk/reservations.ts | 1 + shared/src/i18n/vi/reservations.ts | 1 + shared/src/i18n/zh-TW/reservations.ts | 1 + shared/src/i18n/zh/reservations.ts | 1 + wiki/Reservations-and-Bookings.md | 5 +++-- 36 files changed, 76 insertions(+), 19 deletions(-) diff --git a/client/src/components/PDF/TripPDF.tsx b/client/src/components/PDF/TripPDF.tsx index 98745bd8e..c3d084a38 100644 --- a/client/src/components/PDF/TripPDF.tsx +++ b/client/src/components/PDF/TripPDF.tsx @@ -1,7 +1,7 @@ // Trip PDF via browser print window import { createElement } from 'react' import { getCategoryIcon } from '../shared/categoryIcons' -import { FileText, Info, Clock, MapPin, Navigation, Train, Plane, Bus, Car, Ship, Sailboat, Bike, CarTaxiFront, Route, Coffee, Ticket, Star, Heart, Camera, Flag, Lightbulb, AlertTriangle, ShoppingBag, Bookmark, Hotel, LogIn, LogOut, KeyRound, BedDouble, Utensils, Users, LucideIcon } from 'lucide-react' +import { FileText, Info, Clock, MapPin, Navigation, Train, Plane, Bus, Car, Ship, Sailboat, Bike, CarTaxiFront, Route, Coffee, Ticket, Star, Heart, Camera, Flag, Lightbulb, AlertTriangle, ShoppingBag, Bookmark, Hotel, LogIn, LogOut, KeyRound, BedDouble, Utensils, Users, ParkingSquare, LucideIcon } from 'lucide-react' import { accommodationsApi, mapsApi, pluginsApi } from '../../api/client' import type { Trip, Day, Place, Category, AssignmentsMap, DayNote } from '../../types' import { isDayInAccommodationRange, getDayOrder } from '../../utils/dayOrder' @@ -22,8 +22,8 @@ function noteIconSvg(iconId) { return renderLucideIcon(Icon, { size: 14, strokeWidth: 1.8, color: '#94a3b8' }) } -const RESERVATION_ICON_MAP = { flight: Plane, train: Train, bus: Bus, car: Car, taxi: CarTaxiFront, bicycle: Bike, cruise: Ship, ferry: Sailboat, transport_other: Route, restaurant: Utensils, event: Ticket, tour: Users, other: FileText } -const RESERVATION_COLOR_MAP = { flight: '#3b82f6', train: '#06b6d4', bus: '#059669', car: '#6b7280', taxi: '#ca8a04', bicycle: '#84cc16', cruise: '#0ea5e9', ferry: '#0d9488', transport_other: '#6b7280', restaurant: '#ef4444', event: '#f59e0b', tour: '#10b981', other: '#6b7280' } +const RESERVATION_ICON_MAP = { flight: Plane, train: Train, bus: Bus, car: Car, taxi: CarTaxiFront, bicycle: Bike, cruise: Ship, ferry: Sailboat, transport_other: Route, restaurant: Utensils, event: Ticket, tour: Users, parking: ParkingSquare, other: FileText } +const RESERVATION_COLOR_MAP = { flight: '#3b82f6', train: '#06b6d4', bus: '#059669', car: '#6b7280', taxi: '#ca8a04', bicycle: '#84cc16', cruise: '#0ea5e9', ferry: '#0d9488', transport_other: '#6b7280', restaurant: '#ef4444', event: '#f59e0b', tour: '#10b981', parking: '#2563eb', other: '#6b7280' } function reservationIconSvg(type) { const Icon = RESERVATION_ICON_MAP[type] || Ticket const color = RESERVATION_COLOR_MAP[type] || '#3b82f6' diff --git a/client/src/components/Planner/DayDetailPanel.tsx b/client/src/components/Planner/DayDetailPanel.tsx index d1327787c..ecec60c62 100644 --- a/client/src/components/Planner/DayDetailPanel.tsx +++ b/client/src/components/Planner/DayDetailPanel.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect, useRef } from 'react' import ReactDOM from 'react-dom' -import { X, Sun, Cloud, CloudRain, CloudSnow, CloudDrizzle, CloudLightning, Wind, Droplets, Sunrise, Sunset, Hotel, Calendar, MapPin, LogIn, LogOut, Hash, Pencil, Plane, Utensils, Train, Car, Ship, Ticket, FileText, Users, ChevronsDown, ChevronsUp, TramFront } from 'lucide-react' +import { X, Sun, Cloud, CloudRain, CloudSnow, CloudDrizzle, CloudLightning, Wind, Droplets, Sunrise, Sunset, Hotel, Calendar, MapPin, LogIn, LogOut, Hash, Pencil, Plane, Utensils, Train, Car, Ship, Ticket, FileText, Users, ChevronsDown, ChevronsUp, TramFront, ParkingSquare } from 'lucide-react' -const RES_TYPE_ICONS = { flight: Plane, hotel: Hotel, restaurant: Utensils, train: Train, car: Car, cruise: Ship, transit: TramFront, event: Ticket, tour: Users, other: FileText } -const RES_TYPE_COLORS = { flight: '#3b82f6', hotel: '#8b5cf6', restaurant: '#ef4444', train: '#06b6d4', car: '#6b7280', cruise: '#0ea5e9', transit: '#7c3aed', event: '#f59e0b', tour: '#10b981', other: '#6b7280' } +const RES_TYPE_ICONS = { flight: Plane, hotel: Hotel, restaurant: Utensils, train: Train, car: Car, cruise: Ship, transit: TramFront, event: Ticket, tour: Users, parking: ParkingSquare, other: FileText } +const RES_TYPE_COLORS = { flight: '#3b82f6', hotel: '#8b5cf6', restaurant: '#ef4444', train: '#06b6d4', car: '#6b7280', cruise: '#0ea5e9', transit: '#7c3aed', event: '#f59e0b', tour: '#10b981', parking: '#2563eb', other: '#6b7280' } import { weatherApi, accommodationsApi } from '../../api/client' import { usePluginViewContributions, PluginCardFooter } from '../Plugins/PluginContributions' import { usePluginStore } from '../../store/pluginStore' diff --git a/client/src/components/Planner/DayPlanSidebar.constants.ts b/client/src/components/Planner/DayPlanSidebar.constants.ts index 52359d539..63f36a8df 100644 --- a/client/src/components/Planner/DayPlanSidebar.constants.ts +++ b/client/src/components/Planner/DayPlanSidebar.constants.ts @@ -5,7 +5,7 @@ import { Wine, ParkingSquare, Fuel, Footprints, Mountain, Waves, Sun, Umbrella, Music, Landmark, Gift, } from 'lucide-react' -export const RES_ICONS = { flight: Plane, hotel: Hotel, restaurant: Utensils, train: Train, car: Car, cruise: Ship, bus: Bus, ferry: Sailboat, bicycle: Bike, taxi: CarTaxiFront, transit: TramFront, transport_other: Route, event: Ticket, tour: Users, other: FileText } +export const RES_ICONS = { flight: Plane, hotel: Hotel, restaurant: Utensils, train: Train, car: Car, cruise: Ship, bus: Bus, ferry: Sailboat, bicycle: Bike, taxi: CarTaxiFront, transit: TramFront, transport_other: Route, event: Ticket, tour: Users, parking: ParkingSquare, other: FileText } export const NOTE_ICONS = [ { id: 'FileText', Icon: FileText }, @@ -47,7 +47,7 @@ export function getNoteIcon(iconId) { return NOTE_ICON_MAP[iconId] || FileText } export const TYPE_ICONS = { flight: '✈️', hotel: '🏨', restaurant: '🍽️', train: '🚆', car: '🚗', cruise: '🚢', bus: '🚌', ferry: '⛴️', bicycle: '🚲', taxi: '🚕', - transport_other: '🧭', event: '🎫', other: '📋', + transport_other: '🧭', event: '🎫', parking: '🅿️', other: '📋', } export const TRANSPORT_DETAIL_COLORS = { flight: '#3b82f6', train: '#06b6d4', bus: '#059669', ferry: '#0d9488', bicycle: '#84cc16', taxi: '#ca8a04', car: '#6b7280', cruise: '#0ea5e9', transit: '#7c3aed', transport_other: '#6b7280' } diff --git a/client/src/components/Planner/ReservationModal.test.tsx b/client/src/components/Planner/ReservationModal.test.tsx index 69e8994bf..f34470a19 100644 --- a/client/src/components/Planner/ReservationModal.test.tsx +++ b/client/src/components/Planner/ReservationModal.test.tsx @@ -443,6 +443,20 @@ describe('ReservationModal', () => { ); }); + it('FE-PLANNER-RESMODAL-031b: parking type — saving calls onSave with parking type (#1444)', async () => { + const onSave = vi.fn().mockResolvedValue(undefined); + render(); + + await userEvent.click(screen.getByRole('button', { name: /Parking/i })); + await userEvent.type(screen.getByPlaceholderText(/e\.g\. Lufthansa/i), 'Airport Parking P1'); + await userEvent.click(screen.getByRole('button', { name: /^Add$/i })); + + await waitFor(() => expect(onSave).toHaveBeenCalled()); + expect(onSave).toHaveBeenCalledWith( + expect.objectContaining({ title: 'Airport Parking P1', type: 'parking' }) + ); + }); + it('FE-PLANNER-RESMODAL-032: edit mode — save button shows "Update"', () => { const res = buildReservation({ title: 'My Trip', type: 'other' }); render(); diff --git a/client/src/components/Planner/ReservationModal.tsx b/client/src/components/Planner/ReservationModal.tsx index 369cfb282..f61eecd10 100644 --- a/client/src/components/Planner/ReservationModal.tsx +++ b/client/src/components/Planner/ReservationModal.tsx @@ -6,7 +6,7 @@ import { useAddonStore } from '../../store/addonStore' import Modal from '../shared/Modal' import CustomSelect from '../shared/CustomSelect' import AddressInput from './AddressInput' -import { Hotel, Utensils, Ticket, FileText, Users, Paperclip, X, ExternalLink, Link2 } from 'lucide-react' +import { Hotel, Utensils, Ticket, FileText, Users, Paperclip, X, ExternalLink, Link2, ParkingSquare } from 'lucide-react' import { useToast } from '../shared/Toast' import { useTranslation } from '../../i18n' import { CustomDatePicker } from '../shared/CustomDateTimePicker' @@ -24,6 +24,7 @@ const TYPE_OPTIONS = [ { value: 'restaurant', labelKey: 'reservations.type.restaurant', Icon: Utensils }, { value: 'event', labelKey: 'reservations.type.event', Icon: Ticket }, { value: 'tour', labelKey: 'reservations.type.tour', Icon: Users }, + { value: 'parking', labelKey: 'reservations.type.parking', Icon: ParkingSquare }, { value: 'other', labelKey: 'reservations.type.other', Icon: FileText }, ] diff --git a/client/src/components/Planner/ReservationsPanel.tsx b/client/src/components/Planner/ReservationsPanel.tsx index cede313cb..302b0a108 100644 --- a/client/src/components/Planner/ReservationsPanel.tsx +++ b/client/src/components/Planner/ReservationsPanel.tsx @@ -9,7 +9,7 @@ import { Plane, Hotel, Utensils, Train, Car, Ship, Bus, Sailboat, Bike, CarTaxiFront, Route, Ticket, FileText, MapPin, Calendar, Hash, CheckCircle2, Circle, Pencil, Trash2, Plus, ChevronDown, ChevronRight, Users, ExternalLink, Lightbulb, Link2, Clock, ArrowRight, AlertCircle, Download, - TramFront, Footprints, StickyNote, + TramFront, Footprints, StickyNote, ParkingSquare, } from 'lucide-react' import { openFile } from '../../utils/fileDownload' import { TransitTitle, TransitLegChips, TransitMetaBadges, fmtTransitDuration } from './transitDisplay' @@ -48,6 +48,7 @@ const TYPE_OPTIONS = [ { value: 'transport_other', labelKey: 'reservations.type.transport_other', Icon: Route, color: '#6b7280' }, { value: 'event', labelKey: 'reservations.type.event', Icon: Ticket, color: '#f59e0b' }, { value: 'tour', labelKey: 'reservations.type.tour', Icon: Users, color: '#10b981' }, + { value: 'parking', labelKey: 'reservations.type.parking', Icon: ParkingSquare, color: '#2563eb' }, { value: 'other', labelKey: 'reservations.type.other', Icon: FileText, color: '#6b7280' }, ] diff --git a/client/src/mobile/screens/trip/sheets/MReservationSheet.tsx b/client/src/mobile/screens/trip/sheets/MReservationSheet.tsx index ad69931a3..90536f4f5 100644 --- a/client/src/mobile/screens/trip/sheets/MReservationSheet.tsx +++ b/client/src/mobile/screens/trip/sheets/MReservationSheet.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react' -import { FileText, Hotel, Link2, Plus, Ticket, Users, Utensils } from 'lucide-react' +import { FileText, Hotel, Link2, ParkingSquare, Plus, Ticket, Users, Utensils } from 'lucide-react' import MSheet from '../../../components/MSheet' import { useAddonStore } from '../../../../store/addonStore' import { useTranslation } from '../../../../i18n' @@ -23,6 +23,7 @@ const TYPE_OPTIONS = [ { value: 'restaurant', labelKey: 'reservations.type.restaurant', Icon: Utensils }, { value: 'event', labelKey: 'reservations.type.event', Icon: Ticket }, { value: 'tour', labelKey: 'reservations.type.tour', Icon: Users }, + { value: 'parking', labelKey: 'reservations.type.parking', Icon: ParkingSquare }, { value: 'other', labelKey: 'reservations.type.other', Icon: FileText }, ] diff --git a/client/src/mobile/screens/trip/tabs/bookingsModel.ts b/client/src/mobile/screens/trip/tabs/bookingsModel.ts index b144b6f9c..79e5ac960 100644 --- a/client/src/mobile/screens/trip/tabs/bookingsModel.ts +++ b/client/src/mobile/screens/trip/tabs/bookingsModel.ts @@ -10,5 +10,6 @@ export const BOOKING_TYPE_COLOR: Record = { restaurant: '#ef4444', event: '#f59e0b', tour: '#10b981', + parking: '#2563eb', other: '#6b7280', } diff --git a/client/src/pages/DashboardPage.tsx b/client/src/pages/DashboardPage.tsx index dae82ee8a..46c293a04 100644 --- a/client/src/pages/DashboardPage.tsx +++ b/client/src/pages/DashboardPage.tsx @@ -17,7 +17,7 @@ import { import { Plus, Edit2, Trash2, Archive, Copy, ArrowRight, MapPin, Plane, Hotel, Utensils, Clock, RefreshCw, ArrowRightLeft, Calendar, - LayoutGrid, List, Ticket, X, CalendarPlus, + LayoutGrid, List, Ticket, X, CalendarPlus, ParkingSquare, } from 'lucide-react' import { IcsSubscribeModal } from '../components/Planner/IcsSubscribeModal' import CollectionsWidget from '../components/Dashboard/CollectionsWidget' @@ -92,7 +92,7 @@ function initials(name: string | null | undefined): string { } const RES_ICON: Record = { - flight: , hotel: , restaurant: , + flight: , hotel: , restaurant: , parking: , } const RES_TYPE_CLASS: Record = { flight: 'flight', hotel: 'hotel', restaurant: 'food' } diff --git a/server/src/mcp/tools/reservations.ts b/server/src/mcp/tools/reservations.ts index 9b9fa08c9..b78e0c08c 100644 --- a/server/src/mcp/tools/reservations.ts +++ b/server/src/mcp/tools/reservations.ts @@ -23,11 +23,11 @@ export function registerReservationTools(server: McpServer, userId: number, scop server.registerTool( 'create_reservation', { - description: 'Recommend a reservation for a trip. Created as pending — the user must confirm it. For flights, trains, cars, and cruises, use create_transport instead. Linking: hotel → use place_id + start_day_id + end_day_id (all three required to create the accommodation link); restaurant/event/tour/activity/other → use assignment_id. Set price to record the cost; it will appear on the booking and in the Budget tab.', + description: 'Recommend a reservation for a trip. Created as pending — the user must confirm it. For flights, trains, cars, and cruises, use create_transport instead. Linking: hotel → use place_id + start_day_id + end_day_id (all three required to create the accommodation link); restaurant/event/tour/activity/parking/other → use assignment_id. Set price to record the cost; it will appear on the booking and in the Budget tab.', inputSchema: { tripId: z.number().int().positive(), title: z.string().min(1).max(200), - type: z.enum(['hotel', 'restaurant', 'event', 'tour', 'activity', 'other']).describe('Reservation type: "hotel", "restaurant", "event", "tour", "activity", or "other"'), + type: z.enum(['hotel', 'restaurant', 'event', 'tour', 'activity', 'parking', 'other']).describe('Reservation type: "hotel", "restaurant", "event", "tour", "activity", "parking", or "other"'), reservation_time: z.string().optional().describe('ISO 8601 datetime or time string'), location: z.string().max(500).optional(), confirmation_number: z.string().max(100).optional(), @@ -95,12 +95,12 @@ export function registerReservationTools(server: McpServer, userId: number, scop server.registerTool( 'update_reservation', { - description: 'Update an existing reservation in a trip. Use status "confirmed" to confirm a pending recommendation, or "pending" to revert it. For flights, trains, cars, and cruises, use update_transport instead. Linking: hotel → use place_id to link to an accommodation place; restaurant/event/tour/activity/other → use assignment_id to link to a day assignment.', + description: 'Update an existing reservation in a trip. Use status "confirmed" to confirm a pending recommendation, or "pending" to revert it. For flights, trains, cars, and cruises, use update_transport instead. Linking: hotel → use place_id to link to an accommodation place; restaurant/event/tour/activity/parking/other → use assignment_id to link to a day assignment.', inputSchema: { tripId: z.number().int().positive(), reservationId: z.number().int().positive(), title: z.string().min(1).max(200).optional(), - type: z.enum(['hotel', 'restaurant', 'event', 'tour', 'activity', 'other']).optional().describe('Reservation type: "hotel", "restaurant", "event", "tour", "activity", or "other"'), + type: z.enum(['hotel', 'restaurant', 'event', 'tour', 'activity', 'parking', 'other']).optional().describe('Reservation type: "hotel", "restaurant", "event", "tour", "activity", "parking", or "other"'), reservation_time: z.string().optional().describe('ISO 8601 datetime or time string'), location: z.string().max(500).optional(), confirmation_number: z.string().max(100).optional(), diff --git a/server/tests/unit/mcp/tools-reservations.test.ts b/server/tests/unit/mcp/tools-reservations.test.ts index 55f02ca26..6c2262b1c 100644 --- a/server/tests/unit/mcp/tools-reservations.test.ts +++ b/server/tests/unit/mcp/tools-reservations.test.ts @@ -79,6 +79,20 @@ describe('Tool: create_reservation', () => { }); }); + it('creates a parking reservation (#1444)', async () => { + const { user } = createUser(testDb); + const trip = createTrip(testDb, user.id); + await withHarness(user.id, async (h) => { + const result = await h.client.callTool({ + name: 'create_reservation', + arguments: { tripId: trip.id, title: 'Airport Parking P1', type: 'parking' }, + }); + const data = parseToolResult(result) as any; + expect(data.reservation.title).toBe('Airport Parking P1'); + expect(data.reservation.type).toBe('parking'); + }); + }); + it('creates a hotel reservation and links accommodation', async () => { const { user } = createUser(testDb); const trip = createTrip(testDb, user.id); diff --git a/shared/src/budget/budget.schema.ts b/shared/src/budget/budget.schema.ts index 80dbf04d9..ca71b3c3f 100644 --- a/shared/src/budget/budget.schema.ts +++ b/shared/src/budget/budget.schema.ts @@ -70,6 +70,7 @@ const RESERVATION_TYPE_TO_COST_CATEGORY: Record = { hotel: 'accommodation', accommodation: 'accommodation', lodging: 'accommodation', + parking: 'transport', restaurant: 'food', activity: 'activities', }; diff --git a/shared/src/i18n/ar/reservations.ts b/shared/src/i18n/ar/reservations.ts index 6ba3b6d04..b4090192a 100644 --- a/shared/src/i18n/ar/reservations.ts +++ b/shared/src/i18n/ar/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'رحلة بحرية', 'reservations.type.event': 'فعالية', 'reservations.type.tour': 'جولة', + 'reservations.type.parking': 'موقف سيارات', 'reservations.type.other': 'أخرى', 'reservations.type.bus': 'حافلة', 'reservations.type.ferry': 'عبّارة', diff --git a/shared/src/i18n/br/reservations.ts b/shared/src/i18n/br/reservations.ts index 2d9e3737e..cbed3dfb3 100644 --- a/shared/src/i18n/br/reservations.ts +++ b/shared/src/i18n/br/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Cruzeiro', 'reservations.type.event': 'Evento', 'reservations.type.tour': 'Passeio', + 'reservations.type.parking': 'Estacionamento', 'reservations.type.other': 'Outro', 'reservations.type.bus': 'Ônibus', 'reservations.type.ferry': 'Balsa', diff --git a/shared/src/i18n/ca/reservations.ts b/shared/src/i18n/ca/reservations.ts index 0b086d955..071d3cce3 100644 --- a/shared/src/i18n/ca/reservations.ts +++ b/shared/src/i18n/ca/reservations.ts @@ -31,6 +31,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Creuer', 'reservations.type.event': 'Esdeveniment', 'reservations.type.tour': 'Excursió', + 'reservations.type.parking': 'Aparcament', 'reservations.type.other': 'Altres', 'reservations.type.bus': 'Autobús', 'reservations.type.ferry': 'Ferri', diff --git a/shared/src/i18n/cs/reservations.ts b/shared/src/i18n/cs/reservations.ts index c7ccb22d6..c488cdf9c 100644 --- a/shared/src/i18n/cs/reservations.ts +++ b/shared/src/i18n/cs/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Plavba', 'reservations.type.event': 'Událost', 'reservations.type.tour': 'Prohlídka', + 'reservations.type.parking': 'Parkování', 'reservations.type.other': 'Jiné', 'reservations.type.bus': 'Autobus', 'reservations.type.ferry': 'Trajekt', diff --git a/shared/src/i18n/de/reservations.ts b/shared/src/i18n/de/reservations.ts index 12ed9b110..c57ad758a 100644 --- a/shared/src/i18n/de/reservations.ts +++ b/shared/src/i18n/de/reservations.ts @@ -61,6 +61,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Kreuzfahrt', 'reservations.type.event': 'Veranstaltung', 'reservations.type.tour': 'Tour', + 'reservations.type.parking': 'Parkplatz', 'reservations.type.other': 'Sonstiges', 'reservations.type.bus': 'Bus', 'reservations.type.ferry': 'Fähre', diff --git a/shared/src/i18n/en/reservations.ts b/shared/src/i18n/en/reservations.ts index 108961ed1..34acf4e97 100644 --- a/shared/src/i18n/en/reservations.ts +++ b/shared/src/i18n/en/reservations.ts @@ -60,6 +60,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Cruise', 'reservations.type.event': 'Event', 'reservations.type.tour': 'Tour', + 'reservations.type.parking': 'Parking', 'reservations.type.other': 'Other', 'reservations.type.bus': 'Bus', 'reservations.type.ferry': 'Ferry', diff --git a/shared/src/i18n/es/reservations.ts b/shared/src/i18n/es/reservations.ts index 54d5d4b0b..c10fdb988 100644 --- a/shared/src/i18n/es/reservations.ts +++ b/shared/src/i18n/es/reservations.ts @@ -31,6 +31,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Crucero', 'reservations.type.event': 'Evento', 'reservations.type.tour': 'Excursión', + 'reservations.type.parking': 'Aparcamiento', 'reservations.type.other': 'Otro', 'reservations.type.bus': 'Autobús', 'reservations.type.ferry': 'Ferry', diff --git a/shared/src/i18n/fr/reservations.ts b/shared/src/i18n/fr/reservations.ts index f2f7949a3..4d11ea14c 100644 --- a/shared/src/i18n/fr/reservations.ts +++ b/shared/src/i18n/fr/reservations.ts @@ -60,6 +60,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Croisière', 'reservations.type.event': 'Événement', 'reservations.type.tour': 'Visite', + 'reservations.type.parking': 'Parking', 'reservations.type.other': 'Autre', 'reservations.type.bus': 'Bus', 'reservations.type.ferry': 'Ferry', diff --git a/shared/src/i18n/gr/reservations.ts b/shared/src/i18n/gr/reservations.ts index 835c7c535..fe91b966d 100644 --- a/shared/src/i18n/gr/reservations.ts +++ b/shared/src/i18n/gr/reservations.ts @@ -60,6 +60,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Κρουαζιέρα', 'reservations.type.event': 'Εκδήλωση', 'reservations.type.tour': 'Περιήγηση', + 'reservations.type.parking': 'Στάθμευση', 'reservations.type.other': 'Άλλο', 'reservations.type.bus': 'Λεωφορείο', 'reservations.type.ferry': 'Φέρι', diff --git a/shared/src/i18n/hu/reservations.ts b/shared/src/i18n/hu/reservations.ts index bebe3d47d..127a67acf 100644 --- a/shared/src/i18n/hu/reservations.ts +++ b/shared/src/i18n/hu/reservations.ts @@ -60,6 +60,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Hajóút', 'reservations.type.event': 'Esemény', 'reservations.type.tour': 'Túra', + 'reservations.type.parking': 'Parkolás', 'reservations.type.other': 'Egyéb', 'reservations.type.bus': 'Busz', 'reservations.type.ferry': 'Komp', diff --git a/shared/src/i18n/id/reservations.ts b/shared/src/i18n/id/reservations.ts index cdf0ce322..41d5ac90a 100644 --- a/shared/src/i18n/id/reservations.ts +++ b/shared/src/i18n/id/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Kapal Pesiar', 'reservations.type.event': 'Acara', 'reservations.type.tour': 'Tur', + 'reservations.type.parking': 'Parkir', 'reservations.type.other': 'Lainnya', 'reservations.type.bus': 'Bus', 'reservations.type.ferry': 'Feri', diff --git a/shared/src/i18n/it/reservations.ts b/shared/src/i18n/it/reservations.ts index d0709d142..d5f27ea6f 100644 --- a/shared/src/i18n/it/reservations.ts +++ b/shared/src/i18n/it/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Crociera', 'reservations.type.event': 'Evento', 'reservations.type.tour': 'Tour', + 'reservations.type.parking': 'Parcheggio', 'reservations.type.other': 'Altro', 'reservations.type.bus': 'Autobus', 'reservations.type.ferry': 'Traghetto', diff --git a/shared/src/i18n/ja/reservations.ts b/shared/src/i18n/ja/reservations.ts index 2792a9363..a0e759d10 100644 --- a/shared/src/i18n/ja/reservations.ts +++ b/shared/src/i18n/ja/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'クルーズ', 'reservations.type.event': 'イベント', 'reservations.type.tour': 'ツアー', + 'reservations.type.parking': '駐車場', 'reservations.type.other': 'その他', 'reservations.type.bus': 'バス', 'reservations.type.ferry': 'フェリー', diff --git a/shared/src/i18n/ko/reservations.ts b/shared/src/i18n/ko/reservations.ts index 2031fea43..bec314b94 100644 --- a/shared/src/i18n/ko/reservations.ts +++ b/shared/src/i18n/ko/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': '크루즈', 'reservations.type.event': '이벤트', 'reservations.type.tour': '투어', + 'reservations.type.parking': '주차', 'reservations.type.other': '기타', 'reservations.type.bus': '버스', 'reservations.type.ferry': '페리', diff --git a/shared/src/i18n/nl/reservations.ts b/shared/src/i18n/nl/reservations.ts index f85ed6352..174a7093f 100644 --- a/shared/src/i18n/nl/reservations.ts +++ b/shared/src/i18n/nl/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Cruise', 'reservations.type.event': 'Evenement', 'reservations.type.tour': 'Rondleiding', + 'reservations.type.parking': 'Parkeren', 'reservations.type.other': 'Overig', 'reservations.type.bus': 'Bus', 'reservations.type.ferry': 'Veerboot', diff --git a/shared/src/i18n/pl/reservations.ts b/shared/src/i18n/pl/reservations.ts index 4bccd2139..122ba3167 100644 --- a/shared/src/i18n/pl/reservations.ts +++ b/shared/src/i18n/pl/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Rejs', 'reservations.type.event': 'Wydarzenie', 'reservations.type.tour': 'Wycieczka', + 'reservations.type.parking': 'Parking', 'reservations.type.other': 'Inne', 'reservations.type.bus': 'Autobus', 'reservations.type.ferry': 'Prom', diff --git a/shared/src/i18n/ru/reservations.ts b/shared/src/i18n/ru/reservations.ts index 90d39fc61..0e8551956 100644 --- a/shared/src/i18n/ru/reservations.ts +++ b/shared/src/i18n/ru/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Круиз', 'reservations.type.event': 'Мероприятие', 'reservations.type.tour': 'Экскурсия', + 'reservations.type.parking': 'Парковка', 'reservations.type.other': 'Другое', 'reservations.type.bus': 'Автобус', 'reservations.type.ferry': 'Паром', diff --git a/shared/src/i18n/sv/reservations.ts b/shared/src/i18n/sv/reservations.ts index ee29bc2b7..99d0e07f4 100644 --- a/shared/src/i18n/sv/reservations.ts +++ b/shared/src/i18n/sv/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Kryssning', 'reservations.type.event': 'Evenemang', 'reservations.type.tour': 'Rundtur', + 'reservations.type.parking': 'Parkering', 'reservations.type.other': 'Övrigt', 'reservations.type.bus': 'Buss', 'reservations.type.ferry': 'Färja', diff --git a/shared/src/i18n/tr/reservations.ts b/shared/src/i18n/tr/reservations.ts index a76414fc9..7233ed552 100644 --- a/shared/src/i18n/tr/reservations.ts +++ b/shared/src/i18n/tr/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Dolaşmak', 'reservations.type.event': 'Etkinlik', 'reservations.type.tour': 'Tur', + 'reservations.type.parking': 'Otopark', 'reservations.type.other': 'Diğer', 'reservations.type.bus': 'Otobüs', 'reservations.type.ferry': 'Feribot', diff --git a/shared/src/i18n/uk/reservations.ts b/shared/src/i18n/uk/reservations.ts index f3c484868..ba6c56334 100644 --- a/shared/src/i18n/uk/reservations.ts +++ b/shared/src/i18n/uk/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Круїз', 'reservations.type.event': 'Заходи', 'reservations.type.tour': 'Екскурсія', + 'reservations.type.parking': 'Паркування', 'reservations.type.other': 'Інше', 'reservations.type.bus': 'Автобус', 'reservations.type.ferry': 'Пором', diff --git a/shared/src/i18n/vi/reservations.ts b/shared/src/i18n/vi/reservations.ts index 0fe1a1586..8842c9929 100644 --- a/shared/src/i18n/vi/reservations.ts +++ b/shared/src/i18n/vi/reservations.ts @@ -59,6 +59,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': 'Du thuyền', 'reservations.type.event': 'Sự kiện', 'reservations.type.tour': 'Chuyến du lịch', + 'reservations.type.parking': 'Bãi đỗ xe', 'reservations.type.other': 'Khác', 'reservations.type.bus': 'xe buýt', 'reservations.type.ferry': 'Phà', diff --git a/shared/src/i18n/zh-TW/reservations.ts b/shared/src/i18n/zh-TW/reservations.ts index 18391b427..bab1ca046 100644 --- a/shared/src/i18n/zh-TW/reservations.ts +++ b/shared/src/i18n/zh-TW/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': '郵輪', 'reservations.type.event': '活動', 'reservations.type.tour': '旅遊團', + 'reservations.type.parking': '停車', 'reservations.type.other': '其他', 'reservations.type.bus': '公車', 'reservations.type.ferry': '渡輪', diff --git a/shared/src/i18n/zh/reservations.ts b/shared/src/i18n/zh/reservations.ts index d176d6588..d2cc86e7f 100644 --- a/shared/src/i18n/zh/reservations.ts +++ b/shared/src/i18n/zh/reservations.ts @@ -58,6 +58,7 @@ const reservations: TranslationStrings = { 'reservations.type.cruise': '邮轮', 'reservations.type.event': '活动', 'reservations.type.tour': '旅游团', + 'reservations.type.parking': '停车', 'reservations.type.other': '其他', 'reservations.type.bus': '公交车', 'reservations.type.ferry': '渡轮', diff --git a/wiki/Reservations-and-Bookings.md b/wiki/Reservations-and-Bookings.md index 1b765474c..e8b09981c 100644 --- a/wiki/Reservations-and-Bookings.md +++ b/wiki/Reservations-and-Bookings.md @@ -10,7 +10,7 @@ Open your trip in the planner and select the **Reservations** tab. The panel lis ## Reservation types -TREK supports nine reservation types: +TREK supports ten reservation types: | Type | How to create | |------|--------------| @@ -22,6 +22,7 @@ TREK supports nine reservation types: | Restaurant | Add button in Reservations panel | | Event | Add button in Reservations panel | | Tour | Add button in Reservations panel | +| Parking | Add button in Reservations panel — a fixed-location booking (e.g. airport parking) | | Other | Add button in Reservations panel | Transport types (Flight, Train, Car, Cruise) are created through the dedicated Transport modal, where you can enter endpoint and transit-specific fields. All other types are created directly from the Reservations panel. @@ -61,7 +62,7 @@ Each card displays: Click **Add** (or the + button) in the Reservations panel. Fill in the form: -1. **Type** — choose Hotel, Restaurant, Event, Tour, or Other +1. **Type** — choose Hotel, Restaurant, Event, Tour, Parking, or Other 2. **Title** — required 3. **Link to day-plan assignment** — optional; search across all days and places, grouped by day. Not available for Hotel type 4. **Start date and time** — not shown for Hotel type