Ausgaben-Kategorien dynamisch vom Backend
ExpenseCategory DTO + GET /api/expenses/categories beim Öffnen der Liste sowie bei Refresh. Falls der Endpunkt noch nicht ausgerollt ist (oder fehlschlägt), Fallback auf eine lokale Default-Liste mit den aktuellen sechs Kategorien. AddExpenseSheet bekommt die Kategorien als Parameter, statt eigene Liste zu führen — Source of Truth ist jetzt das Backend.
This commit is contained in:
parent
c03f018c0c
commit
cf625f3391
2 changed files with 47 additions and 15 deletions
|
|
@ -109,6 +109,12 @@ struct ExpenseCreateBody: Encodable {
|
|||
let notiz: String?
|
||||
}
|
||||
|
||||
struct ExpenseCategory: Decodable, Identifiable {
|
||||
let id: String
|
||||
let label: String
|
||||
let color: String?
|
||||
}
|
||||
|
||||
// MARK: - Gassi-Zeiten
|
||||
|
||||
struct GassiZeit: Decodable, Identifiable {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,22 @@ import SwiftUI
|
|||
|
||||
struct AusgabenView: View {
|
||||
@State private var expenses: [Expense] = []
|
||||
@State private var categories: [ExpenseCategory] = []
|
||||
@State private var isLoading = false
|
||||
@State private var errorMessage: String?
|
||||
@State private var showAdd = false
|
||||
|
||||
/// Lokale Fallback-Liste, falls der Backend-Endpunkt /api/expenses/categories
|
||||
/// noch nicht ausgerollt ist. Sollte im Normalfall überschrieben werden.
|
||||
private static let defaultCategories: [ExpenseCategory] = [
|
||||
ExpenseCategory(id: "futter", label: "Futter", color: nil),
|
||||
ExpenseCategory(id: "tierarzt", label: "Tierarzt", color: nil),
|
||||
ExpenseCategory(id: "zubehoer", label: "Zubehör", color: nil),
|
||||
ExpenseCategory(id: "versicherung", label: "Versicherung", color: nil),
|
||||
ExpenseCategory(id: "sitter", label: "Sitter", color: nil),
|
||||
ExpenseCategory(id: "sonstiges", label: "Sonstiges", color: nil)
|
||||
]
|
||||
|
||||
private static let dateFormatter: DateFormatter = {
|
||||
let f = DateFormatter()
|
||||
f.locale = Locale(identifier: "de_DE")
|
||||
|
|
@ -30,10 +42,27 @@ struct AusgabenView: View {
|
|||
}
|
||||
}
|
||||
.sheet(isPresented: $showAdd) {
|
||||
AddExpenseSheet { Task { await load() } }
|
||||
AddExpenseSheet(categories: categories.isEmpty ? Self.defaultCategories : categories) {
|
||||
Task { await load() }
|
||||
}
|
||||
}
|
||||
.task { await load() }
|
||||
.refreshable { await load() }
|
||||
.task {
|
||||
await loadCategories()
|
||||
await load()
|
||||
}
|
||||
.refreshable {
|
||||
await loadCategories()
|
||||
await load()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadCategories() async {
|
||||
if let fetched: [ExpenseCategory] = try? await APIClient.shared.get("/api/expenses/categories"),
|
||||
!fetched.isEmpty {
|
||||
categories = fetched
|
||||
} else if categories.isEmpty {
|
||||
categories = Self.defaultCategories
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
|
@ -139,9 +168,10 @@ private struct ExpenseRow: View {
|
|||
|
||||
private struct AddExpenseSheet: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
let categories: [ExpenseCategory]
|
||||
let onSaved: () -> Void
|
||||
|
||||
@State private var kategorie = "futter"
|
||||
@State private var kategorie: String
|
||||
@State private var betrag = ""
|
||||
@State private var date = Date()
|
||||
@State private var notiz = ""
|
||||
|
|
@ -150,23 +180,19 @@ private struct AddExpenseSheet: View {
|
|||
@State private var isSaving = false
|
||||
@State private var errorMessage: String?
|
||||
|
||||
/// Backend-Whitelist: tierarzt, futter, zubehoer, versicherung, sitter, sonstiges
|
||||
private let kategorien: [(key: String, label: String)] = [
|
||||
("futter", "Futter"),
|
||||
("tierarzt", "Tierarzt"),
|
||||
("zubehoer", "Zubehör"),
|
||||
("versicherung", "Versicherung"),
|
||||
("sitter", "Sitter"),
|
||||
("sonstiges", "Sonstiges")
|
||||
]
|
||||
init(categories: [ExpenseCategory], onSaved: @escaping () -> Void) {
|
||||
self.categories = categories
|
||||
self.onSaved = onSaved
|
||||
_kategorie = State(initialValue: categories.first?.id ?? "sonstiges")
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section("Kategorie") {
|
||||
Picker("Kategorie", selection: $kategorie) {
|
||||
ForEach(kategorien, id: \.key) { entry in
|
||||
Text(entry.label).tag(entry.key)
|
||||
ForEach(categories) { entry in
|
||||
Text(entry.label).tag(entry.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue