Skip to content

Commit

Permalink
Add expense note
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-amisha-i authored Nov 27, 2024
1 parent 41f329e commit 2e682bc
Show file tree
Hide file tree
Showing 13 changed files with 326 additions and 26 deletions.
7 changes: 5 additions & 2 deletions Data/Data/Model/Expense.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,23 @@ public struct Expense: Codable, Hashable, Identifiable {
public var paidBy: [String: Double]
public let addedBy: String
public var updatedBy: String
public var note: String?
public var imageUrl: String?
public var splitTo: [String] // Reference to user ids involved in the split
public var splitType: SplitType
public var splitData: [String: Double]? // Use this to store percentage or share data
public var isActive: Bool

public init(name: String, amount: Double, date: Timestamp, paidBy: [String: Double], addedBy: String,
updatedBy: String, imageUrl: String? = nil, splitTo: [String], splitType: SplitType = .equally,
splitData: [String: Double]? = [:], isActive: Bool = true) {
updatedBy: String, note: String? = nil, imageUrl: String? = nil, splitTo: [String],
splitType: SplitType = .equally, splitData: [String: Double]? = [:], isActive: Bool = true) {
self.name = name
self.amount = amount
self.date = date
self.paidBy = paidBy
self.addedBy = addedBy
self.updatedBy = updatedBy
self.note = note
self.imageUrl = imageUrl
self.splitTo = splitTo
self.splitType = splitType
Expand All @@ -47,6 +49,7 @@ public struct Expense: Codable, Hashable, Identifiable {
case paidBy = "paid_by"
case addedBy = "added_by"
case updatedBy = "updated_by"
case note = "note"
case imageUrl = "image_url"
case splitTo = "split_to"
case splitType = "split_type"
Expand Down
7 changes: 4 additions & 3 deletions Data/Data/Repository/ExpenseRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,10 @@ public class ExpenseRepository: ObservableObject {
private func hasExpenseChanged(_ expense: Expense, oldExpense: Expense) -> Bool {
return oldExpense.name != expense.name || oldExpense.amount != expense.amount ||
oldExpense.date.dateValue() != expense.date.dateValue() || oldExpense.paidBy != expense.paidBy ||
oldExpense.updatedBy != expense.updatedBy || oldExpense.imageUrl != expense.imageUrl ||
oldExpense.splitTo != expense.splitTo || oldExpense.splitType != expense.splitType ||
oldExpense.splitData != expense.splitData || oldExpense.isActive != expense.isActive
oldExpense.updatedBy != expense.updatedBy || oldExpense.note != expense.note ||
oldExpense.imageUrl != expense.imageUrl || oldExpense.splitTo != expense.splitTo ||
oldExpense.splitType != expense.splitType || oldExpense.splitData != expense.splitData ||
oldExpense.isActive != expense.isActive
}

public func updateExpense(group: Groups, expense: Expense, oldExpense: Expense, type: ActivityType) async throws {
Expand Down
16 changes: 16 additions & 0 deletions Splito.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

/* Begin PBXBuildFile section */
0BF8F99614F85846D78DE106 /* Pods_Splito_SplitoUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2B9BBF3F71277A6AA5329CB /* Pods_Splito_SplitoUITests.framework */; };
210CC0382CF6DA7A0035682E /* ExpenseAddNoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210CC0372CF6DA7A0035682E /* ExpenseAddNoteView.swift */; };
210CC03B2CF6DA920035682E /* ExpenseAddNoteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210CC03A2CF6DA920035682E /* ExpenseAddNoteViewModel.swift */; };
213BA0602C0F465000116130 /* GroupSettleUpRouteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213BA05F2C0F465000116130 /* GroupSettleUpRouteView.swift */; };
213BA0662C11B70F00116130 /* HomeRouteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213BA0652C11B70F00116130 /* HomeRouteViewModel.swift */; };
214CF8492C2977E10044C188 /* CalculateExpensesFunctions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214CF8482C2977E10044C188 /* CalculateExpensesFunctions.swift */; };
Expand Down Expand Up @@ -153,6 +155,8 @@

/* Begin PBXFileReference section */
038CCD15E82A4E16A4AD213C /* Pods-Splito-SplitoUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Splito-SplitoUITests.release.xcconfig"; path = "Target Support Files/Pods-Splito-SplitoUITests/Pods-Splito-SplitoUITests.release.xcconfig"; sourceTree = "<group>"; };
210CC0372CF6DA7A0035682E /* ExpenseAddNoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpenseAddNoteView.swift; sourceTree = "<group>"; };
210CC03A2CF6DA920035682E /* ExpenseAddNoteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpenseAddNoteViewModel.swift; sourceTree = "<group>"; };
213BA05F2C0F465000116130 /* GroupSettleUpRouteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupSettleUpRouteView.swift; sourceTree = "<group>"; };
213BA0652C11B70F00116130 /* HomeRouteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeRouteViewModel.swift; sourceTree = "<group>"; };
214CF8482C2977E10044C188 /* CalculateExpensesFunctions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculateExpensesFunctions.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -309,6 +313,15 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
210CC0392CF6DA7F0035682E /* Notes */ = {
isa = PBXGroup;
children = (
210CC0372CF6DA7A0035682E /* ExpenseAddNoteView.swift */,
210CC03A2CF6DA920035682E /* ExpenseAddNoteViewModel.swift */,
);
path = Notes;
sourceTree = "<group>";
};
21559CAA2CBD21850039F127 /* ActivityLog */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -495,6 +508,7 @@
D85E86F02BB41CBA002EDF76 /* Detail Selection */,
D856C7302BCFD2080008A341 /* Expense Detail */,
D8CD952A2BD65E6400407B47 /* Expense Split Option */,
210CC0392CF6DA7F0035682E /* Notes */,
);
path = Expense;
sourceTree = "<group>";
Expand Down Expand Up @@ -1060,6 +1074,7 @@
2177692D2C20316B009B3B37 /* GroupTransactionDetailViewModel.swift in Sources */,
D83344732C0F2D9500CD9F05 /* GroupPaymentView.swift in Sources */,
D83344582C0DD06F00CD9F05 /* GroupSettleUpView.swift in Sources */,
210CC03B2CF6DA920035682E /* ExpenseAddNoteViewModel.swift in Sources */,
D8E244BF2B98592C00C6C82A /* GroupHomeViewModel.swift in Sources */,
D833446C2C0F2D4200CD9F05 /* GroupWhoGettingPaidView.swift in Sources */,
D8D14A562BA189EC00F45FF2 /* JoinMemberView.swift in Sources */,
Expand Down Expand Up @@ -1089,6 +1104,7 @@
214CF8492C2977E10044C188 /* CalculateExpensesFunctions.swift in Sources */,
213BA0602C0F465000116130 /* GroupSettleUpRouteView.swift in Sources */,
D8AC26F72B84B12800CEAAD3 /* LoginView.swift in Sources */,
210CC0382CF6DA7A0035682E /* ExpenseAddNoteView.swift in Sources */,
D8CD952E2BD65F4500407B47 /* ExpenseSplitOptionsViewModel.swift in Sources */,
D85E86E32BAB06D9002EDF76 /* AddExpenseViewModel.swift in Sources */,
D8A7CA702BA484370014EC67 /* GroupSettingView.swift in Sources */,
Expand Down
15 changes: 15 additions & 0 deletions Splito/Localization/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@
},
"Add expense" : {

},
"Add note" : {

},
"added" : {
"extractionState" : "manual"
Expand Down Expand Up @@ -217,6 +220,9 @@
},
"Are you sure you want to sign out?" : {
"extractionState" : "manual"
},
"Attachment:" : {

},
"Authentication failed" : {
"extractionState" : "manual"
Expand Down Expand Up @@ -331,6 +337,9 @@
},
"Enter your last name" : {
"extractionState" : "manual"
},
"Enter your note here..." : {

},
"Enter your phone number" : {
"extractionState" : "manual"
Expand All @@ -353,6 +362,9 @@
"Expense deleted successfully" : {
"extractionState" : "manual"
},
"Failed to save note." : {
"extractionState" : "manual"
},
"First Name" : {
"extractionState" : "manual"
},
Expand Down Expand Up @@ -502,6 +514,9 @@
},
"not involved" : {

},
"Note:" : {

},
"Ok" : {
"extractionState" : "manual"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"images" : [
{
"filename" : "note-1_svgrepo.com.svg",
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"filename" : "note-1_svgrepo.com (1).svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 34 additions & 7 deletions Splito/UI/Home/Expense/AddExpenseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ struct AddExpenseView: View {
.scrollBounceBehavior(.basedOnSize)

AddExpenseFooterView(date: $viewModel.expenseDate, showImagePickerOptions: $viewModel.showImagePickerOptions,
expenseImage: viewModel.expenseImage, expenseImageUrl: viewModel.expenseImageUrl,
handleExpenseImageTap: viewModel.handleExpenseImageTap,
handleActionSelection: viewModel.handleActionSelection(_:))
expenseImage: viewModel.expenseImage, expenseImageUrl: viewModel.expenseImageUrl,
handleNoteBtnTap: viewModel.handleNoteBtnTap, handleExpenseImageTap: viewModel.handleExpenseImageTap,
handleActionSelection: viewModel.handleActionSelection(_:))
}
}
.background(surfaceColor)
Expand Down Expand Up @@ -74,17 +74,21 @@ struct AddExpenseView: View {
)
}
}
.sheet(isPresented: $viewModel.showAddNoteEditor) {
NavigationStack {
ExpenseAddNoteView(viewModel: ExpenseAddNoteViewModel(group: viewModel.selectedGroup, expense: viewModel.expense,
expenseNote: viewModel.expenseNote,
handleSaveNoteTap: viewModel.handleNoteSaveBtnTap(note:)))
}
}
.sheet(isPresented: $viewModel.showImagePicker) {
ImagePickerView(cropOption: .square,
sourceType: !viewModel.sourceTypeIsCamera ? .photoLibrary : .camera,
image: $viewModel.expenseImage, isPresented: $viewModel.showImagePicker)
}
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Cancel") {
dismiss()
}
.foregroundStyle(.blue)
CancelButton()
}
ToolbarItem(placement: .topBarTrailing) {
CheckmarkButton(showLoader: viewModel.showLoader) {
Expand Down Expand Up @@ -208,6 +212,7 @@ private struct AddExpenseFooterView: View {
let expenseImage: UIImage?
let expenseImageUrl: String?

let handleNoteBtnTap: (() -> Void)
let handleExpenseImageTap: (() -> Void)
let handleActionSelection: ((ActionsOfSheet) -> Void)

Expand All @@ -222,6 +227,8 @@ private struct AddExpenseFooterView: View {
DatePickerView(date: $date, isForAddExpense: true)

ExpenseImagePickerView(image: expenseImage, imageUrl: expenseImageUrl, handleImageBtnTap: handleExpenseImageTap)

NoteButtonView(handleNoteBtnTap: handleNoteBtnTap)
}
.padding(.vertical, 12)
.padding(.horizontal, 16)
Expand Down Expand Up @@ -265,3 +272,23 @@ private struct ExpenseImagePickerView: View {
}
}
}

private struct NoteButtonView: View {

let handleNoteBtnTap: (() -> Void)

var body: some View {
Button {
UIApplication.shared.endEditing()
handleNoteBtnTap()
} label: {
Image(.noteIcon)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.padding(4)
.background(container2Color)
.cornerRadius(8)
}
}
}
29 changes: 20 additions & 9 deletions Splito/UI/Home/Expense/AddExpenseViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class AddExpenseViewModel: BaseViewModel, ObservableObject {
@Inject private var expenseRepository: ExpenseRepository

@Published var expenseName = ""
@Published var expenseNote: String = ""
@Published private(set) var expenseImageUrl: String?
@Published private(set) var payerName = "You"

Expand All @@ -27,6 +28,7 @@ class AddExpenseViewModel: BaseViewModel, ObservableObject {
@Published var expenseAmount: Double = 0

@Published var showImagePicker = false
@Published var showAddNoteEditor = false
@Published var showGroupSelection = false
@Published var showPayerSelection = false
@Published var showImagePickerOptions = false
Expand All @@ -50,15 +52,14 @@ class AddExpenseViewModel: BaseViewModel, ObservableObject {
}
}

var expenseId: String?
private var groupId: String?
let expenseId: String?
private let groupId: String?
private let router: Router<AppRoute>

init(router: Router<AppRoute>, groupId: String? = nil, expenseId: String? = nil) {
self.router = router
self.groupId = groupId
self.expenseId = expenseId
self.groupId = groupId

super.init()

Expand All @@ -72,7 +73,7 @@ class AddExpenseViewModel: BaseViewModel, ObservableObject {
}
}

// MARK: - Data Loading
// MARK: - Data Loading
private func fetchGroup(groupId: String) async {
do {
viewState = .loading
Expand Down Expand Up @@ -134,6 +135,7 @@ class AddExpenseViewModel: BaseViewModel, ObservableObject {
splitType = expense.splitType
selectedPayers = expense.paidBy
expenseImageUrl = expense.imageUrl
expenseNote = expense.note ?? ""

if let splitData = expense.splitData {
self.splitData = splitData
Expand Down Expand Up @@ -177,7 +179,6 @@ class AddExpenseViewModel: BaseViewModel, ObservableObject {

// MARK: - User Actions
extension AddExpenseViewModel {

private func updatePayerName() {
Task {
if selectedPayers.count == 1 {
Expand Down Expand Up @@ -213,6 +214,15 @@ extension AddExpenseViewModel {
showImagePickerOptions = true
}

func handleNoteBtnTap() {
showAddNoteEditor = true
}

func handleNoteSaveBtnTap(note: String) {
showAddNoteEditor = false
self.expenseNote = note
}

func handleActionSelection(_ action: ActionsOfSheet) {
switch action {
case .camera:
Expand Down Expand Up @@ -365,7 +375,7 @@ extension AddExpenseViewModel {
private func handleAddExpenseAction(userId: String, group: Groups) async -> Bool {
let expense = Expense(name: expenseName.trimming(spaces: .leadingAndTrailing), amount: expenseAmount,
date: Timestamp(date: expenseDate), paidBy: selectedPayers, addedBy: userId, updatedBy: userId,
splitTo: (splitType == .equally) ? selectedMembers : splitData.map({ $0.key }),
note: expenseNote, splitTo: (splitType == .equally) ? selectedMembers : splitData.map({ $0.key }),
splitType: splitType, splitData: splitData)

return await addExpense(group: group, expense: expense)
Expand Down Expand Up @@ -405,6 +415,7 @@ extension AddExpenseViewModel {
newExpense.amount = expenseAmount
newExpense.date = Timestamp(date: expenseDate)
newExpense.updatedBy = userId
newExpense.note = expenseNote

if selectedPayers.count == 1, let payerId = selectedPayers.keys.first {
newExpense.paidBy = [payerId: expenseAmount]
Expand Down Expand Up @@ -451,9 +462,9 @@ extension AddExpenseViewModel {
private func hasExpenseChanged(_ expense: Expense, oldExpense: Expense) -> Bool {
return oldExpense.name != expense.name || oldExpense.amount != expense.amount ||
oldExpense.date.dateValue() != expense.date.dateValue() || oldExpense.paidBy != expense.paidBy ||
oldExpense.imageUrl != expense.imageUrl || oldExpense.splitTo != expense.splitTo ||
oldExpense.splitType != expense.splitType || oldExpense.splitData != expense.splitData ||
oldExpense.isActive != expense.isActive
oldExpense.note != expense.note || oldExpense.imageUrl != expense.imageUrl ||
oldExpense.splitTo != expense.splitTo || oldExpense.splitType != expense.splitType ||
oldExpense.splitData != expense.splitData || oldExpense.isActive != expense.isActive
}

private func updateGroupMemberBalance(expense: Expense, updateType: ExpenseUpdateType) async {
Expand Down
Loading

0 comments on commit 2e682bc

Please sign in to comment.