fix(schedule): use start of day for date range queries
- Fix startDate to use Calendar.startOfDay instead of Date() to include games earlier in the current day - Add SyncLogger for file-based sync logging viewable in Settings - Add "View Sync Logs" button in Settings debug section - Add diagnostics and NBA game logging to ScheduleViewModel - Add dropped game logging to DataProvider.filterRichGames - Use SyncLogger in SportsTimeApp and CloudKitService for sync operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import os.log
|
||||
|
||||
private let logger = Logger(subsystem: "com.sportstime.app", category: "ScheduleViewModel")
|
||||
|
||||
@MainActor
|
||||
@Observable
|
||||
@@ -13,8 +16,8 @@ final class ScheduleViewModel {
|
||||
// MARK: - Filter State
|
||||
|
||||
var selectedSports: Set<Sport> = Set(Sport.supported)
|
||||
var startDate: Date = Date()
|
||||
var endDate: Date = Calendar.current.date(byAdding: .day, value: 14, to: Date()) ?? Date()
|
||||
var startDate: Date = Calendar.current.startOfDay(for: Date())
|
||||
var endDate: Date = Calendar.current.date(byAdding: .day, value: 14, to: Calendar.current.startOfDay(for: Date())) ?? Date()
|
||||
var searchText: String = ""
|
||||
|
||||
// MARK: - Data State
|
||||
@@ -34,6 +37,11 @@ final class ScheduleViewModel {
|
||||
/// All games matching current filters (before any display limiting)
|
||||
private var filteredGames: [RichGame] = []
|
||||
|
||||
// MARK: - Diagnostics
|
||||
|
||||
/// Debug info for troubleshooting missing games
|
||||
private(set) var diagnostics: ScheduleDiagnostics = ScheduleDiagnostics()
|
||||
|
||||
var hasFilters: Bool {
|
||||
selectedSports.count < Sport.supported.count || !searchText.isEmpty
|
||||
}
|
||||
@@ -51,9 +59,18 @@ final class ScheduleViewModel {
|
||||
error = nil
|
||||
errorMessage = nil
|
||||
|
||||
// Start diagnostics
|
||||
let queryStartDate = startDate
|
||||
let queryEndDate = endDate
|
||||
let querySports = selectedSports
|
||||
|
||||
logger.info("📅 Loading games: \(querySports.map(\.rawValue).joined(separator: ", "))")
|
||||
logger.info("📅 Date range: \(queryStartDate.formatted()) to \(queryEndDate.formatted())")
|
||||
|
||||
do {
|
||||
// Load initial data if needed
|
||||
if dataProvider.teams.isEmpty {
|
||||
logger.info("📅 Teams empty, loading initial data...")
|
||||
await dataProvider.loadInitialData()
|
||||
}
|
||||
|
||||
@@ -63,20 +80,58 @@ final class ScheduleViewModel {
|
||||
self.error = dataProvider.error
|
||||
isLoading = false
|
||||
updateFilteredGames()
|
||||
logger.error("📅 DataProvider error: \(providerError)")
|
||||
return
|
||||
}
|
||||
|
||||
// Log team/stadium counts for diagnostics
|
||||
logger.info("📅 Loaded \(self.dataProvider.teams.count) teams, \(self.dataProvider.stadiums.count) stadiums")
|
||||
|
||||
games = try await dataProvider.filterRichGames(
|
||||
sports: selectedSports,
|
||||
startDate: startDate,
|
||||
endDate: endDate
|
||||
)
|
||||
|
||||
// Update diagnostics
|
||||
var newDiagnostics = ScheduleDiagnostics()
|
||||
newDiagnostics.lastQueryStartDate = queryStartDate
|
||||
newDiagnostics.lastQueryEndDate = queryEndDate
|
||||
newDiagnostics.lastQuerySports = Array(querySports)
|
||||
newDiagnostics.totalGamesReturned = games.count
|
||||
newDiagnostics.teamsLoaded = dataProvider.teams.count
|
||||
newDiagnostics.stadiumsLoaded = dataProvider.stadiums.count
|
||||
|
||||
// Count games by sport
|
||||
var sportCounts: [Sport: Int] = [:]
|
||||
for game in games {
|
||||
sportCounts[game.game.sport, default: 0] += 1
|
||||
}
|
||||
newDiagnostics.gamesBySport = sportCounts
|
||||
|
||||
self.diagnostics = newDiagnostics
|
||||
|
||||
logger.info("📅 Returned \(self.games.count) games")
|
||||
for (sport, count) in sportCounts.sorted(by: { $0.key.rawValue < $1.key.rawValue }) {
|
||||
logger.info("📅 \(sport.rawValue): \(count) games")
|
||||
}
|
||||
|
||||
// Debug: Print all NBA games
|
||||
let nbaGames = games.filter { $0.game.sport == .nba }
|
||||
print("🏀 [DEBUG] All NBA games in schedule (\(nbaGames.count) total):")
|
||||
for game in nbaGames.sorted(by: { $0.game.dateTime < $1.game.dateTime }) {
|
||||
let dateStr = game.game.dateTime.formatted(date: .abbreviated, time: .shortened)
|
||||
print("🏀 \(dateStr): \(game.awayTeam.name) @ \(game.homeTeam.name) (\(game.game.id))")
|
||||
}
|
||||
|
||||
} catch let cloudKitError as CloudKitError {
|
||||
self.error = cloudKitError
|
||||
self.errorMessage = cloudKitError.errorDescription
|
||||
logger.error("📅 CloudKit error: \(cloudKitError.errorDescription ?? "unknown")")
|
||||
} catch {
|
||||
self.error = error
|
||||
self.errorMessage = error.localizedDescription
|
||||
logger.error("📅 Error loading games: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
@@ -147,3 +202,42 @@ final class ScheduleViewModel {
|
||||
.map { (sport: $0.key, games: $0.value.sorted { $0.game.dateTime < $1.game.dateTime }) }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Diagnostics Model
|
||||
|
||||
/// Diagnostic information for troubleshooting schedule display issues
|
||||
struct ScheduleDiagnostics {
|
||||
var lastQueryStartDate: Date?
|
||||
var lastQueryEndDate: Date?
|
||||
var lastQuerySports: [Sport] = []
|
||||
var totalGamesReturned: Int = 0
|
||||
var teamsLoaded: Int = 0
|
||||
var stadiumsLoaded: Int = 0
|
||||
var gamesBySport: [Sport: Int] = [:]
|
||||
|
||||
var summary: String {
|
||||
guard let start = lastQueryStartDate, let end = lastQueryEndDate else {
|
||||
return "No query executed"
|
||||
}
|
||||
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateStyle = .short
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
var lines: [String] = []
|
||||
lines.append("Date Range: \(dateFormatter.string(from: start)) - \(dateFormatter.string(from: end))")
|
||||
lines.append("Sports: \(lastQuerySports.map(\.rawValue).joined(separator: ", "))")
|
||||
lines.append("Teams Loaded: \(teamsLoaded)")
|
||||
lines.append("Stadiums Loaded: \(stadiumsLoaded)")
|
||||
lines.append("Total Games: \(totalGamesReturned)")
|
||||
|
||||
if !gamesBySport.isEmpty {
|
||||
lines.append("By Sport:")
|
||||
for (sport, count) in gamesBySport.sorted(by: { $0.key.rawValue < $1.key.rawValue }) {
|
||||
lines.append(" \(sport.rawValue): \(count)")
|
||||
}
|
||||
}
|
||||
|
||||
return lines.joined(separator: "\n")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user