Missing Field Handling

This commit is contained in:
2026-05-01 13:54:05 -05:00
parent 5a6491fa51
commit 09447be473
9 changed files with 252 additions and 105 deletions

View File

@@ -2,17 +2,20 @@ import Foundation
public struct Chemical: Identifiable, Sendable, Encodable {
public let id: String
public var piFirstName: String
public var physicalState: String
public var chemicalName: String
public var bldgCode: String
public var lab: String
public var storageLocation: String
public var storageDevice: String
public var numberOfContainers: String
public var amountPerContainer: String
public var unitOfMeasure: String
public var casNumber: String
// These eleven fields are nullable on the server (rows imported from spreadsheets
// can leave any of them blank). Treat them as optional everywhere on read; the
// Add/Edit form still validates them as required on write.
public var piFirstName: String?
public var physicalState: String?
public var chemicalName: String?
public var bldgCode: String?
public var lab: String?
public var storageLocation: String?
public var storageDevice: String?
public var numberOfContainers: String?
public var amountPerContainer: String?
public var unitOfMeasure: String?
public var casNumber: String?
public var chemicalFormula: String?
public var molecularWeight: String?
public var vendor: String?
@@ -31,17 +34,17 @@ public struct Chemical: Identifiable, Sendable, Encodable {
public init(
id: String = "",
piFirstName: String = "",
physicalState: String = "",
chemicalName: String = "",
bldgCode: String = "",
lab: String = "",
storageLocation: String = "",
storageDevice: String = "",
numberOfContainers: String = "",
amountPerContainer: String = "",
unitOfMeasure: String = "",
casNumber: String = "",
piFirstName: String? = nil,
physicalState: String? = nil,
chemicalName: String? = nil,
bldgCode: String? = nil,
lab: String? = nil,
storageLocation: String? = nil,
storageDevice: String? = nil,
numberOfContainers: String? = nil,
amountPerContainer: String? = nil,
unitOfMeasure: String? = nil,
casNumber: String? = nil,
chemicalFormula: String? = nil,
molecularWeight: String? = nil,
vendor: String? = nil,
@@ -92,17 +95,17 @@ extension Chemical: Decodable {
public init(from decoder: Decoder) throws {
let c = try decoder.container(keyedBy: CodingKeys.self)
id = try c.decode(String.self, forKey: .id)
piFirstName = try c.decode(String.self, forKey: .piFirstName)
physicalState = try c.decode(String.self, forKey: .physicalState)
chemicalName = try c.decode(String.self, forKey: .chemicalName)
bldgCode = try c.decode(String.self, forKey: .bldgCode)
lab = try c.decode(String.self, forKey: .lab)
storageLocation = try c.decode(String.self, forKey: .storageLocation)
storageDevice = try c.decode(String.self, forKey: .storageDevice)
numberOfContainers = try c.decode(String.self, forKey: .numberOfContainers)
amountPerContainer = try c.decode(String.self, forKey: .amountPerContainer)
unitOfMeasure = try c.decode(String.self, forKey: .unitOfMeasure)
casNumber = try c.decode(String.self, forKey: .casNumber)
piFirstName = try c.decodeIfPresent(String.self, forKey: .piFirstName)
physicalState = try c.decodeIfPresent(String.self, forKey: .physicalState)
chemicalName = try c.decodeIfPresent(String.self, forKey: .chemicalName)
bldgCode = try c.decodeIfPresent(String.self, forKey: .bldgCode)
lab = try c.decodeIfPresent(String.self, forKey: .lab)
storageLocation = try c.decodeIfPresent(String.self, forKey: .storageLocation)
storageDevice = try c.decodeIfPresent(String.self, forKey: .storageDevice)
numberOfContainers = try c.decodeIfPresent(String.self, forKey: .numberOfContainers)
amountPerContainer = try c.decodeIfPresent(String.self, forKey: .amountPerContainer)
unitOfMeasure = try c.decodeIfPresent(String.self, forKey: .unitOfMeasure)
casNumber = try c.decodeIfPresent(String.self, forKey: .casNumber)
chemicalFormula = try c.decodeIfPresent(String.self, forKey: .chemicalFormula)
molecularWeight = try c.decodeIfPresent(String.self, forKey: .molecularWeight)
vendor = try c.decodeIfPresent(String.self, forKey: .vendor)
@@ -145,6 +148,38 @@ extension Chemical: Decodable {
}
}
/// The eleven fields the web app treats as "key information." A row missing any
/// of these is flagged with a Missing-info badge in the inventory list.
public extension Chemical {
/// Names of the required fields whose value is missing or whitespace-only.
/// Order matches the visual order in the iOS Add/Edit form so the
/// "Missing: " banner reads top-to-bottom in the same order the user fills.
var missingFields: [String] {
func empty(_ s: String?) -> Bool { (s ?? "").trimmingCharacters(in: .whitespaces).isEmpty }
var out: [String] = []
if empty(chemicalName) { out.append("Chemical Name") }
if empty(casNumber) { out.append("CAS #") }
if empty(physicalState) { out.append("Physical State") }
if empty(storageDevice) { out.append("Storage Device") }
if empty(piFirstName) { out.append("PI First Name") }
if empty(bldgCode) { out.append("Building Code") }
if empty(lab) { out.append("Lab") }
if empty(storageLocation) { out.append("Storage Location") }
if empty(numberOfContainers) { out.append("# of Containers") }
if empty(amountPerContainer) { out.append("Amount / Container") }
if empty(unitOfMeasure) { out.append("Unit of Measure") }
return out
}
var isMissingKeyInfo: Bool { !missingFields.isEmpty }
/// Best-effort display name; falls back when `chemicalName` is missing.
var displayName: String {
let trimmed = (chemicalName ?? "").trimmingCharacters(in: .whitespaces)
return trimmed.isEmpty ? "Unnamed chemical" : trimmed
}
}
public struct ChemicalCreateBody: Codable, Sendable {
public var piFirstName: String
public var physicalState: String