import SwiftUI struct RoutesListView: View { @State private var routes: [RouteListItem] = [] @State private var isLoading = false @State private var errorMessage: String? var body: some View { NavigationStack { content .navigationTitle("Touren") .task { await load() } } } @ViewBuilder private var content: some View { if isLoading && routes.isEmpty { ProgressView() } else if let error = errorMessage, routes.isEmpty { ContentUnavailableView( "Konnte Touren nicht laden", systemImage: "wifi.slash", description: Text(error) ) } else if routes.isEmpty { ContentUnavailableView( "Keine Touren", systemImage: "map", description: Text("Lege deine erste Gassi-Tour in der PWA an — oder warte auf Phase 2.") ) } else { List(routes) { route in NavigationLink { RouteDetailView(routeId: route.id, fallbackName: route.name) } label: { RouteRowView(route: route) } } .refreshable { await load() } } } private func load() async { isLoading = true errorMessage = nil defer { isLoading = false } do { routes = try await APIClient.shared.get("/api/routes") } catch { errorMessage = error.localizedDescription } } } struct RouteRowView: View { let route: RouteListItem var body: some View { VStack(alignment: .leading, spacing: 8) { HStack { Text(route.name) .font(.headline) Spacer() if let km = route.distanzKm { Text(String(format: "%.1f km", km)) .font(.subheadline.monospacedDigit()) .foregroundStyle(.secondary) } } HStack(spacing: 12) { if let mins = route.dauerMin { Label("\(mins) min", systemImage: "clock") } if let date = route.createdAt { Text(DateUtil.format(date)) } Spacer() } .font(.caption) .foregroundStyle(.secondary) if route.previewTrack.count >= 2 { MiniRouteMap(track: route.previewTrack) .frame(height: 110) .clipShape(RoundedRectangle(cornerRadius: 10)) } } .padding(.vertical, 4) } } enum DateUtil { /// Parses backend timestamps (SQLite `YYYY-MM-DD HH:MM:SS` or ISO-8601) /// into a German short date. static func format(_ input: String) -> String { let parser = DateFormatter() parser.locale = Locale(identifier: "en_US_POSIX") parser.timeZone = TimeZone(identifier: "UTC") for format in ["yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ssZ"] { parser.dateFormat = format if let date = parser.date(from: input) { let out = DateFormatter() out.locale = Locale(identifier: "de_DE") out.dateStyle = .medium return out.string(from: date) } } return String(input.prefix(10)) } }