Primera build enviada

This commit is contained in:
2026-01-19 14:40:43 +01:00
parent c6be398e5a
commit b03d35194f
36 changed files with 1641 additions and 561 deletions
@@ -10,19 +10,28 @@ struct AddSourceView: View {
@State private var initialValue = ""
@State private var showingCategoryPicker = false
@State private var selectedAccountId: UUID?
@State private var duplicateError: String?
@StateObject private var categoryRepository = CategoryRepository()
@StateObject private var sourceRepository = InvestmentSourceRepository()
private var availableAccounts: [Account] {
accountStore.accounts.filter { $0.safeId != nil }
}
var body: some View {
NavigationStack {
Form {
if accountStore.accounts.count > 1 {
if availableAccounts.count > 1 {
Section {
Picker("Account", selection: $selectedAccountId) {
ForEach(accountStore.accounts) { account in
Text(account.name).tag(Optional(account.id))
ForEach(availableAccounts, id: \.objectID) { account in
Text(account.name).tag(Optional(account.safeId))
}
}
.onChange(of: selectedAccountId) { _, _ in
validateSourceName(name)
}
} header: {
Text("Account")
}
@@ -32,6 +41,9 @@ struct AddSourceView: View {
Section {
TextField("Source Name", text: $name)
.textContentType(.organizationName)
.onChange(of: name) { _, newValue in
validateSourceName(newValue)
}
Button {
showingCategoryPicker = true
@@ -61,6 +73,11 @@ struct AddSourceView: View {
}
} header: {
Text("Source Information")
} footer: {
if let error = duplicateError {
Text(error)
.foregroundColor(.negativeRed)
}
}
// Initial Value (Optional)
@@ -107,7 +124,7 @@ struct AddSourceView: View {
selectedCategory = categoryRepository.categories.first
}
if selectedAccountId == nil {
selectedAccountId = accountStore.selectedAccount?.id ?? accountStore.accounts.first?.id
selectedAccountId = accountStore.selectedAccount?.safeId ?? availableAccounts.first?.safeId
}
}
}
@@ -116,7 +133,21 @@ struct AddSourceView: View {
// MARK: - Validation
private var isValid: Bool {
!name.trimmingCharacters(in: .whitespaces).isEmpty && selectedCategory != nil
!name.trimmingCharacters(in: .whitespaces).isEmpty && selectedCategory != nil && duplicateError == nil
}
private func validateSourceName(_ newName: String) {
let trimmed = newName.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else {
duplicateError = nil
return
}
if sourceRepository.sourceExists(name: trimmed, in: selectedAccount) {
duplicateError = "A source with this name already exists."
} else {
duplicateError = nil
}
}
// MARK: - Save
@@ -177,7 +208,7 @@ struct AddSourceView: View {
private var selectedAccount: Account? {
guard let id = selectedAccountId else { return nil }
return accountStore.accounts.first { $0.id == id }
return availableAccounts.first { $0.safeId == id }
}
}
@@ -248,17 +279,17 @@ struct EditSourceView: View {
self.source = source
_name = State(initialValue: source.name)
_selectedCategory = State(initialValue: source.category)
_selectedAccountId = State(initialValue: source.account?.id)
_selectedAccountId = State(initialValue: source.account?.safeId)
}
var body: some View {
NavigationStack {
Form {
if accountStore.accounts.count > 1 {
if availableAccounts.count > 1 {
Section {
Picker("Account", selection: $selectedAccountId) {
ForEach(accountStore.accounts) { account in
Text(account.name).tag(Optional(account.id))
ForEach(availableAccounts, id: \.objectID) { account in
Text(account.name).tag(Optional(account.safeId))
}
}
} header: {
@@ -320,6 +351,10 @@ struct EditSourceView: View {
}
}
private var availableAccounts: [Account] {
accountStore.accounts.filter { $0.safeId != nil }
}
private var isValid: Bool {
!name.trimmingCharacters(in: .whitespaces).isEmpty && selectedCategory != nil
}
@@ -343,7 +378,7 @@ struct EditSourceView: View {
private var selectedAccount: Account? {
guard let id = selectedAccountId else { return nil }
return accountStore.accounts.first { $0.id == id }
return availableAccounts.first { $0.safeId == id }
}
}