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 */; };
|
8043704728CBF16600F229F9 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8043704628CBF16600F229F9 /* GoogleService-Info.plist */; };
|
||||||
8043EB84271F26ED00498E73 /* CategoryDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8043EB83271F26ED00498E73 /* CategoryDetailsView.swift */; };
|
8043EB84271F26ED00498E73 /* CategoryDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8043EB83271F26ED00498E73 /* CategoryDetailsView.swift */; };
|
||||||
8044BA3927828E9D009A78D4 /* CategoryDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3827828E9D009A78D4 /* CategoryDataStore.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 */; };
|
8044BA3D2784CC0D009A78D4 /* TransactionForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3C2784CC0D009A78D4 /* TransactionForm.swift */; };
|
||||||
8044BA3F27853054009A78D4 /* CategoryForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3E27853054009A78D4 /* CategoryForm.swift */; };
|
8044BA3F27853054009A78D4 /* CategoryForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3E27853054009A78D4 /* CategoryForm.swift */; };
|
||||||
806C7850272B700B00FA1375 /* TwigsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 806C784F272B700B00FA1375 /* TwigsApp.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
806C784F272B700B00FA1375 /* TwigsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwigsApp.swift; sourceTree = "<group>"; };
|
||||||
|
@ -346,7 +344,6 @@
|
||||||
28FE6B03234449DC00D5543E /* TransactionListView.swift */,
|
28FE6B03234449DC00D5543E /* TransactionListView.swift */,
|
||||||
28FE6B0523444A9800D5543E /* TransactionDetailsView.swift */,
|
28FE6B0523444A9800D5543E /* TransactionDetailsView.swift */,
|
||||||
2821265F23555FD300072D52 /* TransactionFormSheet.swift */,
|
2821265F23555FD300072D52 /* TransactionFormSheet.swift */,
|
||||||
8044BA3A2784B659009A78D4 /* TransactionDetails.swift */,
|
|
||||||
8044BA3C2784CC0D009A78D4 /* TransactionForm.swift */,
|
8044BA3C2784CC0D009A78D4 /* TransactionForm.swift */,
|
||||||
);
|
);
|
||||||
path = Transaction;
|
path = Transaction;
|
||||||
|
@ -621,7 +618,6 @@
|
||||||
2857EAED233DA30B0026BC83 /* LoadingView.swift in Sources */,
|
2857EAED233DA30B0026BC83 /* LoadingView.swift in Sources */,
|
||||||
282126A3235ABC1800072D52 /* TwigsInMemoryCacheService.swift in Sources */,
|
282126A3235ABC1800072D52 /* TwigsInMemoryCacheService.swift in Sources */,
|
||||||
800DFC2C277FF47A00EDCE9B /* AsyncData.swift in Sources */,
|
800DFC2C277FF47A00EDCE9B /* AsyncData.swift in Sources */,
|
||||||
8044BA3B2784B659009A78D4 /* TransactionDetails.swift in Sources */,
|
|
||||||
28B9E50E2346BCB2007C3909 /* RegistrationView.swift in Sources */,
|
28B9E50E2346BCB2007C3909 /* RegistrationView.swift in Sources */,
|
||||||
284102322342E12F00EAFA29 /* CategoryListView.swift in Sources */,
|
284102322342E12F00EAFA29 /* CategoryListView.swift in Sources */,
|
||||||
8043EB84271F26ED00498E73 /* CategoryDetailsView.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() {
|
func newBudget() {
|
||||||
self.budget = .editing(Budget(id: "", name: "", description: "", currencyCode: ""))
|
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 {
|
func save(_ category: TwigsCore.Category) async {
|
||||||
self.category = .loading
|
self.category = .loading
|
||||||
do {
|
do {
|
||||||
|
@ -731,7 +747,7 @@ class DataStore : ObservableObject {
|
||||||
self.user = .success(user)
|
self.user = .success(user)
|
||||||
} catch {
|
} catch {
|
||||||
self.errorReporter.reportError(error: error)
|
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 {
|
struct TransactionDetailsView: View {
|
||||||
@EnvironmentObject var apiService: TwigsApiService
|
@EnvironmentObject var apiService: TwigsApiService
|
||||||
@EnvironmentObject var dataStore: DataStore
|
@EnvironmentObject var dataStore: DataStore
|
||||||
@ObservedObject var transactionDetails: TransactionDetails
|
|
||||||
var editing: Bool {
|
var editing: Bool {
|
||||||
if case .editing(_) = dataStore.transaction {
|
if case .editing(_) = dataStore.transaction {
|
||||||
return true
|
return true
|
||||||
|
@ -24,9 +23,6 @@ struct TransactionDetailsView: View {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
init(_ transactionDetails: TransactionDetails) {
|
|
||||||
self.transactionDetails = transactionDetails
|
|
||||||
}
|
|
||||||
private var currentUserId: String? {
|
private var currentUserId: String? {
|
||||||
get {
|
get {
|
||||||
if case let .success(currentUser) = self.dataStore.currentUser {
|
if case let .success(currentUser) = self.dataStore.currentUser {
|
||||||
|
@ -55,14 +51,13 @@ struct TransactionDetailsView: View {
|
||||||
if let description = transaction.description {
|
if let description = transaction.description {
|
||||||
LabeledField(label: "notes", value: description, loading: .constant(false), showDivider: true)
|
LabeledField(label: "notes", value: description, loading: .constant(false), showDivider: true)
|
||||||
}
|
}
|
||||||
CategoryLineItem()
|
if let categoryId = transaction.categoryId {
|
||||||
BudgetLineItem()
|
CategoryLineItem(id: categoryId)
|
||||||
UserLineItem()
|
|
||||||
}.padding()
|
|
||||||
.environmentObject(transactionDetails)
|
|
||||||
.task {
|
|
||||||
await transactionDetails.loadDetails(transaction)
|
|
||||||
}
|
}
|
||||||
|
BudgetLineItem(id: transaction.budgetId)
|
||||||
|
UserLineItem(id: transaction.createdBy)
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
}
|
}
|
||||||
.navigationBarItems(trailing: Button(
|
.navigationBarItems(trailing: Button(
|
||||||
action: { self.dataStore.editTransaction(transaction) }
|
action: { self.dataStore.editTransaction(transaction) }
|
||||||
|
@ -92,7 +87,6 @@ struct LabeledField: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if let val = value, !val.isEmpty {
|
|
||||||
VStack {
|
VStack {
|
||||||
HStack {
|
HStack {
|
||||||
Text(self.label)
|
Text(self.label)
|
||||||
|
@ -101,7 +95,7 @@ struct LabeledField: View {
|
||||||
if loading {
|
if loading {
|
||||||
EmbeddedLoadingView()
|
EmbeddedLoadingView()
|
||||||
} else {
|
} else {
|
||||||
Text(verbatim: val)
|
Text(verbatim: self.value ?? "")
|
||||||
.multilineTextAlignment(.trailing)
|
.multilineTextAlignment(.trailing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,13 +105,13 @@ struct LabeledField: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct CategoryLineItem: View {
|
struct CategoryLineItem: View {
|
||||||
@EnvironmentObject var transactionDetails: TransactionDetails
|
let id: String
|
||||||
|
@EnvironmentObject var dataStore: DataStore
|
||||||
var value: String {
|
var value: String {
|
||||||
// TODO: Show errors
|
// TODO: Show errors
|
||||||
if case let .success(category) = transactionDetails.category {
|
if let category = dataStore.getCategory(id) {
|
||||||
return category.title
|
return category.title
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
|
@ -126,19 +120,16 @@ struct CategoryLineItem: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var body: some View {
|
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 {
|
struct BudgetLineItem: View {
|
||||||
@EnvironmentObject var transactionDetails: TransactionDetails
|
let id: String
|
||||||
|
@EnvironmentObject var dataStore: DataStore
|
||||||
var value: String {
|
var value: String {
|
||||||
// TODO: Show errors
|
// TODO: Show errors
|
||||||
if case let .success(budget) = transactionDetails.budget {
|
if let budget = dataStore.getBudget(id) {
|
||||||
return budget.name
|
return budget.name
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
|
@ -147,19 +138,16 @@ struct BudgetLineItem: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var body: some View {
|
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 {
|
struct UserLineItem: View {
|
||||||
@EnvironmentObject var transactionDetails: TransactionDetails
|
let id: String
|
||||||
|
@EnvironmentObject var dataStore: DataStore
|
||||||
var value: String {
|
var value: String {
|
||||||
// TODO: Show errors
|
// TODO: Show errors
|
||||||
if case let .success(user) = transactionDetails.user {
|
if case let .success(user) = dataStore.user, user.id == id {
|
||||||
return user.username
|
return user.username
|
||||||
} else {
|
} else {
|
||||||
return ""
|
return ""
|
||||||
|
@ -168,10 +156,9 @@ struct UserLineItem: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
var body: some View {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +166,7 @@ struct UserLineItem: View {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
struct TransactionDetailsView_Previews: PreviewProvider {
|
struct TransactionDetailsView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
TransactionDetailsView(TransactionDetails(TwigsInMemoryCacheService()))
|
TransactionDetailsView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -138,7 +138,7 @@ struct TransactionListItemView: View {
|
||||||
tag: self.transaction,
|
tag: self.transaction,
|
||||||
selection: self.$dataStore.selectedTransaction,
|
selection: self.$dataStore.selectedTransaction,
|
||||||
destination: {
|
destination: {
|
||||||
TransactionDetailsView(TransactionDetails(dataStore.apiService))
|
TransactionDetailsView()
|
||||||
.navigationBarTitle("details", displayMode: .inline)
|
.navigationBarTitle("details", displayMode: .inline)
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
|
|
Loading…
Reference in a new issue