Jul 30 - Update iPad - inspector can re-inspect and create follow-up
This commit is contained in:
@@ -278,6 +278,7 @@ class SyncManager: ObservableObject {
|
||||
await pullReferenceData()
|
||||
await pullAssignedIssues(context: context)
|
||||
await pullScheduledInspections(context: context)
|
||||
await pullFollowUpRequests(context: context)
|
||||
|
||||
// Poll notifications immediately on every sync rather than waiting
|
||||
// for the 60-second timer — ensures the inspector sees assignments
|
||||
@@ -918,6 +919,65 @@ class SyncManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Follow-up Requests ────────────────────────────────────────────────
|
||||
// Read-only pull of inspections a director flagged for follow-up, for the
|
||||
// Dashboard and My Inspections "Follow-up Requested" section. Upsert by
|
||||
// serverId, then delete rows the server no longer returns (the follow-up was
|
||||
// fulfilled by a linked re-inspection, or the director cleared the flag).
|
||||
// Best-effort — never blocks the pipeline.
|
||||
|
||||
func pullFollowUpRequests(context: ModelContext) async {
|
||||
guard isOnline, AuthManager.shared.isAuthenticated else { return }
|
||||
do {
|
||||
let apiRows = try await APIClient.shared.fetchFollowUpRequests()
|
||||
|
||||
// Fetch-all + filter/map in Swift — no #Predicate (CLAUDE.md rule 3).
|
||||
let allLocal = (try? context.fetch(FetchDescriptor<LocalFollowUpRequest>())) ?? []
|
||||
var byServerId: [Int: LocalFollowUpRequest] = [:]
|
||||
for row in allLocal { byServerId[row.serverId] = row }
|
||||
|
||||
for api in apiRows {
|
||||
if let existing = byServerId[api.id] {
|
||||
existing.update(from: api)
|
||||
} else {
|
||||
context.insert(LocalFollowUpRequest(from: api))
|
||||
}
|
||||
}
|
||||
|
||||
// Delete rows the server no longer returns.
|
||||
let returnedIds = Set(apiRows.map { $0.id })
|
||||
for row in allLocal where !returnedIds.contains(row.serverId) {
|
||||
context.delete(row)
|
||||
}
|
||||
|
||||
// Keep the local copy of the flagged inspection in step, so the
|
||||
// follow-up badge in My Inspections / history detail agrees with the
|
||||
// card without waiting for the inspector to open that detail view
|
||||
// (which was previously the only thing that wrote these fields).
|
||||
var noteByServerId: [Int: String] = [:]
|
||||
for api in apiRows {
|
||||
if let note = api.followUpNote { noteByServerId[api.id] = note }
|
||||
}
|
||||
for local in (try? context.fetch(FetchDescriptor<LocalInspection>())) ?? [] {
|
||||
guard let sid = local.serverId else { continue }
|
||||
if returnedIds.contains(sid) {
|
||||
local.followUpRequired = true
|
||||
local.followUpNote = noteByServerId[sid]
|
||||
} else if local.followUpRequired {
|
||||
local.followUpRequired = false
|
||||
local.followUpNote = nil
|
||||
}
|
||||
}
|
||||
|
||||
try? context.save()
|
||||
|
||||
} catch APIError.notAuthenticated {
|
||||
// Let AuthManager handle session expiry
|
||||
} catch {
|
||||
// Non-fatal — stale follow-up rows stay visible until next pull
|
||||
}
|
||||
}
|
||||
|
||||
// ── Dashboard Stats ───────────────────────────────────────────────────
|
||||
// Best-effort fetch — a network failure silently leaves dashboardStats nil
|
||||
// so the UI falls back to a placeholder card. Never blocks the sync pipeline.
|
||||
|
||||
Reference in New Issue
Block a user