import SwiftUI struct FinanceView: View { @EnvironmentObject var authManager: AuthManager @State private var summary: FinanceSummary? @State private var transactions: [FinanceTransaction] = [] @State private var categories: [FinanceCategory] = [] @State private var isLoading = true @State private var showAddTransaction = false var body: some View { ZStack { Color(hex: "0a0a1a").ignoresSafeArea() VStack(spacing: 0) { HStack { Text("Финансы").font(.title.bold()).foregroundColor(.white) Spacer() Button(action: { showAddTransaction = true }) { Image(systemName: "plus.circle.fill").font(.title2).foregroundColor(Color(hex: "00d4aa")) } }.padding() if isLoading { ProgressView().tint(Color(hex: "00d4aa")).padding(.top, 40) Spacer() } else { ScrollView { VStack(spacing: 16) { // Summary card if let s = summary { FinanceSummaryCard(summary: s) } // Recent transactions if !transactions.isEmpty { VStack(alignment: .leading, spacing: 8) { Text("Последние операции") .font(.headline).foregroundColor(.white).padding(.horizontal) ForEach(transactions.prefix(20)) { tx in TransactionRowView(transaction: tx, categories: categories) } } } } } } } } .sheet(isPresented: $showAddTransaction) { AddTransactionView(isPresented: $showAddTransaction, categories: categories) { await loadData() } .presentationDetents([.medium, .large]) .presentationDragIndicator(.visible) .presentationBackground(Color(hex: "0a0a1a")) } .task { await loadData() } .refreshable { await loadData(refresh: true) } } func loadData(refresh: Bool = false) async { if !refresh { isLoading = true } async let s = APIService.shared.getFinanceSummary(token: authManager.token) async let t = APIService.shared.getTransactions(token: authManager.token) async let c = APIService.shared.getFinanceCategories(token: authManager.token) summary = try? await s transactions = (try? await t) ?? [] categories = (try? await c) ?? [] isLoading = false } } // MARK: - FinanceSummaryCard struct FinanceSummaryCard: View { let summary: FinanceSummary var body: some View { VStack(spacing: 16) { HStack(spacing: 20) { VStack(spacing: 4) { Text("Доходы").font(.caption).foregroundColor(Color(hex: "8888aa")) Text("+\(Int(summary.totalIncome ?? 0))₽").font(.headline).foregroundColor(Color(hex: "00d4aa")) } Spacer() VStack(spacing: 4) { Text("Баланс").font(.subheadline).foregroundColor(Color(hex: "8888aa")) Text("\(Int(summary.balance ?? 0))₽").font(.title2.bold()).foregroundColor(.white) } Spacer() VStack(spacing: 4) { Text("Расходы").font(.caption).foregroundColor(Color(hex: "8888aa")) Text("-\(Int(summary.totalExpense ?? 0))₽").font(.headline).foregroundColor(Color(hex: "ff4757")) } } } .padding(20) .background(RoundedRectangle(cornerRadius: 20).fill(Color.white.opacity(0.05))) .padding(.horizontal) } } // MARK: - TransactionRowView struct TransactionRowView: View { let transaction: FinanceTransaction let categories: [FinanceCategory] var category: FinanceCategory? { categories.first { $0.id == transaction.categoryId } } var isIncome: Bool { transaction.type == "income" } var body: some View { HStack { Text(category?.icon ?? (isIncome ? "💰" : "💸")).font(.title2) VStack(alignment: .leading, spacing: 2) { Text(transaction.description ?? category?.name ?? "Операция") .font(.callout).foregroundColor(.white) Text(transaction.date ?? "").font(.caption).foregroundColor(Color(hex: "8888aa")) } Spacer() Text("\(isIncome ? "+" : "-")\(Int(transaction.amount))₽") .font(.callout.bold()) .foregroundColor(isIncome ? Color(hex: "00d4aa") : Color(hex: "ff4757")) } .padding(12) .background(RoundedRectangle(cornerRadius: 12).fill(Color.white.opacity(0.04))) .padding(.horizontal) .padding(.vertical, 2) } }