From 1e44b25a0c6d1c2e99ef75de07685f69a6ff7830 Mon Sep 17 00:00:00 2001 From: micro92 Date: Thu, 2 Apr 2026 20:59:02 -0400 Subject: [PATCH] Add Accomodation to PDF --- client/src/components/PDF/TripPDF.tsx | 71 +++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/client/src/components/PDF/TripPDF.tsx b/client/src/components/PDF/TripPDF.tsx index c83cc4b..57412d2 100644 --- a/client/src/components/PDF/TripPDF.tsx +++ b/client/src/components/PDF/TripPDF.tsx @@ -2,7 +2,7 @@ import { createElement } from 'react' import { getCategoryIcon } from '../shared/categoryIcons' import { FileText, Info, Clock, MapPin, Navigation, Train, Plane, Bus, Car, Ship, Coffee, Ticket, Star, Heart, Camera, Flag, Lightbulb, AlertTriangle, ShoppingBag, Bookmark } from 'lucide-react' -import { mapsApi } from '../../api/client' +import { accommodationsApi, mapsApi } from '../../api/client' import type { Trip, Day, Place, Category, AssignmentsMap, DayNotesMap } from '../../types' const NOTE_ICON_MAP = { FileText, Info, Clock, MapPin, Navigation, Train, Plane, Bus, Car, Ship, Coffee, Ticket, Star, Heart, Camera, Flag, Lightbulb, AlertTriangle, ShoppingBag, Bookmark } @@ -115,6 +115,8 @@ export async function downloadTripPDF({ trip, days, places, assignments, categor const sorted = [...(days || [])].sort((a, b) => a.day_number - b.day_number) const range = longDateRange(sorted, loc) const coverImg = safeImg(trip?.cover_image) + //retrieve accomodations for the trip to display on the day sections and prefetch their photos if needed + const accomodations = await accommodationsApi.list(trip.id); // Pre-fetch place photos from Google const photoMap = await fetchPlacePhotos(assignments) @@ -223,7 +225,45 @@ export async function downloadTripPDF({ trip, days, places, assignments, categor ${place.notes ? `
${escHtml(place.notes)}
` : ''} ` - }).join('') + }).join('') + + const accomodationsForDay = accomodations.accommodations?.filter(a => + days.some(d => d.id >= a.start_day_id && d.id <= a.end_day_id && d.id === day?.id) + ).sort((a, b) => a.start_day_id - b.start_day_id); + + const accomodationDetails = accomodationsForDay.map(item => { + + const isCheckIn = day.id === item.start_day_id; + const isCheckOut = day.id === item.end_day_id; + const accomoAction = isCheckIn ? '🛎️ '+tr('reservations.meta.checkIn') + : isCheckOut ? '🧳 '+tr('reservations.meta.checkOut') + : '🏨 '+tr('reservations.meta.linkAccommodation') + + const accomoEmoji = isCheckIn ? '🛎️' + : isCheckOut ? '🧳' + : '' + + const accomoTime = isCheckIn ? item.check_in || 'N/A' + : isCheckOut ? item.check_out || 'N/A' + : '' + + return ` +
+
${escHtml(accomoAction)}
+ ${accomoTime ? `
${accomoEmoji} ${accomoTime}
` : ''} + +
🏨 ${escHtml(item.place_name)}
+ ${item.place_address ? `
📌 ${escHtml(item.place_address)}
` : ''} + ${item.notes ? `
📝 ${escHtml(item.notes)}
` : ''} + ${isCheckIn && item.confirmation ? `
🔑 ${escHtml(item.confirmation)}
` : ''} +
+ ` + }).join(''); + + const accomodationsHtml = accomodationDetails ? + `
+
${accomodationDetails}
+
` : ''; return `
@@ -233,8 +273,8 @@ export async function downloadTripPDF({ trip, days, places, assignments, categor ${day.date ? `${shortDate(day.date, loc)}` : ''} ${cost ? `${cost}` : ''}
-
${itemsHtml}
- ` +
${accomodationsHtml}${itemsHtml}
+ ` }).join('') const html = ` @@ -317,6 +357,29 @@ export async function downloadTripPDF({ trip, days, places, assignments, categor .day-cost { font-size: 9px; font-weight: 600; color: rgba(255,255,255,0.65); } .day-body { padding: 12px 28px 6px; } + /* Accomodation info */ + .day-accomodations-overview { font-size: 12px; } + .day-accomodations { display: flex; flex-direction: row; justify-content: space-between; } + .day-accomodations.single { justify-content: center; } + + .day-accomodation { + width: 50%; + margin:10px; + padding:10px; + border:2px solid #e2e8f0; + border-radius: 12px; + justify-content: center; + display: flex; + flex-direction: column; + } + + .day-accomodation-action { + font-size: 18px; + font-weight: 600; + text-align: center; + margin-bottom: 4px; + } + /* ── Place card ────────────────────────────────── */ .place-card { display: flex; align-items: stretch;