Missing Field Handling
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user