import SwiftUI struct ClubsView: View { @StateObject private var viewModel = ClubViewModel() @State private var showingCreateSheet = false @State private var selectedTab: ClubTab = .discover enum ClubTab: String, CaseIterable { case discover, myClubs } var body: some View { NavigationView { Group { if viewModel.isLoading && viewModel.clubs.isEmpty { loadingView } else if currentClubs.isEmpty { emptyStateView } else { clubListView } } .navigationTitle("Clubs") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button { showingCreateSheet = true } label: { Image(systemName: "plus") } } } .sheet(isPresented: $showingCreateSheet) { CreateClubSheet() } } .onAppear { Task { await viewModel.fetchClubs() } } } private var currentClubs: [Club] { switch selectedTab { case .discover: return viewModel.publicClubs case .myClubs: return viewModel.userClubs } } private var clubListView: some View { List { Picker("Clubs", selection: $selectedTab) { ForEach(ClubTab.allCases, id: \.self) { tab in Text(tab.rawValue.capitalized).tag(tab) } } .pickerStyle(.segmented) .padding(.top, 8) Section(currentSectionTitle) { ForEach(currentClubs) { club in NavigationLink(destination: ClubDetailView(club: club)) { ClubRowView(club: club) } } } } .listStyle(.insetGrouped) .refreshable { await viewModel.fetchClubs() } } private var currentSectionTitle: String { switch selectedTab { case .discover: return "Discover Clubs" case .myClubs: return "My Clubs" } } private var loadingView: some View { VStack(spacing: 16) { ProgressView() Text("Loading Clubs...") .font(.subheadline) .foregroundColor(.secondary) } .padding(.vertical, 60) } private var emptyStateView: some View { VStack(spacing: 16) { Image(systemName: "person.3.fill") .font(.system(size: 64)) .foregroundColor(.secondary) Text("No \(selectedTab.rawValue) Clubs") .font(.title2) .fontWeight(.semibold) Text(selectedTab == .discover ? "Find running and fitness clubs in your area." : "Join or create a club to get started.") .font(.subheadline) .foregroundColor(.secondary) .multilineTextAlignment(.center) .padding(.horizontal, 32) } .padding(.vertical, 60) } } struct CreateClubSheet: View { @Environment(\.dismiss) var dismiss @State private var name = "" @State private var description = "" @State private var clubType: ClubType = .running @State private var privacy: ClubPrivacy = .publicPrivacy @State private var location = "" @State private var maxMembers = "" @State private var rules = "" var body: some View { NavigationView { Form { Section("Club Details") { TextField("Club Name", text: $name) TextField("Description", text: $description) TextField("Location", text: $location) } Section("Type & Privacy") { Picker("Club Type", selection: $clubType) { ForEach(ClubType.allCases, id: \.self) { type in Text(type.displayName).tag(type) } } Picker("Privacy", selection: $privacy) { ForEach(ClubPrivacy.allCases, id: \.self) { priv in Text(priv.displayName).tag(priv) } } } Section("Optional") { TextField("Max Members", text: $maxMembers) .keyboardType(.numberPad) TextField("Rules", text: $rules) } } .navigationTitle("Create Club") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("Cancel") { dismiss() } } ToolbarItem(placement: .navigationBarTrailing) { Button("Create") { let request = CreateClubRequest( name: name, description: description, clubType: clubType, privacy: privacy, location: location, latitude: nil, longitude: nil, maxMembers: Int(maxMembers), rules: rules.isEmpty ? nil : rules ) dismiss() } .disabled(name.isEmpty || location.isEmpty) } } } } } struct ClubRowView: View { let club: Club var body: some View { HStack(spacing: 12) { Image(systemName: club.clubType.icon) .font(.system(size: 24)) .foregroundColor(club.clubType.color) .frame(width: 44, height: 44) .background(club.clubType.color.opacity(0.15)) .cornerRadius(10) VStack(alignment: .leading, spacing: 4) { Text(club.name) .font(.headline) Text("\(club.location) \u2022 \(club.privacy.displayName)") .font(.subheadline) .foregroundColor(.secondary) HStack(spacing: 8) { Text("\(club.memberCount) members") .font(.caption) .foregroundColor(.secondary) if let spots = club.availableSpots, spots > 0 { Text("\(spots) spots left") .font(.caption2) .foregroundColor(.green) } } } Spacer() switch club.membershipStatus { case .active: Image(systemName: "checkmark.circle.fill") .foregroundColor(.green) case .pending: Image(systemName: "clock.fill") .foregroundColor(.orange) case .invited: Image(systemName: "mail.fill") .foregroundColor(.blue) case .left: Image(systemName: "circle") .foregroundColor(.secondary) } } .padding(.vertical, 4) } } #Preview { ClubsView() }