import SwiftUI struct AllocationTargetsView: View { @StateObject private var categoryRepository = CategoryRepository() @State private var targetValues: [UUID: String] = [:] var body: some View { List { Section { HStack { Text("Total Targets") Spacer() Text(String(format: "%.0f%%", totalTargets)) .foregroundColor(totalTargets == 100 ? .positiveGreen : .secondary) } if totalTargets != 100 { Text("Targets don't need to be perfect, but aiming for 100% keeps the drift view accurate.") .font(.caption) .foregroundColor(.secondary) } } Section { ForEach(categoryRepository.categories) { category in let categoryId = category.id HStack { HStack(spacing: 8) { Circle() .fill(category.color) .frame(width: 10, height: 10) Text(category.name) } Spacer() TextField("0", text: targetBinding(for: categoryId)) .keyboardType(.decimalPad) .multilineTextAlignment(.trailing) .frame(width: 60) Text("%") .foregroundColor(.secondary) } } } header: { Text("Targets by Category") } footer: { Text("Set your desired allocation percentages to track drift over time.") } } .navigationTitle("Allocation Targets") .navigationBarTitleDisplayMode(.inline) .onAppear { preloadTargets() } } private var totalTargets: Double { let ids = categoryRepository.categories.compactMap { $0.id } return AllocationTargetStore.totalTargetPercentage(for: ids) } private func preloadTargets() { targetValues = categoryRepository.categories.reduce(into: [:]) { result, category in let id = category.id if let target = AllocationTargetStore.target(for: id) { result[id] = String(format: "%.0f", target) } } } private func targetBinding(for categoryId: UUID) -> Binding { Binding( get: { targetValues[categoryId] ?? "" }, set: { newValue in targetValues[categoryId] = newValue let sanitized = newValue.replacingOccurrences(of: ",", with: ".") let value = Double(sanitized) ?? 0 AllocationTargetStore.setTarget(value, for: categoryId) } ) } } #Preview { NavigationStack { AllocationTargetsView() } }