diff --git a/Data/Data/Model/Transaction.swift b/Data/Data/Model/Transaction.swift index 53690f9f0..2e0eef4cc 100644 --- a/Data/Data/Model/Transaction.swift +++ b/Data/Data/Model/Transaction.swift @@ -17,19 +17,22 @@ public struct Transactions: Codable, Hashable, Identifiable { public var updatedBy: String public var note: String? public var imageUrl: String? + public var reason: String? public var amount: Double public var date: Timestamp public var updatedAt: Timestamp public var isActive: Bool public init(payerId: String, receiverId: String, addedBy: String, updatedBy: String, note: String? = nil, - imageUrl: String? = nil, amount: Double, date: Timestamp, updatedAt: Timestamp = Timestamp(), isActive: Bool = true) { + imageUrl: String? = nil, reason: String? = nil, amount: Double, date: Timestamp, + updatedAt: Timestamp = Timestamp(), isActive: Bool = true) { self.payerId = payerId self.receiverId = receiverId self.addedBy = addedBy self.updatedBy = updatedBy self.note = note self.imageUrl = imageUrl + self.reason = reason self.amount = amount self.date = date self.updatedAt = updatedAt @@ -42,8 +45,9 @@ public struct Transactions: Codable, Hashable, Identifiable { case receiverId = "receiver_id" case addedBy = "added_by" case updatedBy = "updated_by" - case note = "note" + case note case imageUrl = "image_url" + case reason case amount case date case updatedAt = "updated_at" diff --git a/Splito/Localization/Localizable.xcstrings b/Splito/Localization/Localizable.xcstrings index fb749de72..1da6cf9ad 100644 --- a/Splito/Localization/Localizable.xcstrings +++ b/Splito/Localization/Localizable.xcstrings @@ -310,6 +310,9 @@ }, "Enter a description" : { "extractionState" : "manual" + }, + "Enter a reason for this payment" : { + }, "Enter a valid phone number." : { "extractionState" : "manual" @@ -511,6 +514,9 @@ }, "not involved" : { + }, + "Note" : { + }, "Note:" : { @@ -595,6 +601,9 @@ }, "Reach out to your friends to get the code of the group they created." : { + }, + "Reason" : { + }, "Reauthenticate" : { "extractionState" : "manual" diff --git a/Splito/UI/Home/Expense/AddExpenseView.swift b/Splito/UI/Home/Expense/AddExpenseView.swift index 43b335303..b79a27fe9 100644 --- a/Splito/UI/Home/Expense/AddExpenseView.swift +++ b/Splito/UI/Home/Expense/AddExpenseView.swift @@ -79,7 +79,7 @@ struct AddExpenseView: View { .sheet(isPresented: $viewModel.showAddNoteEditor) { NavigationStack { AddNoteView(viewModel: AddNoteViewModel(group: viewModel.selectedGroup, expense: viewModel.expense, note: viewModel.expenseNote, - handleSaveNoteTap: viewModel.handleNoteSaveBtnTap(note:))) + handleSaveNoteTap: viewModel.handleNoteSaveBtnTap(note:reason:))) } } .sheet(isPresented: $viewModel.showImagePicker) { diff --git a/Splito/UI/Home/Expense/AddExpenseViewModel.swift b/Splito/UI/Home/Expense/AddExpenseViewModel.swift index 09e2cd02c..63371c229 100644 --- a/Splito/UI/Home/Expense/AddExpenseViewModel.swift +++ b/Splito/UI/Home/Expense/AddExpenseViewModel.swift @@ -215,7 +215,7 @@ extension AddExpenseViewModel { showAddNoteEditor = true } - func handleNoteSaveBtnTap(note: String) { + func handleNoteSaveBtnTap(note: String, reason: String?) { showAddNoteEditor = false self.expenseNote = note } diff --git a/Splito/UI/Home/Expense/Note/AddNoteView.swift b/Splito/UI/Home/Expense/Note/AddNoteView.swift index c0e4a1447..a6a4275da 100644 --- a/Splito/UI/Home/Expense/Note/AddNoteView.swift +++ b/Splito/UI/Home/Expense/Note/AddNoteView.swift @@ -14,22 +14,51 @@ struct AddNoteView: View { @StateObject var viewModel: AddNoteViewModel @State private var tempNote: String = "" + @State private var tempPaymentReason: String = "" @FocusState private var isFocused: Bool var body: some View { - VStack(alignment: .leading, spacing: 8) { - TextField("Enter your note here...", text: $tempNote, axis: .vertical) - .font(.subTitle2()) - .foregroundStyle(primaryText) - .focused($isFocused) - .tint(primaryColor) - .autocorrectionDisabled() - .padding(.horizontal, 16) - .padding(.vertical, 12) - .overlay { - RoundedRectangle(cornerRadius: 12) - .stroke(outlineColor, lineWidth: 1) + VStack(alignment: .leading, spacing: 16) { + if let paymentReason = viewModel.paymentReason { + VStack(alignment: .leading, spacing: 8) { + Text("Reason") + .font(.body3()) + .foregroundStyle(disableText) + + TextField("Enter a reason for this payment", text: $tempPaymentReason) + .font(.subTitle2()) + .foregroundStyle(primaryText) + .focused($isFocused) + .tint(primaryColor) + .autocorrectionDisabled() + .padding(16) + .overlay { + RoundedRectangle(cornerRadius: 12) + .stroke(outlineColor, lineWidth: 1) + } } + .onAppear { + tempPaymentReason = paymentReason + } + } + + VStack(alignment: .leading, spacing: 8) { + Text("Note") + .font(.body3()) + .foregroundStyle(disableText) + + TextField("Enter your note here...", text: $tempNote, axis: .vertical) + .font(.subTitle2()) + .foregroundStyle(primaryText) + .focused($isFocused) + .tint(primaryColor) + .autocorrectionDisabled() + .padding(16) + .overlay { + RoundedRectangle(cornerRadius: 12) + .stroke(outlineColor, lineWidth: 1) + } + } Spacer() } diff --git a/Splito/UI/Home/Expense/Note/AddNoteViewModel.swift b/Splito/UI/Home/Expense/Note/AddNoteViewModel.swift index d23223665..3338126b4 100644 --- a/Splito/UI/Home/Expense/Note/AddNoteViewModel.swift +++ b/Splito/UI/Home/Expense/Note/AddNoteViewModel.swift @@ -16,19 +16,21 @@ class AddNoteViewModel: BaseViewModel, ObservableObject { @Inject private var transactionRepository: TransactionRepository @Published var note: String + @Published var paymentReason: String? @Published private(set) var showLoader: Bool = false private let group: Groups? private let expense: Expense? private let payment: Transactions? - private let handleSaveNoteTap: ((String) -> Void)? + private let handleSaveNoteTap: ((_ note: String, _ reason: String?) -> Void)? - init(group: Groups?, expense: Expense? = nil, payment: Transactions? = nil, - note: String, handleSaveNoteTap: ((String) -> Void)? = nil) { + init(group: Groups?, expense: Expense? = nil, payment: Transactions? = nil, note: String, + paymentReason: String? = nil, handleSaveNoteTap: ((_ note: String, _ reason: String?) -> Void)? = nil) { self.group = group self.expense = expense self.payment = payment self.note = note + self.paymentReason = paymentReason self.handleSaveNoteTap = handleSaveNoteTap super.init() } @@ -40,7 +42,7 @@ class AddNoteViewModel: BaseViewModel, ObservableObject { func handleSaveNoteAction() async -> Bool { if let handleSaveNoteTap { - handleSaveNoteTap(note) + handleSaveNoteTap(note, paymentReason) return true } @@ -88,6 +90,7 @@ class AddNoteViewModel: BaseViewModel, ObservableObject { var updatedPayment = payment updatedPayment.note = note + updatedPayment.reason = paymentReason updatedPayment = try await transactionRepository.updateTransaction(group: group, transaction: updatedPayment, oldTransaction: payment, members: members, type: .transactionUpdated) diff --git a/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentView.swift b/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentView.swift index d9e431fef..b22f9cd93 100644 --- a/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentView.swift +++ b/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentView.swift @@ -109,7 +109,8 @@ struct GroupPaymentView: View { .sheet(isPresented: $viewModel.showAddNoteEditor) { NavigationStack { AddNoteView(viewModel: AddNoteViewModel(group: viewModel.group, payment: viewModel.transaction, note: viewModel.paymentNote, - handleSaveNoteTap: viewModel.handleNoteSaveBtnTap(note:))) + paymentReason: viewModel.paymentReason, + handleSaveNoteTap: viewModel.handleNoteSaveBtnTap(note:reason:))) } } } diff --git a/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift b/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift index 7ff3b36e7..79fec16b7 100644 --- a/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift +++ b/Splito/UI/Home/Groups/Group/Group Options/Settle up/Payment/GroupPaymentViewModel.swift @@ -23,6 +23,7 @@ class GroupPaymentViewModel: BaseViewModel, ObservableObject { @Published var paymentDate = Date() @Published var paymentImage: UIImage? + @Published var paymentReason: String = "" @Published var paymentNote: String = "" @Published private(set) var paymentImageUrl: String? @@ -110,6 +111,7 @@ class GroupPaymentViewModel: BaseViewModel, ObservableObject { paymentDate = transaction?.date.dateValue() ?? Date.now paymentNote = transaction?.note ?? "" paymentImageUrl = transaction?.imageUrl + paymentReason = transaction?.reason ?? "" viewState = .initial LogD("GroupPaymentViewModel: \(#function) Payment fetched successfully.") @@ -150,9 +152,10 @@ class GroupPaymentViewModel: BaseViewModel, ObservableObject { showAddNoteEditor = true } - func handleNoteSaveBtnTap(note: String) { + func handleNoteSaveBtnTap(note: String, reason: String?) { showAddNoteEditor = false self.paymentNote = note + self.paymentReason = reason ?? "" } func handlePaymentImageTap() { @@ -239,12 +242,13 @@ class GroupPaymentViewModel: BaseViewModel, ObservableObject { newTransaction.updatedAt = Timestamp() newTransaction.updatedBy = userId newTransaction.note = paymentNote + newTransaction.reason = paymentReason return await updateTransaction(transaction: newTransaction, oldTransaction: transaction) } else { let transaction = Transactions(payerId: payerId, receiverId: receiverId, addedBy: userId, - updatedBy: userId, note: paymentNote, amount: amount, - date: .init(date: paymentDate)) + updatedBy: userId, note: paymentNote, reason: paymentReason, + amount: amount, date: .init(date: paymentDate)) return await addTransaction(transaction: transaction) } } diff --git a/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailView.swift b/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailView.swift index 2b20b7456..ab0acc511 100644 --- a/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailView.swift +++ b/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailView.swift @@ -103,7 +103,8 @@ struct GroupTransactionDetailView: View { } .fullScreenCover(isPresented: $viewModel.showAddNoteEditor) { NavigationStack { - AddNoteView(viewModel: AddNoteViewModel(group: viewModel.group, payment: viewModel.transaction, note: viewModel.paymentNote)) + AddNoteView(viewModel: AddNoteViewModel(group: viewModel.group, payment: viewModel.transaction, + note: viewModel.paymentNote, paymentReason: viewModel.paymentReason)) } } .navigationDestination(isPresented: $showImageDisplayView) { diff --git a/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailViewModel.swift b/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailViewModel.swift index 757b56458..5720dcfcb 100644 --- a/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailViewModel.swift +++ b/Splito/UI/Home/Groups/Group/Group Options/Transactions/Transaction Detail/GroupTransactionDetailViewModel.swift @@ -16,6 +16,8 @@ class GroupTransactionDetailViewModel: BaseViewModel, ObservableObject { @Inject private var transactionRepository: TransactionRepository @Published var paymentNote: String = "" + @Published var paymentReason: String = "" + @Published private(set) var transaction: Transactions? @Published private(set) var transactionUsersData: [AppUser] = [] @@ -92,6 +94,7 @@ class GroupTransactionDetailViewModel: BaseViewModel, ObservableObject { self.transactionUsersData = userData self.paymentNote = transaction.note ?? "" + self.paymentReason = transaction.reason ?? "" } private func fetchUserData(for userId: String) async -> AppUser? { @@ -261,6 +264,7 @@ class GroupTransactionDetailViewModel: BaseViewModel, ObservableObject { guard let updatedTransaction = notification.object as? Transactions else { return } transaction = updatedTransaction paymentNote = updatedTransaction.note ?? "" + paymentReason = updatedTransaction.reason ?? "" } // MARK: - Error Handling