// // RegionMapSelector.swift // SportsTime // // Interactive map for selecting travel regions. // import SwiftUI /// A map-based selector for choosing geographic regions. /// Shows North America with three selectable zones: West, Central, East. /// /// Selection rules: /// - Can select: East, Central, West, East+Central, Central+West /// - Cannot select: East+West (must have Central between them) struct RegionMapSelector: View { @Binding var selectedRegions: Set let onToggle: (Region) -> Void @Environment(\.colorScheme) private var colorScheme var body: some View { VStack(spacing: Theme.Spacing.sm) { // Map with regions GeometryReader { geometry in ZStack { // Background map outline mapBackground // Selectable regions HStack(spacing: 0) { regionButton(.west) regionButton(.central) regionButton(.east) } } } .frame(height: 140) .clipShape(RoundedRectangle(cornerRadius: Theme.CornerRadius.medium)) .overlay( RoundedRectangle(cornerRadius: Theme.CornerRadius.medium) .stroke(Theme.textMuted(colorScheme).opacity(0.5), lineWidth: 1) ) // Legend selectionLegend } } // MARK: - Map Background private var mapBackground: some View { ZStack { // Simple gradient background representing land LinearGradient( colors: [ Color.green.opacity(0.15), Color.green.opacity(0.1), Color.green.opacity(0.15) ], startPoint: .leading, endPoint: .trailing ) // Subtle grid lines for visual separation HStack(spacing: 0) { Color.clear .frame(maxWidth: .infinity) Rectangle() .fill(Theme.textMuted(colorScheme).opacity(0.3)) .frame(width: 1) Color.clear .frame(maxWidth: .infinity) Rectangle() .fill(Theme.textMuted(colorScheme).opacity(0.3)) .frame(width: 1) Color.clear .frame(maxWidth: .infinity) } } } // MARK: - Region Button private func regionButton(_ region: Region) -> some View { let isSelected = selectedRegions.contains(region) let isDisabled = isRegionDisabled(region) return Button { onToggle(region) } label: { VStack(spacing: Theme.Spacing.xs) { // Region icon Image(systemName: iconForRegion(region)) .font(.system(size: 24)) .foregroundStyle(isSelected ? .white : Theme.textSecondary(colorScheme)) // Region name Text(region.shortName) .font(.system(size: Theme.FontSize.caption, weight: .semibold)) .foregroundStyle(isSelected ? .white : Theme.textPrimary(colorScheme)) // Cities hint Text(citiesForRegion(region)) .font(.system(size: Theme.FontSize.micro)) .foregroundStyle(isSelected ? .white.opacity(0.8) : Theme.textMuted(colorScheme)) .lineLimit(2) .multilineTextAlignment(.center) } .frame(maxWidth: .infinity, maxHeight: .infinity) .background( isSelected ? regionColor(region) : Color.clear ) .opacity(isDisabled ? 0.4 : 1.0) } .buttonStyle(.plain) .disabled(isDisabled) } // MARK: - Helpers private func iconForRegion(_ region: Region) -> String { switch region { case .west: return "sun.max.fill" case .central: return "building.2.fill" case .east: return "building.columns.fill" case .crossCountry: return "arrow.left.arrow.right" } } private func citiesForRegion(_ region: Region) -> String { switch region { case .west: return "LA, SF, Seattle" case .central: return "Chicago, Houston, Denver" case .east: return "NYC, Boston, Miami" case .crossCountry: return "" } } private func regionColor(_ region: Region) -> Color { switch region { case .west: return .orange case .central: return .blue case .east: return .green case .crossCountry: return .purple } } /// East and West cannot both be selected (not adjacent) private func isRegionDisabled(_ region: Region) -> Bool { // If trying to show East+West as disabled, we handle that in toggle logic instead // This is for visual indication only return false } // MARK: - Legend private var selectionLegend: some View { HStack(spacing: Theme.Spacing.md) { if selectedRegions.isEmpty { Text("Tap regions to select") .font(.system(size: Theme.FontSize.micro)) .foregroundStyle(Theme.textMuted(colorScheme)) } else { Text("Selected: \(selectedRegions.map { $0.shortName }.sorted().joined(separator: " + "))") .font(.system(size: Theme.FontSize.caption, weight: .medium)) .foregroundStyle(Theme.textPrimary(colorScheme)) Spacer() Button { selectedRegions.removeAll() } label: { Text("Clear") .font(.system(size: Theme.FontSize.micro)) .foregroundStyle(Theme.warmOrange) } } } } } #Preview { struct PreviewWrapper: View { @State private var selected: Set = [.central] var body: some View { VStack(spacing: 20) { RegionMapSelector(selectedRegions: $selected) { region in if selected.contains(region) { selected.remove(region) } else { // Adjacency rule if region == .east { selected.remove(.west) } else if region == .west { selected.remove(.east) } selected.insert(region) } } .padding() Text("Selected: \(selected.map { $0.shortName }.joined(separator: ", "))") } .padding() } } return PreviewWrapper() }