fix: resolve specificStadium achievement ID mismatch
The Green Monster (Fenway) and Ivy League (Wrigley) achievements weren't working because: 1. Symbolic IDs use lowercase sport (stadium_mlb_bos) 2. Sport enum uses uppercase raw values (MLB) 3. Visits store stadium UUIDs, not symbolic IDs Added resolveSymbolicStadiumId() helper that: - Uppercases the sport string before Sport(rawValue:) - Looks up team by abbreviation and sport - Returns the team's stadiumId as UUID string Also fixed: - getStadiumIdsForLeague returns UUID strings (not symbolic IDs) - AchievementProgress.isEarned computed from progress OR stored record - getStadiumIdsForDivision queries CanonicalTeam properly Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,8 @@ struct StadiumVisitSheet: View {
|
||||
// UI state
|
||||
@State private var showStadiumPicker = false
|
||||
@State private var isSaving = false
|
||||
@State private var isLookingUpGame = false
|
||||
@State private var scoreFromScraper = false // Track if score was auto-filled
|
||||
@State private var errorMessage: String?
|
||||
@State private var showAwayTeamSuggestions = false
|
||||
@State private var showHomeTeamSuggestions = false
|
||||
@@ -220,10 +222,36 @@ struct StadiumVisitSheet: View {
|
||||
.frame(width: 50)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
// Look Up Game Button
|
||||
if selectedStadium != nil {
|
||||
Button {
|
||||
Task {
|
||||
await lookUpGame()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
if isLookingUpGame {
|
||||
ProgressView()
|
||||
.scaleEffect(0.8)
|
||||
} else {
|
||||
Image(systemName: "magnifyingglass")
|
||||
}
|
||||
Text("Look Up Game")
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.foregroundStyle(Theme.warmOrange)
|
||||
}
|
||||
.disabled(isLookingUpGame)
|
||||
}
|
||||
} header: {
|
||||
Text("Game Info")
|
||||
} footer: {
|
||||
Text("Leave blank if you don't remember the score")
|
||||
if selectedStadium != nil {
|
||||
Text("Tap 'Look Up Game' to auto-fill teams and score from historical data")
|
||||
} else {
|
||||
Text("Select a stadium to enable game lookup")
|
||||
}
|
||||
}
|
||||
.listRowBackground(Theme.cardBackground(colorScheme))
|
||||
}
|
||||
@@ -320,6 +348,36 @@ struct StadiumVisitSheet: View {
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
private func lookUpGame() async {
|
||||
guard let stadium = selectedStadium else { return }
|
||||
|
||||
isLookingUpGame = true
|
||||
errorMessage = nil
|
||||
|
||||
// Use the historical game scraper
|
||||
if let scrapedGame = await HistoricalGameScraper.shared.scrapeGame(
|
||||
stadium: stadium,
|
||||
date: visitDate
|
||||
) {
|
||||
// Fill in the form with scraped data
|
||||
awayTeamName = scrapedGame.awayTeam
|
||||
homeTeamName = scrapedGame.homeTeam
|
||||
|
||||
if let away = scrapedGame.awayScore {
|
||||
awayScore = String(away)
|
||||
scoreFromScraper = true
|
||||
}
|
||||
if let home = scrapedGame.homeScore {
|
||||
homeScore = String(home)
|
||||
scoreFromScraper = true
|
||||
}
|
||||
} else {
|
||||
errorMessage = "No game found for \(stadium.name) on this date"
|
||||
}
|
||||
|
||||
isLookingUpGame = false
|
||||
}
|
||||
|
||||
private func saveVisit() {
|
||||
guard let stadium = selectedStadium else {
|
||||
errorMessage = "Please select a stadium"
|
||||
@@ -340,8 +398,8 @@ struct StadiumVisitSheet: View {
|
||||
homeTeamName: homeTeamName.isEmpty ? nil : homeTeamName,
|
||||
awayTeamName: awayTeamName.isEmpty ? nil : awayTeamName,
|
||||
finalScore: finalScoreString,
|
||||
scoreSource: finalScoreString != nil ? .user : nil,
|
||||
dataSource: .fullyManual,
|
||||
scoreSource: finalScoreString != nil ? (scoreFromScraper ? .scraped : .user) : nil,
|
||||
dataSource: scoreFromScraper ? .automatic : .fullyManual,
|
||||
seatLocation: seatLocation.isEmpty ? nil : seatLocation,
|
||||
notes: notes.isEmpty ? nil : notes,
|
||||
source: .manual
|
||||
|
||||
Reference in New Issue
Block a user