diff --git a/ios/Sources/Models.swift b/ios/Sources/Models.swift index 1a41298..605dae2 100644 --- a/ios/Sources/Models.swift +++ b/ios/Sources/Models.swift @@ -309,6 +309,8 @@ struct NewProductRequest: Codable { var individual: Bool? = nil /// Verbrauchsgegenstand: Gegenstand wie ein Lebensmittel (Charge) geführt. var bulk: Bool? = nil + /// Selbst definierte Feldwerte der Kategorie: {feld_id (als Text): Wert}. + var fieldValues: [String: String?]? = nil enum CodingKeys: String, CodingKey { case barcode, name, brand, individual, bulk @@ -319,6 +321,7 @@ struct NewProductRequest: Codable { case datePrecision = "date_precision" case groupId = "group_id" case categoryId = "category_id" + case fieldValues = "field_values" } } diff --git a/ios/Sources/ProductViews.swift b/ios/Sources/ProductViews.swift index e71b4c0..f069649 100644 --- a/ios/Sources/ProductViews.swift +++ b/ios/Sources/ProductViews.swift @@ -89,6 +89,9 @@ struct ProductFormView: View { @State private var pendingImage: UIImage? @State private var showCamera = false @State private var pickerItem: PhotosPickerItem? + // Eigene Felder der (Gegenstands-)Kategorie – schon beim Anlegen ausfüllbar. + @State private var fieldDefs: [FieldDefinition] = [] + @State private var fieldValues: [String: String] = [:] private let baseUnits = [("piece", "Stück"), ("gram", "Gramm"), ("milliliter", "Milliliter")] // Beschriftungen kommen sonst aus DisplaySettings.baseUnitLabel. @@ -179,6 +182,15 @@ struct ProductFormView: View { } } } + // Eigene Felder der Gegenstands-Kategorie (z.B. Größe, Farbe beim + // T-Shirt) – schon beim Anlegen ausfüllbar, nicht erst danach. + if !fieldDefs.isEmpty { + Section("Eigene Felder") { + ForEach(fieldDefs) { def in + ObjectFieldRow(def: def, value: fieldBinding(def)) + } + } + } // Foto direkt beim Anlegen – z.B. wenn Open Food/Products Facts keins // liefert. Wird nach dem Anlegen hochgeladen (dann gibt es eine ID). Section("Foto") { @@ -222,6 +234,16 @@ struct ProductFormView: View { pickerItem = nil } } + .onChange(of: selectedCategoryId) { cid in + // Bei einer Gegenstands-Kategorie deren (vererbte) Felder nachladen. + Task { + if let cid, categories.first(where: { $0.id == cid })?.isObject == true { + fieldDefs = (try? await APIClient.shared.categoryFields(categoryId: cid)) ?? [] + } else { + fieldDefs = [] + } + } + } .onAppear(perform: prefill) .task { groups = (try? await APIClient.shared.groups()) ?? [] @@ -243,6 +265,19 @@ struct ProductFormView: View { } } + private func fieldBinding(_ def: FieldDefinition) -> Binding { + let key = String(def.id) + return Binding(get: { fieldValues[key] ?? "" }, set: { fieldValues[key] = $0 }) + } + + /// Werte der geltenden eigenen Felder als {feld_id: Wert} – nil, wenn keine. + private func eigeneFeldwerte() -> [String: String?]? { + guard !fieldDefs.isEmpty else { return nil } + var fv: [String: String?] = [:] + for def in fieldDefs { fv[String(def.id)] = fieldValues[String(def.id)] ?? "" } + return fv + } + private func prefill() { if let initialType { modus = initialType } barcode = suggestion?.barcode ?? prefillBarcode ?? "" @@ -277,7 +312,8 @@ struct ProductFormView: View { groupId: selectedGroupId, categoryId: selectedCategoryId, individual: modus == "object" ? (objMode == "individual") : nil, - bulk: modus == "object" ? (objMode == "bulk") : nil + bulk: modus == "object" ? (objMode == "bulk") : nil, + fieldValues: eigeneFeldwerte() ) ) // Vorgemerktes Foto hochladen – ein Fehler darf das Anlegen nicht