import SwiftUI struct ClubDetailView: View { let club: Club @StateObject private var viewModel = ClubViewModel() @State private var inviteEmail = "" @State private var showingInviteAlert = false var body: some View { ScrollView { VStack(alignment: .leading, spacing: 16) { clubHeader clubInfoSection clubDescription membershipSection rulesSection membersSection } .padding(.horizontal) .padding(.bottom, 32) } .navigationTitle(club.name) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { if club.membershipStatus == .active { Menu { Button("Edit Club") {} Button("Leave Club", role: .destructive) { Task { await viewModel.leaveClub(id: club.id) } } } label: { Image(systemName: "ellipsis.circle") } } } } .onAppear { Task { await viewModel.selectClub(id: club.id) } } } private var clubHeader: some View { VStack(spacing: 12) { HStack { Image(systemName: club.clubType.icon) .font(.system(size: 40)) .foregroundColor(club.clubType.color) VStack(alignment: .leading, spacing: 4) { Text(club.clubType.displayName) .font(.title2) .fontWeight(.bold) Text(club.location) .font(.subheadline) .foregroundColor(.secondary) } Spacer() } Divider() HStack(spacing: 20) { infoItem(label: "Members", value: "\(club.memberCount)") infoItem(label: "Privacy", value: club.privacy.displayName) infoItem(label: "Owner", value: club.ownerName) } } .padding() .background(Color.secondary.opacity(0.1)) .cornerRadius(12) } private func infoItem(label: String, value: String) -> some View { VStack(alignment: .leading, spacing: 2) { Text(label) .font(.caption) .foregroundColor(.secondary) Text(value) .font(.subheadline) .fontWeight(.medium) } } private var clubInfoSection: some View { VStack(alignment: .leading, spacing: 8) { Text("Club Details") .font(.headline) VStack(alignment: .leading, spacing: 6) { detailRow(label: "Type", value: club.clubType.displayName) detailRow(label: "Privacy", value: club.privacy.displayName) detailRow(label: "Location", value: club.location) if let max = club.maxMembers { detailRow(label: "Capacity", value: "\(club.memberCount)/\(max)") } detailRow(label: "Joined", value: formatDate(club.createdAt)) } } } private func detailRow(label: String, value: String) -> some View { HStack { Text(label) .font(.subheadline) .foregroundColor(.secondary) .frame(width: 100, alignment: .leading) Text(value) .font(.subheadline) .fontWeight(.medium) } } private var clubDescription: some View { VStack(alignment: .leading, spacing: 4) { Text("About This Club") .font(.headline) Text(club.description) .font(.subheadline) .foregroundColor(.secondary) } } private var membershipSection: some View { VStack(alignment: .leading, spacing: 12) { Text("Membership") .font(.headline) HStack(spacing: 12) { switch club.membershipStatus { case .active: Button { Task { await viewModel.leaveClub(id: club.id) } } label: { Label("Leave Club", systemImage: "door.left.hand.open") .foregroundColor(.red) } .frame(maxWidth: .infinity) .padding(.vertical, 8) .background(Color.red.opacity(0.15)) .cornerRadius(8) case .pending: Label("Joining...", systemImage: "clock.fill") .foregroundColor(.orange) .frame(maxWidth: .infinity) .padding(.vertical, 8) .background(Color.orange.opacity(0.15)) .cornerRadius(8) case .invited: Button { Task { await viewModel.joinClub(id: club.id) } } label: { Label("Accept Invite", systemImage: "checkmark.circle.fill") .foregroundColor(.green) } .frame(maxWidth: .infinity) .padding(.vertical, 8) .background(Color.green.opacity(0.15)) .cornerRadius(8) case .left: Button { Task { await viewModel.joinClub(id: club.id) } } label: { Label("Rejoin Club", systemImage: "arrow.turn.down.right") .foregroundColor(.blue) } .frame(maxWidth: .infinity) .padding(.vertical, 8) .background(Color.blue.opacity(0.15)) .cornerRadius(8) } if club.membershipStatus == .active { Button { showingInviteAlert = true } label: { Label("Invite", systemImage: "person.crop.circle.badge.plus") .foregroundColor(.blue) } .frame(maxWidth: .infinity) .padding(.vertical, 8) .background(Color.blue.opacity(0.15)) .cornerRadius(8) } } } } } private var rulesSection: some View { VStack(alignment: .leading, spacing: 4) { Text("Club Rules") .font(.headline) if let rules = club.rules { Text(rules) .font(.subheadline) .foregroundColor(.secondary) } else { Text("No rules specified.") .font(.subheadline) .foregroundColor(.secondary) } } } private var membersSection: some View { VStack(alignment: .leading, spacing: 8) { Text("Members (\(club.memberCount))") .font(.headline) ForEach(viewModel.members) { member in HStack(spacing: 12) { Circle() .fill(Color.secondary.opacity(0.2)) .frame(width: 32, height: 32) VStack(alignment: .leading, spacing: 2) { Text(member.name) .font(.subheadline) Text(member.role.displayName) .font(.caption) .foregroundColor(.secondary) } Spacer() Text(member.membershipStatus.rawValue.capitalized) .font(.caption) .foregroundColor(member.membershipStatus == .active ? .green : .secondary) } } } } private func formatDate(_ date: Date) -> String { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .none return formatter.string(from: date) } } #Preview { NavigationView { ClubDetailView(club: sampleClub) } } private var sampleClub: Club { Club( id: "1", name: "Central Park Runners", description: "A friendly running club that meets every weekend in Central Park. All levels welcome!", clubType: .running, privacy: .publicPrivacy, location: "Central Park, NYC", latitude: 40.7851, longitude: -73.9683, memberCount: 142, maxMembers: 200, imageUrl: nil, rules: "Be respectful, stay hydrated, and have fun!", ownerId: "user1", ownerName: "Alex Johnson", membershipStatus: .active, createdAt: Date().addingTimeInterval(-30 * 24 * 3600) ) }