// // MealPlanModels.swift // Nextcloud Cookbook iOS Client // import Foundation /// Tracks meal plan assignments for a recipe, stored as `_mealPlanAssignment` in the recipe JSON on the server. struct MealPlanAssignment: Codable { var version: Int = 1 var lastModified: String var dates: [String: MealPlanDateEntry] init(lastModified: String = MealPlanDate.now(), dates: [String: MealPlanDateEntry] = [:]) { self.version = 1 self.lastModified = lastModified self.dates = dates } } struct MealPlanDateEntry: Codable { enum Status: String, Codable { case assigned case removed } var status: Status var mealType: String? var modifiedAt: String init(status: Status, mealType: String? = nil, modifiedAt: String = MealPlanDate.now()) { self.status = status self.mealType = mealType self.modifiedAt = modifiedAt } } /// ISO 8601 date helpers for meal plan dates. enum MealPlanDate { private static let isoFormatter: ISO8601DateFormatter = { let f = ISO8601DateFormatter() f.formatOptions = [.withInternetDateTime] return f }() private static let dayFormatter: DateFormatter = { let f = DateFormatter() f.dateFormat = "yyyy-MM-dd" f.timeZone = .current return f }() static func now() -> String { isoFormatter.string(from: Date()) } static func date(from string: String) -> Date? { isoFormatter.date(from: string) } static func string(from date: Date) -> String { isoFormatter.string(from: date) } static func dayString(from date: Date) -> String { dayFormatter.string(from: date) } static func dateFromDay(_ dayString: String) -> Date? { dayFormatter.date(from: dayString) } } /// Local-only aggregated view struct used by the UI. struct MealPlanEntry: Identifiable { let recipeId: String let recipeName: String let date: Date let dateString: String let mealType: String? var id: String { "\(recipeId)-\(dateString)" } }