fix(pdf): include all trip days in PDF export
Fixed PDF export missing the last day when games occur on departure date. Root cause: Trip.itineraryDays() calculated lastActivityDate as departure - 1, assuming departure is always after the last activity. When games happen ON the departure date, that day was skipped. Fix: Check if the last stop has games. If so, include the departure date in the itinerary loop. Also includes: - buildCompleteItineraryItems() to merge games, travel, and custom items - Magazine-style PDF layout with sport-specific accent colors - Proper iteration over all trip days in PDF generator Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1199,7 +1199,14 @@ struct TripDetailView: View {
|
||||
exportProgress = nil
|
||||
|
||||
do {
|
||||
let url = try await exportService.exportToPDF(trip: trip, games: games) { progress in
|
||||
// Build complete itinerary items (games + travel + custom)
|
||||
let completeItems = buildCompleteItineraryItems()
|
||||
|
||||
let url = try await exportService.exportToPDF(
|
||||
trip: trip,
|
||||
games: games,
|
||||
itineraryItems: completeItems
|
||||
) { progress in
|
||||
await MainActor.run {
|
||||
self.exportProgress = progress
|
||||
}
|
||||
@@ -1213,6 +1220,57 @@ struct TripDetailView: View {
|
||||
isExporting = false
|
||||
}
|
||||
|
||||
/// Build complete itinerary items by merging games, travel, and custom items
|
||||
private func buildCompleteItineraryItems() -> [ItineraryItem] {
|
||||
var allItems: [ItineraryItem] = []
|
||||
|
||||
// Get itinerary days from trip
|
||||
let tripDays = trip.itineraryDays()
|
||||
|
||||
// 1. Add game items using day.gameIds (reliable source from trip stops)
|
||||
for day in tripDays {
|
||||
for (gameIndex, gameId) in day.gameIds.enumerated() {
|
||||
guard let richGame = games[gameId] else { continue }
|
||||
let gameItem = ItineraryItem(
|
||||
tripId: trip.id,
|
||||
day: day.dayNumber,
|
||||
sortOrder: Double(gameIndex) * 0.01, // Games near the start of the day
|
||||
kind: .game(gameId: gameId, city: richGame.stadium.city)
|
||||
)
|
||||
allItems.append(gameItem)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Add travel items (from trip segments + overrides)
|
||||
for segment in trip.travelSegments {
|
||||
let travelId = "travel:\(segment.fromLocation.name.lowercased())->\(segment.toLocation.name.lowercased())"
|
||||
|
||||
// Use override if available, otherwise default to day 1
|
||||
let override = travelOverrides[travelId]
|
||||
let day = override?.day ?? 1
|
||||
let sortOrder = override?.sortOrder ?? 100.0 // After games by default
|
||||
|
||||
let travelItem = ItineraryItem(
|
||||
tripId: trip.id,
|
||||
day: day,
|
||||
sortOrder: sortOrder,
|
||||
kind: .travel(TravelInfo(
|
||||
fromCity: segment.fromLocation.name,
|
||||
toCity: segment.toLocation.name,
|
||||
distanceMeters: segment.distanceMeters,
|
||||
durationSeconds: segment.durationSeconds
|
||||
))
|
||||
)
|
||||
allItems.append(travelItem)
|
||||
}
|
||||
|
||||
// 3. Add custom items (from CloudKit)
|
||||
let customItems = itineraryItems.filter { $0.isCustom }
|
||||
allItems.append(contentsOf: customItems)
|
||||
|
||||
return allItems
|
||||
}
|
||||
|
||||
private func toggleSaved() {
|
||||
if isSaved {
|
||||
unsaveTrip()
|
||||
|
||||
Reference in New Issue
Block a user