Remove Add Transaction feature and clean all related code

Deleted files:
- AddTransactionView.swift
- TransactionRepository.swift
- Transaction+CoreDataClass.swift

Cleaned files:
- SourceDetailViewModel: removed transactions published property,
  showingAddTransaction flag, transactionRepository dependency,
  addTransaction() and deleteTransaction() methods
- SourceDetailView: removed transactionsSection, TransactionRow struct,
  Add Transaction button from quickActions, sheet presentation
- InvestmentSource+CoreDataClass: removed transactions NSManaged property,
  transactionsArray, totalInvested, totalDividends, totalFees computed
  properties, and all transaction Core Data accessors
- SettingsViewModel: removed "Transaction" from resetAllData entity list
- SampleDataService: removed transactionRepository and sample transaction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
alexandrev-tibco
2026-02-20 23:04:03 +01:00
parent b17d8866a4
commit 7cb5f92cf4
20 changed files with 215 additions and 503 deletions
@@ -1,94 +0,0 @@
import SwiftUI
struct AddTransactionView: View {
@Environment(\.dismiss) private var dismiss
let onSave: (TransactionType, Date, Decimal?, Decimal?, Decimal?, String?) -> Void
@State private var type: TransactionType = .buy
@State private var date = Date()
@State private var shares = ""
@State private var price = ""
@State private var amount = ""
@State private var notes = ""
var body: some View {
NavigationStack {
Form {
Section {
Picker("Type", selection: $type) {
ForEach(TransactionType.allCases) { transactionType in
Text(transactionType.displayName).tag(transactionType)
}
}
DatePicker("Date", selection: $date, displayedComponents: .date)
} header: {
Text("Transaction")
}
Section {
TextField("Shares", text: $shares)
.keyboardType(.decimalPad)
TextField("Price per share", text: $price)
.keyboardType(.decimalPad)
TextField("Total amount", text: $amount)
.keyboardType(.decimalPad)
} header: {
Text("Amounts")
} footer: {
Text("Enter shares and price or just a total amount.")
}
Section {
TextField("Notes", text: $notes, axis: .vertical)
.lineLimit(2...4)
} header: {
Text("Notes (Optional)")
}
}
.navigationTitle("Add Transaction")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") { dismiss() }
}
ToolbarItem(placement: .navigationBarTrailing) {
Button("Save") { save() }
.disabled(!isValid)
}
}
}
.presentationDetents([.medium, .large])
}
private var isValid: Bool {
parseDecimal(shares) != nil || parseDecimal(amount) != nil
}
private func save() {
onSave(
type,
date,
parseDecimal(shares),
parseDecimal(price),
parseDecimal(amount),
notes.isEmpty ? nil : notes
)
dismiss()
}
private func parseDecimal(_ value: String) -> Decimal? {
let cleaned = value
.replacingOccurrences(of: ",", with: ".")
.trimmingCharacters(in: .whitespaces)
guard !cleaned.isEmpty else { return nil }
return Decimal(string: cleaned)
}
}
#Preview {
AddTransactionView { _, _, _, _, _, _ in }
}
@@ -55,9 +55,6 @@ struct SourceDetailView: View {
metricsSection
}
// Transactions
transactionsSection
// Snapshots List
snapshotsSection
}
@@ -95,18 +92,6 @@ struct SourceDetailView: View {
MissingSnapshotView()
}
}
.sheet(isPresented: $viewModel.showingAddTransaction) {
AddTransactionView { type, date, shares, price, amount, notes in
viewModel.addTransaction(
type: type,
date: date,
shares: shares,
price: price,
amount: amount,
notes: notes
)
}
}
.sheet(isPresented: $viewModel.showingEditSource) {
EditSourceView(source: viewModel.source)
}
@@ -187,30 +172,16 @@ struct SourceDetailView: View {
// MARK: - Quick Actions
private var quickActions: some View {
HStack(spacing: 12) {
Button {
viewModel.showingAddSnapshot = true
} label: {
Label("Add Snapshot", systemImage: "plus.circle.fill")
.font(.subheadline.weight(.semibold))
.frame(maxWidth: .infinity)
.padding()
.background(Color.appPrimary)
.foregroundColor(.white)
.cornerRadius(AppConstants.UI.cornerRadius)
}
Button {
viewModel.showingAddTransaction = true
} label: {
Label("Add Transaction", systemImage: "arrow.left.arrow.right.circle")
.font(.subheadline.weight(.semibold))
.frame(maxWidth: .infinity)
.padding()
.background(Color.appSecondary.opacity(0.15))
.foregroundColor(.appSecondary)
.cornerRadius(AppConstants.UI.cornerRadius)
}
Button {
viewModel.showingAddSnapshot = true
} label: {
Label("Add Snapshot", systemImage: "plus.circle.fill")
.font(.subheadline.weight(.semibold))
.frame(maxWidth: .infinity)
.padding()
.background(Color.appPrimary)
.foregroundColor(.white)
.cornerRadius(AppConstants.UI.cornerRadius)
}
}
@@ -362,56 +333,6 @@ struct SourceDetailView: View {
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
}
// MARK: - Transactions Section
private var transactionsSection: some View {
VStack(alignment: .leading, spacing: 12) {
HStack {
Text("Transactions")
.font(.headline)
Spacer()
Text("\(viewModel.transactions.count)")
.font(.subheadline)
.foregroundColor(.secondary)
}
if viewModel.transactions.isEmpty {
Text("Add buys, sells, dividends, and fees to track cashflows.")
.font(.subheadline)
.foregroundColor(.secondary)
} else {
HStack(spacing: 12) {
MetricChip(title: "Invested", value: viewModel.source.totalInvested.compactCurrencyString)
MetricChip(title: "Dividends", value: viewModel.source.totalDividends.compactCurrencyString)
MetricChip(title: "Fees", value: viewModel.source.totalFees.compactCurrencyString)
}
ForEach(viewModel.transactions.prefix(5)) { transaction in
TransactionRow(transaction: transaction)
.contextMenu {
Button(role: .destructive) {
viewModel.deleteTransaction(transaction)
} label: {
Label("Delete", systemImage: "trash")
}
}
}
if viewModel.transactions.count > 5 {
Text("+ \(viewModel.transactions.count - 5) more")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(AppConstants.UI.cornerRadius)
.shadow(color: .black.opacity(0.05), radius: 8, y: 2)
}
// MARK: - Snapshots Section
private var snapshotsSection: some View {
@@ -567,32 +488,6 @@ struct SnapshotRowView: View {
}
}
// MARK: - Transaction Row View
struct TransactionRow: View {
let transaction: Transaction
var body: some View {
HStack {
VStack(alignment: .leading, spacing: 2) {
Text(transaction.transactionType.displayName)
.font(.subheadline.weight(.semibold))
Text(transaction.date.friendlyDescription)
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
Text(transaction.decimalAmount.compactCurrencyString)
.font(.subheadline.weight(.semibold))
.foregroundColor(transaction.transactionType == .fee ? .negativeRed : .primary)
}
.padding(.vertical, 4)
}
}
struct MetricChip: View {
let title: String
let value: String