import SwiftUI import Charts struct AllocationPieChart: View { let data: [(category: String, value: Decimal, color: String)] @State private var selectedSlice: String? var total: Decimal { data.reduce(Decimal.zero) { $0 + $1.value } } var body: some View { VStack(alignment: .leading, spacing: 16) { Text("Asset Allocation") .font(.headline) if !data.isEmpty { HStack(alignment: .top, spacing: 20) { // Pie Chart Chart(data, id: \.category) { item in SectorMark( angle: .value("Value", NSDecimalNumber(decimal: item.value).doubleValue), innerRadius: .ratio(0.6), angularInset: 1.5 ) .foregroundStyle(Color(hex: item.color) ?? .gray) .cornerRadius(4) .opacity(selectedSlice == nil || selectedSlice == item.category ? 1 : 0.5) } .chartLegend(.hidden) .frame(width: 180, height: 180) .overlay { // Center content VStack(spacing: 2) { if let selected = selectedSlice, let item = data.first(where: { $0.category == selected }) { Text(selected) .font(.caption) .foregroundColor(.secondary) Text(item.value.compactCurrencyString) .font(.headline) let percentage = total > 0 ? NSDecimalNumber(decimal: item.value / total).doubleValue * 100 : 0 Text(String(format: "%.1f%%", percentage)) .font(.caption) .foregroundColor(.secondary) } else { Text("Total") .font(.caption) .foregroundColor(.secondary) Text(total.compactCurrencyString) .font(.headline) } } } .gesture( DragGesture(minimumDistance: 0) .onChanged { value in // Simple tap detection } ) // Legend VStack(alignment: .leading, spacing: 8) { ForEach(data, id: \.category) { item in Button { if selectedSlice == item.category { selectedSlice = nil } else { selectedSlice = item.category } } label: { HStack(spacing: 8) { Circle() .fill(Color(hex: item.color) ?? .gray) .frame(width: 10, height: 10) VStack(alignment: .leading, spacing: 0) { Text(item.category) .font(.caption) .foregroundColor(.primary) let percentage = total > 0 ? NSDecimalNumber(decimal: item.value / total).doubleValue * 100 : 0 Text(String(format: "%.1f%%", percentage)) .font(.caption2) .foregroundColor(.secondary) } } .opacity(selectedSlice == nil || selectedSlice == item.category ? 1 : 0.5) } .buttonStyle(.plain) } } .frame(maxWidth: .infinity, alignment: .leading) } } else { Text("No allocation data available") .foregroundColor(.secondary) .frame(height: 200) .frame(maxWidth: .infinity) } } .padding() .background(Color(.systemBackground)) .cornerRadius(AppConstants.UI.cornerRadius) .shadow(color: .black.opacity(0.05), radius: 8, y: 2) } } // MARK: - Allocation List View (Alternative) struct AllocationListView: View { let data: [(category: String, value: Decimal, color: String)] var total: Decimal { data.reduce(Decimal.zero) { $0 + $1.value } } var body: some View { VStack(alignment: .leading, spacing: 12) { Text("Asset Allocation") .font(.headline) ForEach(data, id: \.category) { item in VStack(spacing: 4) { HStack { HStack(spacing: 8) { Circle() .fill(Color(hex: item.color) ?? .gray) .frame(width: 10, height: 10) Text(item.category) .font(.subheadline) } Spacer() let percentage = total > 0 ? NSDecimalNumber(decimal: item.value / total).doubleValue * 100 : 0 Text(String(format: "%.1f%%", percentage)) .font(.subheadline.weight(.medium)) Text(item.value.compactCurrencyString) .font(.caption) .foregroundColor(.secondary) .frame(width: 70, alignment: .trailing) } // Progress bar GeometryReader { geometry in let percentage = total > 0 ? NSDecimalNumber(decimal: item.value / total).doubleValue : 0 ZStack(alignment: .leading) { Rectangle() .fill(Color.gray.opacity(0.1)) .frame(height: 6) .cornerRadius(3) Rectangle() .fill(Color(hex: item.color) ?? .gray) .frame(width: geometry.size.width * percentage, height: 6) .cornerRadius(3) } } .frame(height: 6) } } } .padding() .background(Color(.systemBackground)) .cornerRadius(AppConstants.UI.cornerRadius) .shadow(color: .black.opacity(0.05), radius: 8, y: 2) } } #Preview { let sampleData: [(category: String, value: Decimal, color: String)] = [ ("Stocks", 50000, "#10B981"), ("Bonds", 25000, "#3B82F6"), ("Real Estate", 15000, "#F59E0B"), ("Crypto", 10000, "#8B5CF6") ] return VStack(spacing: 20) { AllocationPieChart(data: sampleData) AllocationListView(data: sampleData) } .padding() }