feat: rewrite bootstrap, fix CloudKit sync, update canonical data, and UI fixes
- Rewrite BootstrapService: remove all legacy code paths (JSONStadium, JSONGame, bootstrapStadiumsLegacy, bootstrapGamesLegacy, venue aliases, createDefaultLeagueStructure), require canonical JSON files only - Add clearCanonicalData() to handle partial bootstrap recovery (prevents duplicate key crashes from interrupted first-launch) - Fix nullable stadium_canonical_id in games (4 MLS games have null) - Fix CKModels: logoUrl case, conference/division field keys - Fix CanonicalSyncService: sync conferenceCanonicalId/divisionCanonicalId - Add sports_canonical.json and DemoMode.swift - Delete legacy stadiums.json and games.json - Update all canonical resource JSON files with latest data - Fix TripWizardView horizontal scrolling with GeometryReader constraint - Update RegionMapSelector, TripDetailView, TripOptionsView UI improvements - Add DateRangePicker, PlanningModeStep, SportsStep enhancements - Update UI tests and marketing-videos config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,8 @@ struct RegionMapSelector: View {
|
||||
let onToggle: (Region) -> Void
|
||||
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
@Environment(\.isDemoMode) private var isDemoMode
|
||||
@State private var hasAppliedDemoSelection = false
|
||||
|
||||
// Camera position centered on continental US
|
||||
@State private var cameraPosition: MapCameraPosition = .camera(
|
||||
@@ -33,29 +35,44 @@ struct RegionMapSelector: View {
|
||||
var body: some View {
|
||||
VStack(spacing: Theme.Spacing.sm) {
|
||||
// Map with region overlays
|
||||
MapReader { proxy in
|
||||
Map(position: $cameraPosition, interactionModes: []) {
|
||||
// West region polygon
|
||||
MapPolygon(coordinates: RegionCoordinates.west)
|
||||
.foregroundStyle(fillColor(for: .west))
|
||||
.stroke(strokeColor(for: .west), lineWidth: strokeWidth(for: .west))
|
||||
ZStack {
|
||||
MapReader { proxy in
|
||||
Map(position: $cameraPosition, interactionModes: []) {
|
||||
// West region polygon
|
||||
MapPolygon(coordinates: RegionCoordinates.west)
|
||||
.foregroundStyle(fillColor(for: .west))
|
||||
.stroke(strokeColor(for: .west), lineWidth: strokeWidth(for: .west))
|
||||
|
||||
// Central region polygon
|
||||
MapPolygon(coordinates: RegionCoordinates.central)
|
||||
.foregroundStyle(fillColor(for: .central))
|
||||
.stroke(strokeColor(for: .central), lineWidth: strokeWidth(for: .central))
|
||||
// Central region polygon
|
||||
MapPolygon(coordinates: RegionCoordinates.central)
|
||||
.foregroundStyle(fillColor(for: .central))
|
||||
.stroke(strokeColor(for: .central), lineWidth: strokeWidth(for: .central))
|
||||
|
||||
// East region polygon
|
||||
MapPolygon(coordinates: RegionCoordinates.east)
|
||||
.foregroundStyle(fillColor(for: .east))
|
||||
.stroke(strokeColor(for: .east), lineWidth: strokeWidth(for: .east))
|
||||
}
|
||||
.mapStyle(.standard(elevation: .flat, pointsOfInterest: .excludingAll))
|
||||
.onTapGesture { location in
|
||||
if let coordinate = proxy.convert(location, from: .local) {
|
||||
let tappedRegion = regionForCoordinate(coordinate)
|
||||
onToggle(tappedRegion)
|
||||
// East region polygon
|
||||
MapPolygon(coordinates: RegionCoordinates.east)
|
||||
.foregroundStyle(fillColor(for: .east))
|
||||
.stroke(strokeColor(for: .east), lineWidth: strokeWidth(for: .east))
|
||||
}
|
||||
.mapStyle(.standard(elevation: .flat, pointsOfInterest: .excludingAll))
|
||||
.onTapGesture { location in
|
||||
if let coordinate = proxy.convert(location, from: .local) {
|
||||
let tappedRegion = regionForCoordinate(coordinate)
|
||||
onToggle(tappedRegion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invisible button overlays for UI testing accessibility
|
||||
HStack(spacing: 0) {
|
||||
Button { onToggle(.west) } label: { Color.clear }
|
||||
.accessibilityIdentifier("wizard.regions.west")
|
||||
.frame(maxWidth: .infinity)
|
||||
Button { onToggle(.central) } label: { Color.clear }
|
||||
.accessibilityIdentifier("wizard.regions.central")
|
||||
.frame(maxWidth: .infinity)
|
||||
Button { onToggle(.east) } label: { Color.clear }
|
||||
.accessibilityIdentifier("wizard.regions.east")
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.frame(height: 160)
|
||||
@@ -71,6 +88,14 @@ struct RegionMapSelector: View {
|
||||
// Selection footer
|
||||
selectionFooter
|
||||
}
|
||||
.onAppear {
|
||||
if isDemoMode && !hasAppliedDemoSelection && selectedRegions.isEmpty {
|
||||
hasAppliedDemoSelection = true
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + DemoConfig.selectionDelay) {
|
||||
onToggle(DemoConfig.demoRegion)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Coordinate to Region
|
||||
|
||||
Reference in New Issue
Block a user