diff --git a/Coinly/App/ContentView.swift b/Coinly/App/ContentView.swift index b47435d..0c82bcb 100644 --- a/Coinly/App/ContentView.swift +++ b/Coinly/App/ContentView.swift @@ -2,14 +2,18 @@ import SwiftUI struct ContentView: View { @StateObject private var transactionsStore = TransactionsStore() + @StateObject private var accountsStore = AccountsStore() @StateObject private var settings = AppSettings.shared var body: some View { TabView { - DashboardView(store: transactionsStore) - .tabItem { - Label("Dashboard", systemImage: "chart.pie.fill") - } + DashboardView( + store: transactionsStore, + accountsStore: accountsStore + ) + .tabItem { + Label("Dashboard", systemImage: "chart.pie.fill") + } TransactionsView(store: transactionsStore) .tabItem { @@ -24,3 +28,9 @@ struct ContentView: View { .environmentObject(settings) } } + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/Coinly/Features/Accounts/AccountsListView.swift b/Coinly/Features/Accounts/AccountsListView.swift new file mode 100644 index 0000000..18b69da --- /dev/null +++ b/Coinly/Features/Accounts/AccountsListView.swift @@ -0,0 +1,54 @@ +// +// AccountsListView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct AccountsListView: View { + @Environment(\.dismiss) private var dismiss + @ObservedObject var store: AccountsStore + @State private var showingAddAccount = false + + var body: some View { + NavigationView { + List { + ForEach(AccountType.allCases, id: \.self) { type in + Section(type.rawValue) { + ForEach(store.getAccounts(of: type)) { account in + AccountCardView(account: account) + } + } + } + } + .listStyle(InsetGroupedListStyle()) + .navigationTitle("Accounts") + .navigationBarTitleDisplayMode(.large) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button("Close") { + dismiss() + } + } + + ToolbarItem(placement: .navigationBarTrailing) { + Button { + showingAddAccount = true + } label: { + Image(systemName: "plus") + } + } + } + } + } +} + +struct AccountsListView_Previews: PreviewProvider { + static var previews: some View { + AccountsListView(store: AccountsStore()) + .environmentObject(AppSettings.shared) + } +} \ No newline at end of file diff --git a/Coinly/Features/Dashboard/DashboardView.swift b/Coinly/Features/Dashboard/DashboardView.swift index 63785fa..69c7c7f 100644 --- a/Coinly/Features/Dashboard/DashboardView.swift +++ b/Coinly/Features/Dashboard/DashboardView.swift @@ -2,6 +2,7 @@ import SwiftUI struct DashboardView: View { @ObservedObject var store: TransactionsStore + @ObservedObject var accountsStore: AccountsStore @EnvironmentObject private var settings: AppSettings private var totalBalance: Double { @@ -58,6 +59,9 @@ struct DashboardView: View { .cornerRadius(12) .shadow(radius: 2) + // Accounts Summary + AccountsSummaryView(accountsStore: accountsStore) + // Income/Expense Summary HStack(spacing: 16) { // Income Card @@ -157,7 +161,10 @@ struct DashboardView: View { struct DashboardView_Previews: PreviewProvider { static var previews: some View { - DashboardView(store: TransactionsStore()) - .environmentObject(AppSettings.shared) + DashboardView( + store: TransactionsStore(), + accountsStore: AccountsStore() + ) + .environmentObject(AppSettings.shared) } } diff --git a/Coinly/UI/Components/AccountCardView.swift b/Coinly/UI/Components/AccountCardView.swift new file mode 100644 index 0000000..081bfd3 --- /dev/null +++ b/Coinly/UI/Components/AccountCardView.swift @@ -0,0 +1,83 @@ +// +// AccountCardView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct AccountCardView: View { + let account: AccountModel + @EnvironmentObject private var settings: AppSettings + + private var accountIcon: String { + account.type.icon + } + + private var accountColor: Color { + switch account.type { + case .wallet: return .blue + case .bankAccount: return .green + case .creditCard: return .purple + case .deposit: return .orange + case .debt: return .red + } + } + + var body: some View { + VStack(alignment: .leading, spacing: 12) { + // Header + HStack { + Image(systemName: accountIcon) + .font(.title2) + .foregroundColor(accountColor) + + Text(account.name) + .font(.headline) + + Spacer() + + Text(account.currency.symbol) + .font(.subheadline) + .foregroundColor(.gray) + } + + // Balance + Text(account.balance.formatAsCurrency()) + .font(.title2) + .fontWeight(.bold) + + // Additional Info + if let availableCredit = account.availableCredit { + Text("Available: \(availableCredit.formatAsCurrency())") + .font(.caption) + .foregroundColor(.gray) + } + + if account.isOverdue { + Label("Overdue", systemImage: "exclamationmark.circle.fill") + .font(.caption) + .foregroundColor(.red) + } + } + .padding() + .background(Color(.systemBackground)) + .cornerRadius(12) + .shadow(radius: 2) + } +} + +struct AccountCardView_Previews: PreviewProvider { + static var previews: some View { + Group { + AccountCardView(account: AccountModel.sampleData[0]) + AccountCardView(account: AccountModel.sampleData[2]) + } + .padding() + .background(Color(.systemGroupedBackground)) + .environmentObject(AppSettings.shared) + .previewLayout(.sizeThatFits) + } +} \ No newline at end of file diff --git a/Coinly/UI/Components/AccountsSummaryView.swift b/Coinly/UI/Components/AccountsSummaryView.swift new file mode 100644 index 0000000..7ef1ef3 --- /dev/null +++ b/Coinly/UI/Components/AccountsSummaryView.swift @@ -0,0 +1,67 @@ +// +// AccountsSummaryView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct AccountsSummaryView: View { + @ObservedObject var accountsStore: AccountsStore + @EnvironmentObject private var settings: AppSettings + @State private var showingAccountsList = false + + private var totalBalance: Double { + accountsStore.totalBalance(in: settings.currency) + } + + var body: some View { + VStack(spacing: 16) { + // Header with total balance + VStack(spacing: 8) { + Text("Total Assets") + .font(.subheadline) + .foregroundColor(.gray) + + Text(totalBalance.formatAsCurrency()) + .font(.title2) + .fontWeight(.bold) + } + + // Recent accounts preview + VStack(spacing: 12) { + ForEach(Array(accountsStore.accounts.prefix(2))) { account in + AccountCardView(account: account) + } + } + + // Show all button + Button(action: { + showingAccountsList = true + }) { + Text("Show All Accounts") + .font(.headline) + .foregroundColor(.blue) + } + } + .padding() + .background(Color(.systemBackground)) + .cornerRadius(12) + .shadow(radius: 2) + .sheet(isPresented: $showingAccountsList) { + AccountsListView(store: accountsStore) + } + } +} + +struct AccountsSummaryView_Previews: PreviewProvider { + static var previews: some View { + AccountsSummaryView(accountsStore: AccountsStore()) + .environmentObject(AppSettings.shared) + .padding() + .background(Color(.systemGroupedBackground)) + .previewLayout(.sizeThatFits) + } +} \ No newline at end of file