import SwiftUI struct TrainingPlanView: View { @StateObject private var viewModel = TrainingPlanViewModel() @State private var selectedType: PlanType? = nil @State private var selectedDifficulty: Difficulty? = nil @State private var showingGenerateSheet = false var body: some View { NavigationView { Group { if viewModel.isLoading && viewModel.plans.isEmpty { loadingView } else if viewModel.plans.isEmpty { emptyStateView } else { planListView } } .navigationTitle("Training Plans") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button { showingGenerateSheet = true } label: { Image(systemName: "plus") } } } .sheet(isPresented: $showingGenerateSheet) { GeneratePlanSheet() } } .onAppear { Task { await viewModel.fetchPlans() } } } private var planListView: some View { List { if selectedType != nil || selectedDifficulty != nil { Section("Filters") { HStack { Text("Type: \(selectedType?.displayName ?? "All")") .font(.caption) .foregroundColor(.secondary) Spacer() Text("Difficulty: \(selectedDifficulty?.displayName ?? "All")") .font(.caption) .foregroundColor(.secondary) } Button("Clear Filters") { selectedType = nil selectedDifficulty = nil Task { await viewModel.fetchPlans() } } } } Section("Plans") { ForEach(viewModel.plans) { plan in NavigationLink(destination: TrainingPlanDetailView(plan: plan)) { PlanRowView(plan: plan) } } } Section("Filter by Type") { ForEach(viewModel.planTypes, id: \.self) { type in Button(type.displayName) { selectedType = type Task { await viewModel.fetchPlans(type: type) } } .foregroundColor(type == selectedType ? .blue : .primary) } } Section("Filter by Difficulty") { ForEach(viewModel.difficulties, id: \.self) { difficulty in Button(difficulty.displayName) { selectedDifficulty = difficulty Task { await viewModel.fetchPlans(difficulty: difficulty) } } .foregroundColor(difficulty == selectedDifficulty ? .blue : .primary) } } } .listStyle(.insetGrouped) .refreshable { await viewModel.fetchPlans() } } private var loadingView: some View { VStack(spacing: 16) { ProgressView() Text("Loading Plans...") .font(.subheadline) .foregroundColor(.secondary) } .padding(.vertical, 60) } private var emptyStateView: some View { VStack(spacing: 16) { Image(systemName: "figure.run") .font(.system(size: 64)) .foregroundColor(.secondary) Text("No Training Plans") .font(.title2) .fontWeight(.semibold) Text("Start by generating a personalized plan or browse available plans.") .font(.subheadline) .foregroundColor(.secondary) .multilineTextAlignment(.center) .padding(.horizontal, 32) } .padding(.vertical, 60) } } struct GeneratePlanSheet: View { @Environment(\.dismiss) var dismiss @State private var planType: PlanType = .fiveK @State private var difficulty: Difficulty = .beginner @State private var weeklyMileage: String = "" @State private var goalTime: String = "" var body: some View { NavigationView { Form { Section("Plan Type") { Picker("Type", selection: $planType) { ForEach(PlanType.allCases, id: \.self) { type in Text(type.displayName).tag(type) } } } Section("Difficulty") { Picker("Difficulty", selection: $difficulty) { ForEach(Difficulty.allCases, id: \.self) { diff in Text(diff.displayName).tag(diff) } } } Section("Optional Details") { TextField("Current Weekly Mileage (km)", text: $weeklyMileage) .keyboardType(.decimalPad) TextField("Goal Time (minutes)", text: $goalTime) .keyboardType(.numberPad) } } .navigationTitle("Generate Plan") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("Cancel") { dismiss() } } ToolbarItem(placement: .navigationBarTrailing) { Button("Generate") { let request = GeneratePlanRequest( planType: planType, difficulty: difficulty, startDate: Date(), currentWeeklyMileageKm: Double(weeklyMileage), goalTimeMinutes: Int(goalTime), availableDays: [.monday, .wednesday, .friday, .saturday] ) dismiss() } } } } } } struct PlanRowView: View { let plan: TrainingPlan var body: some View { HStack(spacing: 12) { Image(systemName: plan.planType.icon) .font(.system(size: 28)) .foregroundColor(plan.difficulty.color) .frame(width: 44, height: 44) .background(plan.difficulty.color.opacity(0.15)) .cornerRadius(10) VStack(alignment: .leading, spacing: 4) { Text(plan.title) .font(.headline) Text("\(plan.planType.displayName) \u2022 \(plan.durationWeeks) weeks \u2022 \(plan.difficulty.displayName)") .font(.subheadline) .foregroundColor(.secondary) ProgressView(value: plan.progress.percentage) .tint(.blue) .scaleEffect(y: 0.5) .padding(.vertical, -4) } Spacer() if plan.isFollowing { Image(systemName: "checkmark.circle.fill") .foregroundColor(.green) } } .padding(.vertical, 4) } } #Preview { TrainingPlanView() }