Fix meal plan removal ignored on first attempt after app launch
Guard reconcileFromServer() with a syncStartTime so that entries modified locally during an active performSync() cycle are never overwritten by stale server data. This prevents the race condition where a user removes a meal plan entry while Phase 2 of sync is still iterating server recipes. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ class MealPlanManager: ObservableObject {
|
|||||||
private var recipeNames: [String: String] = [:]
|
private var recipeNames: [String: String] = [:]
|
||||||
private let dataStore = DataStore()
|
private let dataStore = DataStore()
|
||||||
var syncManager: MealPlanSyncManager?
|
var syncManager: MealPlanSyncManager?
|
||||||
|
var syncStartTime: String?
|
||||||
|
|
||||||
private static let persistencePath = "meal_plan.data"
|
private static let persistencePath = "meal_plan.data"
|
||||||
|
|
||||||
@@ -128,6 +129,13 @@ class MealPlanManager: ObservableObject {
|
|||||||
|
|
||||||
for (dayStr, serverEntry) in serverAssignment.dates {
|
for (dayStr, serverEntry) in serverAssignment.dates {
|
||||||
if let localEntry = local.dates[dayStr] {
|
if let localEntry = local.dates[dayStr] {
|
||||||
|
// Skip entries modified locally during this sync cycle
|
||||||
|
if let syncStart = syncStartTime,
|
||||||
|
let syncStartDate = MealPlanDate.date(from: syncStart),
|
||||||
|
let localModDate = MealPlanDate.date(from: localEntry.modifiedAt),
|
||||||
|
localModDate >= syncStartDate {
|
||||||
|
continue
|
||||||
|
}
|
||||||
let localDate = MealPlanDate.date(from: localEntry.modifiedAt) ?? .distantPast
|
let localDate = MealPlanDate.date(from: localEntry.modifiedAt) ?? .distantPast
|
||||||
let serverDate = MealPlanDate.date(from: serverEntry.modifiedAt) ?? .distantPast
|
let serverDate = MealPlanDate.date(from: serverEntry.modifiedAt) ?? .distantPast
|
||||||
if serverDate > localDate {
|
if serverDate > localDate {
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ class MealPlanSyncManager {
|
|||||||
func performSync() async {
|
func performSync() async {
|
||||||
guard let appState, let mealPlanManager else { return }
|
guard let appState, let mealPlanManager else { return }
|
||||||
|
|
||||||
|
mealPlanManager.syncStartTime = MealPlanDate.now()
|
||||||
|
defer { mealPlanManager.syncStartTime = nil }
|
||||||
|
|
||||||
// Phase 1: Push locally-known meal plan state
|
// Phase 1: Push locally-known meal plan state
|
||||||
let localRecipeIds = Array(Set(
|
let localRecipeIds = Array(Set(
|
||||||
mealPlanManager.entriesByDate.values.flatMap { $0 }.map(\.recipeId)
|
mealPlanManager.entriesByDate.values.flatMap { $0 }.map(\.recipeId)
|
||||||
|
|||||||
Reference in New Issue
Block a user