Fix budget/category/user disappearing on transaction details
This commit is contained in:
parent
f6ff3bc724
commit
9f7ef79c98
5 changed files with 53 additions and 120 deletions
|
@ -45,7 +45,6 @@
|
|||
8043704728CBF16600F229F9 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8043704628CBF16600F229F9 /* GoogleService-Info.plist */; };
|
||||
8043EB84271F26ED00498E73 /* CategoryDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8043EB83271F26ED00498E73 /* CategoryDetailsView.swift */; };
|
||||
8044BA3927828E9D009A78D4 /* CategoryDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3827828E9D009A78D4 /* CategoryDataStore.swift */; };
|
||||
8044BA3B2784B659009A78D4 /* TransactionDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3A2784B659009A78D4 /* TransactionDetails.swift */; };
|
||||
8044BA3D2784CC0D009A78D4 /* TransactionForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3C2784CC0D009A78D4 /* TransactionForm.swift */; };
|
||||
8044BA3F27853054009A78D4 /* CategoryForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3E27853054009A78D4 /* CategoryForm.swift */; };
|
||||
806C7850272B700B00FA1375 /* TwigsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 806C784F272B700B00FA1375 /* TwigsApp.swift */; };
|
||||
|
@ -144,7 +143,6 @@
|
|||
8043704628CBF16600F229F9 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../Downloads/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
8043EB83271F26ED00498E73 /* CategoryDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDetailsView.swift; sourceTree = "<group>"; };
|
||||
8044BA3827828E9D009A78D4 /* CategoryDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDataStore.swift; sourceTree = "<group>"; };
|
||||
8044BA3A2784B659009A78D4 /* TransactionDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionDetails.swift; sourceTree = "<group>"; };
|
||||
8044BA3C2784CC0D009A78D4 /* TransactionForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionForm.swift; sourceTree = "<group>"; };
|
||||
8044BA3E27853054009A78D4 /* CategoryForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryForm.swift; sourceTree = "<group>"; };
|
||||
806C784F272B700B00FA1375 /* TwigsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwigsApp.swift; sourceTree = "<group>"; };
|
||||
|
@ -346,7 +344,6 @@
|
|||
28FE6B03234449DC00D5543E /* TransactionListView.swift */,
|
||||
28FE6B0523444A9800D5543E /* TransactionDetailsView.swift */,
|
||||
2821265F23555FD300072D52 /* TransactionFormSheet.swift */,
|
||||
8044BA3A2784B659009A78D4 /* TransactionDetails.swift */,
|
||||
8044BA3C2784CC0D009A78D4 /* TransactionForm.swift */,
|
||||
);
|
||||
path = Transaction;
|
||||
|
@ -621,7 +618,6 @@
|
|||
2857EAED233DA30B0026BC83 /* LoadingView.swift in Sources */,
|
||||
282126A3235ABC1800072D52 /* TwigsInMemoryCacheService.swift in Sources */,
|
||||
800DFC2C277FF47A00EDCE9B /* AsyncData.swift in Sources */,
|
||||
8044BA3B2784B659009A78D4 /* TransactionDetails.swift in Sources */,
|
||||
28B9E50E2346BCB2007C3909 /* RegistrationView.swift in Sources */,
|
||||
284102322342E12F00EAFA29 /* CategoryListView.swift in Sources */,
|
||||
8043EB84271F26ED00498E73 /* CategoryDetailsView.swift in Sources */,
|
||||
|
|
|
@ -104,6 +104,14 @@ class DataStore : ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func getBudget(_ id: String) -> TwigsCore.Budget? {
|
||||
if case let .success(budgets) = self.budgets {
|
||||
return budgets.first(where: { $0.id == id })
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newBudget() {
|
||||
self.budget = .editing(Budget(id: "", name: "", description: "", currencyCode: ""))
|
||||
}
|
||||
|
@ -253,6 +261,14 @@ class DataStore : ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
func getCategory(_ id: String) -> TwigsCore.Category? {
|
||||
if case let .success(categories) = self.categories {
|
||||
return categories.first(where: { $0.id == id })
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func save(_ category: TwigsCore.Category) async {
|
||||
self.category = .loading
|
||||
do {
|
||||
|
@ -731,7 +747,7 @@ class DataStore : ObservableObject {
|
|||
self.user = .success(user)
|
||||
} catch {
|
||||
self.errorReporter.reportError(error: error)
|
||||
self.currentUser = .error(error)
|
||||
self.user = .error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
//
|
||||
// TransactionDetail.swift
|
||||
// Twigs
|
||||
//
|
||||
// Created by William Brawner on 1/4/22.
|
||||
// Copyright © 2022 William Brawner. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import TwigsCore
|
||||
|
||||
@MainActor
|
||||
class TransactionDetails: ObservableObject {
|
||||
@Published var category: AsyncData<TwigsCore.Category> = .empty
|
||||
@Published var budget: AsyncData<Budget> = .empty
|
||||
@Published var user: AsyncData<User> = .empty
|
||||
let apiService: TwigsApiService
|
||||
|
||||
init(_ apiService: TwigsApiService) {
|
||||
self.apiService = apiService
|
||||
}
|
||||
|
||||
func loadDetails(_ transaction: TwigsCore.Transaction) async {
|
||||
Task {
|
||||
await loadBudget(transaction.budgetId)
|
||||
}
|
||||
Task {
|
||||
if let categoryId = transaction.categoryId {
|
||||
await loadCategory(categoryId)
|
||||
}
|
||||
}
|
||||
Task {
|
||||
await loadUser(transaction.createdBy)
|
||||
}
|
||||
}
|
||||
|
||||
private func loadBudget(_ id: String) async {
|
||||
self.budget = .loading
|
||||
do {
|
||||
let budget = try await apiService.getBudget(id)
|
||||
self.budget = .success(budget)
|
||||
} catch {
|
||||
self.budget = .error(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func loadCategory(_ id: String) async {
|
||||
self.category = .loading
|
||||
do {
|
||||
let category = try await apiService.getCategory(id)
|
||||
self.category = .success(category)
|
||||
} catch {
|
||||
self.category = .error(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func loadUser(_ id: String) async {
|
||||
self.user = .loading
|
||||
do {
|
||||
let user = try await apiService.getUser(id)
|
||||
self.user = .success(user)
|
||||
} catch {
|
||||
self.user = .error(error)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ import ArgumentParser
|
|||
struct TransactionDetailsView: View {
|
||||
@EnvironmentObject var apiService: TwigsApiService
|
||||
@EnvironmentObject var dataStore: DataStore
|
||||
@ObservedObject var transactionDetails: TransactionDetails
|
||||
var editing: Bool {
|
||||
if case .editing(_) = dataStore.transaction {
|
||||
return true
|
||||
|
@ -24,9 +23,6 @@ struct TransactionDetailsView: View {
|
|||
return false
|
||||
}
|
||||
|
||||
init(_ transactionDetails: TransactionDetails) {
|
||||
self.transactionDetails = transactionDetails
|
||||
}
|
||||
private var currentUserId: String? {
|
||||
get {
|
||||
if case let .success(currentUser) = self.dataStore.currentUser {
|
||||
|
@ -55,14 +51,13 @@ struct TransactionDetailsView: View {
|
|||
if let description = transaction.description {
|
||||
LabeledField(label: "notes", value: description, loading: .constant(false), showDivider: true)
|
||||
}
|
||||
CategoryLineItem()
|
||||
BudgetLineItem()
|
||||
UserLineItem()
|
||||
}.padding()
|
||||
.environmentObject(transactionDetails)
|
||||
.task {
|
||||
await transactionDetails.loadDetails(transaction)
|
||||
if let categoryId = transaction.categoryId {
|
||||
CategoryLineItem(id: categoryId)
|
||||
}
|
||||
BudgetLineItem(id: transaction.budgetId)
|
||||
UserLineItem(id: transaction.createdBy)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationBarItems(trailing: Button(
|
||||
action: { self.dataStore.editTransaction(transaction) }
|
||||
|
@ -92,32 +87,31 @@ struct LabeledField: View {
|
|||
|
||||
@ViewBuilder
|
||||
var body: some View {
|
||||
if let val = value, !val.isEmpty {
|
||||
VStack {
|
||||
HStack {
|
||||
Text(self.label)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
if loading {
|
||||
EmbeddedLoadingView()
|
||||
} else {
|
||||
Text(verbatim: val)
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
}
|
||||
if showDivider {
|
||||
Divider()
|
||||
VStack {
|
||||
HStack {
|
||||
Text(self.label)
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
if loading {
|
||||
EmbeddedLoadingView()
|
||||
} else {
|
||||
Text(verbatim: self.value ?? "")
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
}
|
||||
if showDivider {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CategoryLineItem: View {
|
||||
@EnvironmentObject var transactionDetails: TransactionDetails
|
||||
let id: String
|
||||
@EnvironmentObject var dataStore: DataStore
|
||||
var value: String {
|
||||
// TODO: Show errors
|
||||
if case let .success(category) = transactionDetails.category {
|
||||
if let category = dataStore.getCategory(id) {
|
||||
return category.title
|
||||
} else {
|
||||
return ""
|
||||
|
@ -126,19 +120,16 @@ struct CategoryLineItem: View {
|
|||
|
||||
@ViewBuilder
|
||||
var body: some View {
|
||||
if case .empty = transactionDetails.category {
|
||||
EmptyView()
|
||||
} else {
|
||||
LabeledField(label: "category", value: value, loading: .constant(self.value == ""), showDivider: true)
|
||||
}
|
||||
LabeledField(label: "category", value: value, loading: .constant(self.value == ""), showDivider: true)
|
||||
}
|
||||
}
|
||||
|
||||
struct BudgetLineItem: View {
|
||||
@EnvironmentObject var transactionDetails: TransactionDetails
|
||||
let id: String
|
||||
@EnvironmentObject var dataStore: DataStore
|
||||
var value: String {
|
||||
// TODO: Show errors
|
||||
if case let .success(budget) = transactionDetails.budget {
|
||||
if let budget = dataStore.getBudget(id) {
|
||||
return budget.name
|
||||
} else {
|
||||
return ""
|
||||
|
@ -147,19 +138,16 @@ struct BudgetLineItem: View {
|
|||
|
||||
@ViewBuilder
|
||||
var body: some View {
|
||||
if case .empty = transactionDetails.budget {
|
||||
EmptyView()
|
||||
} else {
|
||||
LabeledField(label: "budget", value: value, loading: .constant(self.value == ""), showDivider: true)
|
||||
}
|
||||
LabeledField(label: "budget", value: value, loading: .constant(self.value == ""), showDivider: true)
|
||||
}
|
||||
}
|
||||
|
||||
struct UserLineItem: View {
|
||||
@EnvironmentObject var transactionDetails: TransactionDetails
|
||||
let id: String
|
||||
@EnvironmentObject var dataStore: DataStore
|
||||
var value: String {
|
||||
// TODO: Show errors
|
||||
if case let .success(user) = transactionDetails.user {
|
||||
if case let .success(user) = dataStore.user, user.id == id {
|
||||
return user.username
|
||||
} else {
|
||||
return ""
|
||||
|
@ -168,18 +156,17 @@ struct UserLineItem: View {
|
|||
|
||||
@ViewBuilder
|
||||
var body: some View {
|
||||
if case .empty = transactionDetails.user {
|
||||
EmptyView()
|
||||
} else {
|
||||
LabeledField(label: "created_by", value: value, loading: .constant(self.value == ""), showDivider: false)
|
||||
}
|
||||
LabeledField(label: "created_by", value: value, loading: .constant(self.value == ""), showDivider: false)
|
||||
.task {
|
||||
await dataStore.getUser(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
struct TransactionDetailsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TransactionDetailsView(TransactionDetails(TwigsInMemoryCacheService()))
|
||||
TransactionDetailsView()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -138,7 +138,7 @@ struct TransactionListItemView: View {
|
|||
tag: self.transaction,
|
||||
selection: self.$dataStore.selectedTransaction,
|
||||
destination: {
|
||||
TransactionDetailsView(TransactionDetails(dataStore.apiService))
|
||||
TransactionDetailsView()
|
||||
.navigationBarTitle("details", displayMode: .inline)
|
||||
},
|
||||
label: {
|
||||
|
|
Loading…
Reference in a new issue