App: Einzelstuecke verleihen - alle Scan-Wege enden schon dort
Verleih-Abschnitt im Einzelstueck: an wen, seit wann, bis wann, dazu Herausgeben bzw. Zuruecknehmen und der Verleih-Verlauf. Pflicht ist nur der Name; Grund und Rueckgabedatum sind abschaltbar, weil "kurz mal mitgenommen" nicht an einem Datum scheitern soll. Der Abschnitt sitzt bewusst oben in ItemEditView, und zwar nicht nur der Wichtigkeit wegen: QR ueber Nachschlagen, eingenaehtes NFC-Tag und ein angetipptes Tag (vorrania://i/<UID>) landen alle in genau dieser Ansicht. Damit ist "scannen und verleihen" ueberall moeglich, ohne einen eigenen Weg dafuer zu bauen. In der Einzelstueck-Liste steht der Verleih unter dem Stueck - ueberfaellig in Rot - und das Filter-Menue kann auf Verliehen, Ueberfaellig oder Im Haus eingrenzen. Wo etwas ist, war bisher immer der Lagerort; ist es verliehen, ist der Entleiher die Antwort, und der Lagerort steht daneben. days_overdue rechnet der Server (GET /loans, ItemOut.loan), damit App und Web nicht getrennt rechnen und nicht auseinanderlaufen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1332dd86fa
commit
aa72d8342a
@@ -10,6 +10,22 @@ struct ItemListView: View {
|
||||
@State private var query = ""
|
||||
@State private var locationFilter: String? // Lagerort-ID
|
||||
@State private var categoryFilter: Int? // Kategorie-ID (Unterkategorien zählen mit)
|
||||
@State private var verleihFilter: VerleihFilter = .alle
|
||||
|
||||
/// Blickwinkel auf den Verleihzustand – „was ist gerade draußen?" ist die
|
||||
/// Frage, die man im Alltag an diese Liste stellt.
|
||||
enum VerleihFilter: String, CaseIterable {
|
||||
case alle, verliehen, ueberfaellig, imHaus
|
||||
|
||||
var label: String {
|
||||
switch self {
|
||||
case .alle: return "Alle"
|
||||
case .verliehen: return "Verliehen"
|
||||
case .ueberfaellig: return "Überfällig"
|
||||
case .imHaus: return "Im Haus"
|
||||
}
|
||||
}
|
||||
}
|
||||
@State private var busy = true
|
||||
@State private var error: String?
|
||||
|
||||
@@ -73,6 +89,12 @@ struct ItemListView: View {
|
||||
return items.filter { it in
|
||||
if let cat = categoryFilter, !imTeilbaum(it.categoryId, target: cat) { return false }
|
||||
if let loc = locationFilter, it.locationId != loc { return false }
|
||||
switch verleihFilter {
|
||||
case .alle: break
|
||||
case .verliehen: if it.loan == nil { return false }
|
||||
case .ueberfaellig: if !(it.loan?.istUeberfaellig ?? false) { return false }
|
||||
case .imHaus: if it.loan != nil { return false }
|
||||
}
|
||||
if !q.isEmpty {
|
||||
let heu = [it.productName, it.uid, it.note, it.productBrand]
|
||||
.compactMap { $0 }.joined(separator: " ").lowercased()
|
||||
@@ -82,7 +104,9 @@ struct ItemListView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var hatFilter: Bool { locationFilter != nil || categoryFilter != nil }
|
||||
private var hatFilter: Bool {
|
||||
locationFilter != nil || categoryFilter != nil || verleihFilter != .alle
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
@@ -117,6 +141,11 @@ struct ItemListView: View {
|
||||
check(loc.path(in: locations), locationFilter == loc.id) { locationFilter = loc.id }
|
||||
}
|
||||
}
|
||||
Menu("Verleih") {
|
||||
ForEach(VerleihFilter.allCases, id: \.self) { f in
|
||||
check(f.label, verleihFilter == f) { verleihFilter = f }
|
||||
}
|
||||
}
|
||||
if !filterKategorien.isEmpty {
|
||||
Menu("Kategorie") {
|
||||
check("Alle", categoryFilter == nil) { categoryFilter = nil }
|
||||
@@ -127,7 +156,9 @@ struct ItemListView: View {
|
||||
}
|
||||
if hatFilter {
|
||||
Divider()
|
||||
Button(role: .destructive) { locationFilter = nil; categoryFilter = nil } label: {
|
||||
Button(role: .destructive) {
|
||||
locationFilter = nil; categoryFilter = nil; verleihFilter = .alle
|
||||
} label: {
|
||||
Label("Filter zurücksetzen", systemImage: "xmark.circle")
|
||||
}
|
||||
}
|
||||
@@ -175,6 +206,14 @@ struct ItemRow: View {
|
||||
Text("· \(pfad)").font(.caption).foregroundStyle(.secondary).lineLimit(1)
|
||||
}
|
||||
}
|
||||
// Verliehen ist die Antwort auf „wo ist es?" - deshalb eigene
|
||||
// Zeile, ueberfaellig in Rot.
|
||||
if let loan = item.loan {
|
||||
Text("verliehen an \(verleihZeile(loan))")
|
||||
.font(.caption)
|
||||
.foregroundStyle(loan.istUeberfaellig ? Color.red : .secondary)
|
||||
.lineLimit(2)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user