// // DiningModel.swift // TigerDine // // Created by Campbell on 10/1/25. // import SwiftUI import WidgetKit @Observable class DiningModel { var locationsByDay = [[DiningLocation]]() var daysRepresented = [Date]() var lastRefreshed: Date? { get { let sharedDefaults = UserDefaults(suiteName: "group.dev.ninjacheetah.RIT-Dining") // If this fails, we should default to an interval of 0. 1970 is obviously going to register as stale cache and will // trigger a reload. return Date(timeIntervalSince1970: sharedDefaults?.double(forKey: "lastRefreshed") ?? 0.0) } set { let sharedDefaults = UserDefaults(suiteName: "group.dev.ninjacheetah.RIT-Dining") sharedDefaults?.set(newValue?.timeIntervalSince1970, forKey: "lastRefreshed") } } // External models that should be nested under this one. var favorites = Favorites() var notifyingChefs = NotifyingChefs() var visitingChefPushes = VisitingChefPushesModel() func getDaysRepresented() async { let calendar = Calendar.current let today = calendar.startOfDay(for: Date()) let week: [Date] = (0..<7).compactMap { offset in calendar.date(byAdding: .day, value: offset, to: today) } daysRepresented = week } /// This is the actual method responsible for making requests to the API for the current day and next 6 days to collect all of the information that the app needs for the various view. Making it part of the model allows it to be updated from any view at any time, and prevents excess API requests (if you never refresh, the app will never need to make more than 7 calls per launch). func getHoursByDay() async throws { await getDaysRepresented() var newLocationsByDay = [[DiningLocation]]() for day in daysRepresented { let dateString = day.formatted(.iso8601 .year().month().day() .dateSeparator(.dash)) switch await getAllDiningInfo(date: dateString) { case .success(let locations): var newDiningLocations = [DiningLocation]() for i in 0.. push.endTime { visitingChefPushes.pushes.remove(at: visitingChefPushes.pushes.firstIndex(of: push)!) } } } /// Cancels all pending push notifications. Used when disabling push notifications as a whole. func cancelAllPushes() async { let uuids = visitingChefPushes.pushes.map(\.uuid) await cancelVisitingChefNotifs(uuids: uuids) visitingChefPushes.pushes.removeAll() } /// Schedules and saves push notifications for a specific visiting chef. func schedulePushesForChef(_ chefName: String) async { for day in locationsByDay { for location in day { if let visitingChefs = location.visitingChefs { for chef in visitingChefs { if chef.name == chefName && notifyingChefs.contains(chef.name) { await visitingChefPushes.scheduleNewPush( name: chef.name, location: location.name, startTime: chef.openTime, endTime: chef.closeTime ) } } } } } } }