import SwiftUI import SwiftData struct GamesHistoryView: View { @Environment(\.modelContext) private var modelContext @State private var viewModel: GamesHistoryViewModel? @State private var selectedVisit: StadiumVisit? var body: some View { Group { if let viewModel { GamesHistoryContent( viewModel: viewModel, selectedVisit: $selectedVisit ) } else { LoadingSpinner(size: .medium, label: "Loading games...") } } .navigationTitle("Games Attended") .sheet(item: $selectedVisit, onDismiss: { // Refresh data after sheet closes (handles deletion case) Task { await viewModel?.loadGames() } }) { visit in if let stadium = AppDataProvider.shared.stadium(for: visit.stadiumId) { VisitDetailView(visit: visit, stadium: stadium) } } .task { if viewModel == nil { let vm = GamesHistoryViewModel(modelContext: modelContext) await vm.loadGames() viewModel = vm } } } } private struct GamesHistoryContent: View { @Environment(\.colorScheme) private var colorScheme @Bindable var viewModel: GamesHistoryViewModel @Binding var selectedVisit: StadiumVisit? var body: some View { VStack(spacing: 0) { // Header with count and filters VStack(spacing: 12) { // Total count HStack { Text("\(viewModel.totalGamesCount) Games") .font(.headline) .foregroundStyle(Theme.textPrimary(colorScheme)) Spacer() if !viewModel.selectedSports.isEmpty { Button("Clear") { viewModel.clearFilters() } .font(.caption) .accessibilityHint("Clear all sport filters") } } // Sport filter chips SportFilterChips( selectedSports: viewModel.selectedSports, onToggle: viewModel.toggleSport ) } .padding() .background(Theme.cardBackground(colorScheme)) Divider() .overlay(Theme.surfaceGlow(colorScheme)) // Games list grouped by year if viewModel.filteredVisits.isEmpty { EmptyGamesView() } else { GamesListByYear( visitsByYear: viewModel.visitsByYear, sortedYears: viewModel.sortedYears, onSelect: { visit in selectedVisit = visit } ) } } .background(Theme.backgroundGradient(colorScheme)) } } private struct SportFilterChips: View { let selectedSports: Set let onToggle: (Sport) -> Void private let sports: [Sport] = [.mlb, .nba, .nhl] var body: some View { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 8) { ForEach(sports, id: \.self) { sport in SportChip( sport: sport, isSelected: selectedSports.contains(sport), onTap: { onToggle(sport) } ) } } } } } private struct SportChip: View { @Environment(\.colorScheme) private var colorScheme let sport: Sport let isSelected: Bool let onTap: () -> Void var body: some View { Button(action: onTap) { HStack(spacing: 4) { Image(systemName: sportIcon) .font(.caption) .accessibilityHidden(true) Text(sport.rawValue) .font(.caption.bold()) } .foregroundStyle(isSelected ? .white : Theme.textPrimary(colorScheme)) .padding(.horizontal, 12) .padding(.vertical, 6) .background( Capsule() .fill(isSelected ? sport.themeColor : Theme.cardBackgroundElevated(colorScheme)) ) } .buttonStyle(.plain) .accessibilityValue(isSelected ? "Selected" : "Not selected") .accessibilityAddTraits(isSelected ? .isSelected : []) } private var sportIcon: String { switch sport { case .mlb: return "baseball" case .nba: return "basketball" case .nhl: return "hockey.puck" case .nfl: return "football" case .mls: return "soccerball" case .wnba: return "basketball" case .nwsl: return "soccerball" } } } private struct GamesListByYear: View { let visitsByYear: [Int: [StadiumVisit]] let sortedYears: [Int] let onSelect: (StadiumVisit) -> Void var body: some View { ScrollView { LazyVStack(spacing: 0, pinnedViews: .sectionHeaders) { ForEach(sortedYears, id: \.self) { year in Section { VStack(spacing: 8) { ForEach(visitsByYear[year] ?? [], id: \.id) { visit in Button { onSelect(visit) } label: { GamesHistoryRow( visit: visit, stadium: AppDataProvider.shared.stadium(for: visit.stadiumId) ) } .buttonStyle(.plain) } } .padding(.horizontal) .padding(.vertical, 8) } header: { YearHeader(year: year) } } } } } } private struct YearHeader: View { @Environment(\.colorScheme) private var colorScheme let year: Int var body: some View { HStack { Text(String(year)) .font(.title3.bold()) .foregroundStyle(Theme.textPrimary(colorScheme)) Spacer() } .padding(.horizontal) .padding(.vertical, 8) .background(Theme.backgroundGradient(colorScheme)) } } private struct EmptyGamesView: View { @Environment(\.colorScheme) private var colorScheme var body: some View { VStack(spacing: 16) { Image(systemName: "ticket") .font(.largeTitle) .foregroundStyle(Theme.textMuted(colorScheme)) Text("No games recorded yet") .font(.headline) .foregroundStyle(Theme.textPrimary(colorScheme)) Text("Add your first stadium visit to see it here!") .font(.subheadline) .foregroundStyle(Theme.textSecondary(colorScheme)) .multilineTextAlignment(.center) } .frame(maxWidth: .infinity, maxHeight: .infinity) .padding() } }