App: Tag beim Anlegen, Menge beim Anlegen, Loeschen und NFC beim Ein-/Auslagern
Vier Bruchstellen im taeglichen Gebrauch, alle an derselben Wurzel: Nach dem Anlegen endete der Weg, und was danach kam, musste man sich selbst suchen. NFC beim Anlegen: createItems liefert die angelegten Stuecke samt UID laengst zurueck, ItemAddSheet warf sie nur weg. Bei genau EINEM Stueck geht es jetzt direkt zum Tag-Blatt. Bei mehreren bleibt es wie bisher - die App koennte nicht wissen, welches der fuenf Stuecke gerade am Tag haengt. Ohne NFC im Geraet (iPad) ebenso unveraendert. Menge beim Anlegen: Ein Gegenstand, der nur als Menge je Lagerort gezaehlt wird, landete nach dem Anlegen im Nichts. Das Blatt dafuer gab es schon (ObjectAddSheet), nur fuehrte kein Weg dorthin. Jetzt derselbe Uebergang wie bei Einzelstuecken, an beiden Einstiegen. Es holt sich die Lagerorte selbst - ObjectAddSheet nimmt sie als Konstante und laedt sie nicht nach. Loeschen: Der Knopf sitzt unten in der Artikelansicht, nur fuer Admins - die Route verlangt das, ohne Riegel gaebe es nur ein wortkarges 403. Lehnt der Server ab (noch Einzelstuecke oder Bestand), bleibt die Ansicht stehen und seine Begruendung steht unveraendert in der Fehlerzeile. NFC beim Ein- und Auslagern: Ein Tag benennt immer genau ein Einzelstueck, deshalb fuehrt er zur Stueck-Ansicht - beim Auslagern ist "Entfernen (mit Grund)" genau die passende Aktion. Bewusst NICHT ueber resolve() abgekuerzt: das faellt bei unbekannter UID auf lookup(barcode:) durch und boete an, einen Artikel mit einer URL als Barcode anzulegen. Beim Nachschlagen gab es NFC schon, nur unscheinbar unter der Kamerakarte - Knopf abgesetzt und in der Bildunterschrift erwaehnt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
501d80a9b8
commit
ea7a42ac22
@@ -5,10 +5,12 @@ struct ProductDetailView: View {
|
||||
let product: Product
|
||||
|
||||
@EnvironmentObject private var display: DisplaySettings
|
||||
@EnvironmentObject private var session: Session
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@State private var current: Product
|
||||
@State private var showLeaveConfirm = false
|
||||
@State private var pendingDelete = false
|
||||
@State private var lots: [Lot] = []
|
||||
@State private var busy = false
|
||||
@State private var error: String?
|
||||
@@ -321,6 +323,14 @@ struct ProductDetailView: View {
|
||||
Label("Verlauf dieses Artikels", systemImage: "clock.arrow.circlepath")
|
||||
}
|
||||
}
|
||||
|
||||
// Loeschen verlangt Adminrechte (DELETE /products/{id}). Ohne den
|
||||
// Riegel bekaeme ein normaler Benutzer nur ein wortkarges 403.
|
||||
if session.isAdmin {
|
||||
Section {
|
||||
Button("Artikel löschen", role: .destructive) { pendingDelete = true }
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(current.name)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
@@ -339,6 +349,14 @@ struct ProductDetailView: View {
|
||||
Text("Änderungen an Name/Marke/Kategorie sind noch nicht gespeichert. "
|
||||
+ "Foto und Lagerort-Bedarf werden sofort gespeichert.")
|
||||
}
|
||||
.confirmationDialog("„\(current.name)“ löschen?", isPresented: $pendingDelete,
|
||||
titleVisibility: .visible) {
|
||||
Button("Löschen", role: .destructive) { Task { await loeschen() } }
|
||||
Button("Abbrechen", role: .cancel) {}
|
||||
} message: {
|
||||
Text("Barcodes, Bild und der Bewegungsverlauf gehen dabei verloren. "
|
||||
+ "Hat der Artikel noch Einzelstücke oder Bestand, lehnt der Server ab.")
|
||||
}
|
||||
.sheet(item: $editLot) { lot in
|
||||
NavigationStack {
|
||||
LotEditView(lot: lot, product: current, locations: locations) {
|
||||
@@ -606,6 +624,25 @@ struct ProductDetailView: View {
|
||||
}
|
||||
await reload()
|
||||
}
|
||||
|
||||
/// Artikel loeschen und zurueck zur Liste.
|
||||
///
|
||||
/// Bewusst `dismiss()` und nicht `attemptLeave()`: Letzteres fragte nach
|
||||
/// ungespeicherten Aenderungen an einem Artikel, den es nicht mehr gibt.
|
||||
/// Lehnt der Server ab (409, noch Einzelstuecke oder Bestand), bleibt die
|
||||
/// Ansicht stehen und seine Begruendung landet unveraendert in der
|
||||
/// Fehlerzeile – sie nennt genau, was noch dranhaengt.
|
||||
private func loeschen() async {
|
||||
error = nil
|
||||
busy = true
|
||||
defer { busy = false }
|
||||
do {
|
||||
try await APIClient.shared.deleteProduct(id: current.id)
|
||||
dismiss()
|
||||
} catch {
|
||||
self.error = error.localizedDescription
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lädt ein Produkt anhand seiner ID nach und zeigt dann die Detailansicht –
|
||||
|
||||
Reference in New Issue
Block a user