05/16 Fix bugs 3

This commit is contained in:
Nguyen Ngo
2026-05-16 14:56:11 -04:00
parent 9c7aa72ff3
commit f436ac2ef2
3 changed files with 93 additions and 45 deletions
@@ -211,31 +211,21 @@ struct HistoryDetailView: View {
@Environment(\.modelContext) private var context
@State private var showReInspect = false
// Look up the local copy by mobileLocalId present only for this-device submissions
private var localCopy: LocalInspection? {
guard let lid = inspection.mobileLocalId else { return nil }
return try? context.fetch(
FetchDescriptor<LocalInspection>(
predicate: #Predicate { $0.localId == lid }
)
).first
}
// Local SwiftData copy used only for follow-up sync-back.
// Form data and schema come from the server response directly so
// History works even after app reinstall or on a different device.
@State private var localCopy: LocalInspection? = nil
// Fetch the template schema so we can render the form grid
private var localTemplate: LocalTemplate? {
guard let copy = localCopy else { return nil }
let id = copy.templateServerId
return try? context.fetch(
FetchDescriptor<LocalTemplate>(predicate: #Predicate { $0.serverId == id })
).first
}
private var formSchema: [[String: Any]] { inspection.formSchema }
private var savedValues: [String: String] { inspection.formValues }
private var formSchema: [[String: Any]] { localTemplate?.formSchema ?? [] }
// Convert saved form data to [String: String] for the grid renderer
private var savedValues: [String: String] {
guard let copy = localCopy else { return [:] }
return copy.formData.compactMapValues { "\($0)" }
/// Load the local SwiftData copy once on appear (for follow-up sync only).
/// Fetch-all + filter in Swift #Predicate with captured String is banned
/// under Xcode 26 SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor (CLAUDE.md rules 3, 25).
private func loadLocalData() {
guard let lid = inspection.mobileLocalId else { return }
let all = (try? context.fetch(FetchDescriptor<LocalInspection>())) ?? []
localCopy = all.first { $0.localId == lid }
}
var body: some View {
@@ -290,6 +280,23 @@ struct HistoryDetailView: View {
issuesCard(copy.localIssues)
}
// Inspector notes
if !inspection.inspectorNotes.isEmpty {
VStack(alignment: .leading, spacing: 6) {
Text("Inspector Notes")
.font(.headline)
.padding(.horizontal, 24)
Text(inspection.inspectorNotes)
.font(.callout)
.foregroundStyle(.primary)
.padding(16)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(.secondarySystemBackground))
.clipShape(RoundedRectangle(cornerRadius: 12))
.padding(.horizontal, 24)
}
}
// Form responses
if !formSchema.isEmpty {
VStack(alignment: .leading, spacing: 8) {
@@ -297,20 +304,12 @@ struct HistoryDetailView: View {
.font(.headline)
.padding(.horizontal, 24)
// Read-only form grid reuses GridFormView with disabled inputs
ReadOnlyGridFormView(
schema: formSchema,
formValues: savedValues
)
.padding(.horizontal, 24)
}
} else if localCopy != nil {
// Template schema no longer cached locally
infoRow(
icon: "doc.text",
text: "Form schema not available offline. Sync to view full responses."
)
.padding(.horizontal, 24)
}
}
.padding(.vertical, 16)
@@ -319,6 +318,7 @@ struct HistoryDetailView: View {
.navigationTitle(inspection.templateName)
.navigationBarTitleDisplayMode(.inline)
.onAppear {
loadLocalData()
syncFollowUpToLocalCopy()
}
.sheet(isPresented: $showReInspect) {