From a434d46b18ed0f482bd392e08fe3d50fa2af116f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CSamoilenkoVadym=E2=80=9D?= <“samoylenko.vadym@gmail.com”> Date: Sun, 2 Mar 2025 19:50:51 +0000 Subject: [PATCH] Add account management models: AccountModel and AccountsStore. Implement different account types (wallet, bank account, credit card, deposit, debt) with their specific properties --- Coinly/Features/Models/AccountModel.swift | 125 +++++++++++++++++++++ Coinly/Features/Models/AccountsStore.swift | 45 ++++++++ 2 files changed, 170 insertions(+) create mode 100644 Coinly/Features/Models/AccountModel.swift create mode 100644 Coinly/Features/Models/AccountsStore.swift diff --git a/Coinly/Features/Models/AccountModel.swift b/Coinly/Features/Models/AccountModel.swift new file mode 100644 index 0000000..a28e529 --- /dev/null +++ b/Coinly/Features/Models/AccountModel.swift @@ -0,0 +1,125 @@ +// +// AccountType.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import Foundation + +enum AccountType: String, Codable, CaseIterable { + case wallet = "Wallet" // Наличные/кошелек + case bankAccount = "Bank" // Банковский счет + case creditCard = "Credit" // Кредитная карта + case deposit = "Deposit" // Депозит + case debt = "Debt" // Долг + + var icon: String { + switch self { + case .wallet: return "wallet.pass" + case .bankAccount: return "building.columns" + case .creditCard: return "creditcard" + case .deposit: return "banknote" + case .debt: return "exclamationmark.circle" + } + } +} + +struct AccountModel: Identifiable, Codable { + let id: String + var name: String + var type: AccountType + var currency: AppSettings.Currency + var balance: Double + var initialBalance: Double + + // Для кредитных карт + var creditLimit: Double? + var interestRate: Double? + var dueDate: Date? + + // Для депозитов + var depositInterestRate: Double? + var depositEndDate: Date? + + // Для долгов + var debtInterestRate: Double? + var debtDueDate: Date? + var creditorName: String? + + init( + name: String, + type: AccountType, + currency: AppSettings.Currency, + balance: Double, + initialBalance: Double = 0, + creditLimit: Double? = nil, + interestRate: Double? = nil, + dueDate: Date? = nil, + depositInterestRate: Double? = nil, + depositEndDate: Date? = nil, + debtInterestRate: Double? = nil, + debtDueDate: Date? = nil, + creditorName: String? = nil + ) { + self.id = UUID().uuidString + self.name = name + self.type = type + self.currency = currency + self.balance = balance + self.initialBalance = initialBalance + self.creditLimit = creditLimit + self.interestRate = interestRate + self.dueDate = dueDate + self.depositInterestRate = depositInterestRate + self.depositEndDate = depositEndDate + self.debtInterestRate = debtInterestRate + self.debtDueDate = debtDueDate + self.creditorName = creditorName + } + + // Вычисляемые свойства + var availableCredit: Double? { + guard type == .creditCard, let limit = creditLimit else { return nil } + return limit - balance + } + + var isOverdue: Bool { + guard let dueDate = dueDate ?? debtDueDate else { return false } + return Date() > dueDate + } + + // Sample Data + static let sampleData = [ + AccountModel( + name: "Cash Wallet", + type: .wallet, + currency: .usd, + balance: 500 + ), + AccountModel( + name: "Main Bank Account", + type: .bankAccount, + currency: .usd, + balance: 2500 + ), + AccountModel( + name: "Credit Card", + type: .creditCard, + currency: .usd, + balance: 1000, + creditLimit: 5000, + interestRate: 19.9, + dueDate: Calendar.current.date(byAdding: .day, value: 15, to: Date()) + ), + AccountModel( + name: "Savings Deposit", + type: .deposit, + currency: .usd, + balance: 10000, + depositInterestRate: 5.5, + depositEndDate: Calendar.current.date(byAdding: .month, value: 12, to: Date()) + ) + ] +} diff --git a/Coinly/Features/Models/AccountsStore.swift b/Coinly/Features/Models/AccountsStore.swift new file mode 100644 index 0000000..26545e6 --- /dev/null +++ b/Coinly/Features/Models/AccountsStore.swift @@ -0,0 +1,45 @@ +// +// AccountsStore.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import Foundation + +class AccountsStore: ObservableObject { + @Published private(set) var accounts: [AccountModel] = AccountModel.sampleData + + func addAccount(_ account: AccountModel) { + accounts.append(account) + } + + func updateAccount(_ account: AccountModel) { + if let index = accounts.firstIndex(where: { $0.id == account.id }) { + accounts[index] = account + } + } + + func deleteAccount(at indexSet: IndexSet) { + accounts.remove(atOffsets: indexSet) + } + + func getAccount(by id: String) -> AccountModel? { + accounts.first { $0.id == id } + } + + // Получение счетов по типу + func getAccounts(of type: AccountType) -> [AccountModel] { + accounts.filter { $0.type == type } + } + + // Общий баланс всех счетов в выбранной валюте + func totalBalance(in currency: AppSettings.Currency) -> Double { + accounts.reduce(0) { total, account in + let settings = AppSettings.shared + let convertedBalance = settings.convert(account.balance, from: account.currency, to: currency) + return total + convertedBalance + } + } +} \ No newline at end of file