import SwiftUI struct AddEditGymView: View { let gymId: UUID? @EnvironmentObject var dataManager: ClimbingDataManager @Environment(\.dismiss) private var dismiss @State private var name = "" @State private var location = "" @State private var notes = "" @State private var selectedClimbTypes = Set() @State private var selectedDifficultySystems = Set() @State private var customDifficultyGrades: [String] = [] @State private var isEditing = false private var existingGym: Gym? { guard let gymId = gymId else { return nil } return dataManager.gym(withId: gymId) } private var availableDifficultySystems: [DifficultySystem] { if selectedClimbTypes.isEmpty { return [] } else { return selectedClimbTypes.flatMap { climbType in DifficultySystem.systemsForClimbType(climbType) }.removingDuplicates() } } init(gymId: UUID? = nil) { self.gymId = gymId } var body: some View { NavigationView { Form { BasicInfoSection() ClimbTypesSection() DifficultySystemsSection() NotesSection() } .navigationTitle(isEditing ? "Edit Gym" : "Add Gym") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("Cancel") { dismiss() } } ToolbarItem(placement: .navigationBarTrailing) { Button("Save") { saveGym() } .disabled(!canSave) } } } .onAppear { loadExistingGym() } .onChange(of: selectedClimbTypes) { updateAvailableDifficultySystems() } } @ViewBuilder private func BasicInfoSection() -> some View { Section("Basic Information") { TextField("Gym Name", text: $name) TextField("Location (Optional)", text: $location) } } @ViewBuilder private func ClimbTypesSection() -> some View { Section("Supported Climb Types") { ForEach(ClimbType.allCases, id: \.self) { climbType in HStack { Text(climbType.displayName) Spacer() if selectedClimbTypes.contains(climbType) { Image(systemName: "checkmark.circle.fill") .foregroundColor(.blue) } else { Image(systemName: "circle") .foregroundColor(.gray) } } .contentShape(Rectangle()) .onTapGesture { if selectedClimbTypes.contains(climbType) { selectedClimbTypes.remove(climbType) } else { selectedClimbTypes.insert(climbType) } } } } } @ViewBuilder private func DifficultySystemsSection() -> some View { Section("Difficulty Systems") { if selectedClimbTypes.isEmpty { Text("Select climb types first to see available difficulty systems") .foregroundColor(.secondary) .font(.caption) } else { ForEach(availableDifficultySystems, id: \.self) { system in HStack { Text(system.displayName) Spacer() if selectedDifficultySystems.contains(system) { Image(systemName: "checkmark.circle.fill") .foregroundColor(.blue) } else { Image(systemName: "circle") .foregroundColor(.gray) } } .contentShape(Rectangle()) .onTapGesture { if selectedDifficultySystems.contains(system) { selectedDifficultySystems.remove(system) } else { selectedDifficultySystems.insert(system) } } } } } } @ViewBuilder private func NotesSection() -> some View { Section("Notes (Optional)") { TextEditor(text: $notes) .frame(minHeight: 100) } } private var canSave: Bool { !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !selectedClimbTypes.isEmpty && !selectedDifficultySystems.isEmpty } private func loadExistingGym() { if let gym = existingGym { isEditing = true name = gym.name location = gym.location ?? "" notes = gym.notes ?? "" selectedClimbTypes = Set(gym.supportedClimbTypes) selectedDifficultySystems = Set(gym.difficultySystems) customDifficultyGrades = gym.customDifficultyGrades } } private func updateAvailableDifficultySystems() { // Remove selected systems that are no longer available let availableSet = Set(availableDifficultySystems) selectedDifficultySystems = selectedDifficultySystems.intersection(availableSet) } private func saveGym() { let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) let trimmedLocation = location.trimmingCharacters(in: .whitespacesAndNewlines) let trimmedNotes = notes.trimmingCharacters(in: .whitespacesAndNewlines) if isEditing, let gym = existingGym { let updatedGym = gym.updated( name: trimmedName, location: trimmedLocation.isEmpty ? nil : trimmedLocation, supportedClimbTypes: Array(selectedClimbTypes), difficultySystems: Array(selectedDifficultySystems), customDifficultyGrades: customDifficultyGrades, notes: trimmedNotes.isEmpty ? nil : trimmedNotes ) dataManager.updateGym(updatedGym) } else { let newGym = Gym( name: trimmedName, location: trimmedLocation.isEmpty ? nil : trimmedLocation, supportedClimbTypes: Array(selectedClimbTypes), difficultySystems: Array(selectedDifficultySystems), customDifficultyGrades: customDifficultyGrades, notes: trimmedNotes.isEmpty ? nil : trimmedNotes ) dataManager.addGym(newGym) } dismiss() } } extension Array where Element: Hashable { func removingDuplicates() -> [Element] { var seen = Set() return filter { seen.insert($0).inserted } } } #Preview { AddEditGymView() .environmentObject(ClimbingDataManager.preview) }