Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix data update issue #80

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions BaseStyle/BaseStyle/Views/AlertPrompt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// Created by Amisha Italiya on 22/02/24.
//

import Foundation
import SwiftUI

public struct AlertPrompt {
Expand All @@ -28,7 +27,7 @@ public struct AlertPrompt {
}
}

public struct Backport<Content> {
public struct AlertView<Content> {
public let content: Content

public init(content: Content) {
Expand All @@ -37,10 +36,10 @@ public struct Backport<Content> {
}

public extension View {
var backport: Backport<Self> { Backport(content: self) }
var alertView: AlertView<Self> { AlertView(content: self) }
}

public extension Backport where Content: View {
public extension AlertView where Content: View {
@ViewBuilder func alert(isPresented: Binding<Bool>, alertStruct: AlertPrompt) -> some View {
content
.alert(alertStruct.title.localized, isPresented: isPresented) {
Expand All @@ -55,7 +54,7 @@ public extension Backport where Content: View {
})
}
if alertStruct.positiveBtnTitle == nil && alertStruct.negativeBtnTitle == nil {
Button("Ok".localized, role: .cancel, action: {
Button("Ok", role: .cancel, action: {
isPresented.wrappedValue = false
})
}
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/DI/Injector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class Injector {
appAssembler = Assembler([AppAssembly()])
}

public func setTestAassembler(assemblies: [Assembly]) {
public func setTestAssembler(assemblies: [Assembly]) {
appAssembler = Assembler(assemblies)
}
}
Expand Down
10 changes: 7 additions & 3 deletions Data/Data/Model/ActivityLog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ public struct ActivityLog: Codable, Identifiable, Hashable {
public let expenseName: String?
public let payerName: String?
public let receiverName: String?
public let paymentReason: String?
public let amount: Double?

public init(type: ActivityType, groupId: String, activityId: String, groupName: String, actionUserName: String,
recordedOn: Timestamp, previousGroupName: String? = nil, removedMemberName: String? = nil,
expenseName: String? = nil, payerName: String? = nil, receiverName: String? = nil, amount: Double? = nil) {
public init(type: ActivityType, groupId: String, activityId: String, groupName: String,
actionUserName: String, recordedOn: Timestamp, previousGroupName: String? = nil,
removedMemberName: String? = nil, expenseName: String? = nil, payerName: String? = nil,
receiverName: String? = nil, paymentReason: String? = nil, amount: Double? = nil) {
self.type = type
self.groupId = groupId
self.activityId = activityId
Expand All @@ -43,6 +45,7 @@ public struct ActivityLog: Codable, Identifiable, Hashable {
self.expenseName = expenseName
self.payerName = payerName
self.receiverName = receiverName
self.paymentReason = paymentReason
self.amount = amount
}

Expand All @@ -59,6 +62,7 @@ public struct ActivityLog: Codable, Identifiable, Hashable {
case expenseName = "expense_name"
case payerName = "payer_name"
case receiverName = "receiver_name"
case paymentReason = "payment_reason"
case amount
}
}
Expand Down
5 changes: 3 additions & 2 deletions Data/Data/Model/Groups.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ public struct Groups: Codable, Identifiable {
public var hasExpenses: Bool
public var isActive: Bool

public init(name: String, createdBy: String, updatedBy: String, imageUrl: String? = nil, members: [String], balances: [GroupMemberBalance],
createdAt: Timestamp, updatedAt: Timestamp, hasExpenses: Bool = false, isActive: Bool = true) {
public init(name: String, createdBy: String, updatedBy: String, imageUrl: String? = nil,
members: [String], balances: [GroupMemberBalance], createdAt: Timestamp = Timestamp(),
updatedAt: Timestamp = Timestamp(), hasExpenses: Bool = false, isActive: Bool = true) {
self.name = name
self.createdBy = createdBy
self.updatedBy = updatedBy
Expand Down
10 changes: 7 additions & 3 deletions Data/Data/Model/Transaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
public init(payerId: String, receiverId: String, addedBy: String, updatedBy: String,
note: String? = nil, 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
Expand All @@ -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"
Expand Down
1 change: 1 addition & 0 deletions Data/Data/Repository/ActivityLogRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct ActivityLogContext {
var currentUser: AppUser?
var payerName: String?
var receiverName: String?
var paymentReason: String?
var previousGroupName: String?
var removedMemberName: String?
}
43 changes: 31 additions & 12 deletions Data/Data/Repository/GroupRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,12 @@ public class GroupRepository: ObservableObject {
}

public func deleteGroup(group: Groups) async throws {
var group = group
guard let userId = preference.user?.id else { return }
cp-nirali-s marked this conversation as resolved.
Show resolved Hide resolved

// Make group inactive
group.isActive = false
var group = group
group.isActive = false // Make group inactive
group.updatedBy = userId
group.updatedAt = Timestamp()

try await updateGroup(group: group, type: .groupDeleted)
}
Expand Down Expand Up @@ -193,17 +195,19 @@ public class GroupRepository: ObservableObject {
try await store.fetchGroupsBy(userId: userId, limit: limit, lastDocument: lastDocument)
}

public func fetchMemberBy(userId: String) async throws -> AppUser? {
public func fetchMemberBy(memberId: String) async throws -> AppUser? {
// Use a synchronous read to check if the member already exists in groupMembers
let existingMember = groupMembersQueue.sync { groupMembers.first(where: { $0.id == userId }) }

if let existingMember {
return existingMember // Return the available member from groupMembers
if let existingMember = groupMembersQueue.sync(execute: {
groupMembers.first(where: { $0.id == memberId })
}) {
await updateCurrentUserImageUrl(for: [memberId])
return existingMember // Return the cached member
}

let member = try await userRepository.fetchUserBy(userID: userId)
// Fetch the member from the repository if not found locally
let member = try await userRepository.fetchUserBy(userID: memberId)

// Append to groupMembers safely with a barrier, ensuring thread safety
// Append the newly fetched member to groupMembers in a thread-safe manner
if let member {
try await withCheckedThrowingContinuation { continuation in
groupMembersQueue.async(flags: .barrier) {
Expand All @@ -218,23 +222,26 @@ public class GroupRepository: ObservableObject {
public func fetchMembersBy(memberIds: [String]) async throws -> [AppUser] {
var members: [AppUser] = []

// Filter out memberIds that already exist in groupMembers to minimise API calls
// Filter out memberIds that already exist in groupMembers to minimize API calls
let missingMemberIds = memberIds.filter { memberId in
let cachedMember = self.groupMembersQueue.sync { self.groupMembers.first { $0.id == memberId } }
return cachedMember == nil
}

if missingMemberIds.isEmpty {
await updateCurrentUserImageUrl(for: memberIds)
return groupMembersQueue.sync { self.groupMembers.filter { memberIds.contains($0.id) } }
}

// Fetch missing members concurrently using a TaskGroup
try await withThrowingTaskGroup(of: AppUser?.self) { groupTask in
for memberId in missingMemberIds {
groupTask.addTask {
try await self.fetchMemberBy(userId: memberId)
try await self.fetchMemberBy(memberId: memberId)
}
}

// Collect results from the task group & add to the groupMembers array
for try await member in groupTask {
if let member {
members.append(member)
Expand All @@ -249,4 +256,16 @@ public class GroupRepository: ObservableObject {

return members
}

// Updates the current user's image url in groupMembers if applicable
private func updateCurrentUserImageUrl(for memberIds: [String]) async {
guard let currentUser = preference.user, memberIds.contains(currentUser.id) else { return }

groupMembersQueue.async(flags: .barrier) {
if let index = self.groupMembers.firstIndex(where: { $0.id == currentUser.id }),
self.groupMembers[index].imageUrl != currentUser.imageUrl {
self.groupMembers[index].imageUrl = currentUser.imageUrl
}
}
}
}
16 changes: 8 additions & 8 deletions Data/Data/Repository/TransactionRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ public class TransactionRepository: ObservableObject {
private func hasTransactionChanged(_ transaction: Transactions, oldTransaction: Transactions) -> Bool {
return oldTransaction.payerId != transaction.payerId || oldTransaction.receiverId != transaction.receiverId ||
oldTransaction.updatedBy != transaction.updatedBy || oldTransaction.note != transaction.note ||
oldTransaction.imageUrl != transaction.imageUrl || oldTransaction.amount != transaction.amount ||
oldTransaction.date.dateValue() != transaction.date.dateValue() ||
oldTransaction.imageUrl != transaction.imageUrl || oldTransaction.reason != transaction.reason ||
oldTransaction.amount != transaction.amount || oldTransaction.date.dateValue() != transaction.date.dateValue() ||
oldTransaction.updatedAt.dateValue() != transaction.updatedAt.dateValue() || oldTransaction.isActive != transaction.isActive
}

Expand All @@ -103,8 +103,9 @@ public class TransactionRepository: ObservableObject {
guard let self else { return nil }
let payerName = (user.id == transaction.payerId && memberId == transaction.payerId) ? (user.id == transaction.addedBy ? "You" : "you") : (memberId == transaction.payerId) ? "you" : members.payer.nameWithLastInitial
let receiverName = (memberId == transaction.receiverId) ? "you" : (memberId == transaction.receiverId) ? "you" : members.receiver.nameWithLastInitial
let context = ActivityLogContext(group: group, transaction: transaction, type: type, memberId: memberId,
currentUser: user, payerName: payerName, receiverName: receiverName)
let context = ActivityLogContext(group: group, transaction: transaction, type: type,
memberId: memberId, currentUser: user, payerName: payerName,
receiverName: receiverName, paymentReason: transaction.reason)

return await self.addActivityLog(context: context)
}
Expand All @@ -131,10 +132,9 @@ public class TransactionRepository: ObservableObject {
let actionUserName = (context.memberId == currentUser.id) ? "You" : currentUser.nameWithLastInitial
let amount: Double = (context.memberId == transaction.payerId) ? transaction.amount : (context.memberId == transaction.receiverId) ? -transaction.amount : 0

return ActivityLog(type: context.type, groupId: groupId, activityId: transactionId,
groupName: context.group?.name ?? "", actionUserName: actionUserName,
recordedOn: Timestamp(date: Date()), payerName: context.payerName,
receiverName: context.receiverName, amount: amount)
return ActivityLog(type: context.type, groupId: groupId, activityId: transactionId, groupName: context.group?.name ?? "",
actionUserName: actionUserName, recordedOn: Timestamp(date: Date()), payerName: context.payerName,
receiverName: context.receiverName, paymentReason: context.paymentReason, amount: amount)
}

private func addActivityLog(context: ActivityLogContext) async -> Error? {
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/Store/ExpenseStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class ExpenseStore: ObservableObject {

func updateExpense(groupId: String, expense: Expense) async throws {
if let expenseId = expense.id {
try expenseReference(groupId: groupId).document(expenseId).setData(from: expense, merge: true)
try expenseReference(groupId: groupId).document(expenseId).setData(from: expense, merge: false)
cp-nirali-s marked this conversation as resolved.
Show resolved Hide resolved
} else {
LogE("ExpenseStore: \(#function) Expense not found.")
throw ServiceError.dataNotFound
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/Store/GroupStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class GroupStore: ObservableObject {

func updateGroup(group: Groups) async throws {
if let groupId = group.id {
try groupReference.document(groupId).setData(from: group, merge: true)
try groupReference.document(groupId).setData(from: group, merge: false)
} else {
LogE("GroupStore: \(#function) Group not found.")
throw ServiceError.dataNotFound
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/Store/TransactionStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class TransactionStore: ObservableObject {

func updateTransaction(groupId: String, transaction: Transactions) async throws {
if let transactionId = transaction.id {
try transactionReference(groupId: groupId).document(transactionId).setData(from: transaction, merge: true)
try transactionReference(groupId: groupId).document(transactionId).setData(from: transaction, merge: false)
} else {
LogE("TransactionStore: \(#function) Payment not found.")
throw ServiceError.dataNotFound
Expand Down
2 changes: 1 addition & 1 deletion Data/Data/Store/UserStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class UserStore: ObservableObject {
}

func updateUser(user: AppUser) async throws -> AppUser? {
try usersCollection.document(user.id).setData(from: user, merge: true)
try usersCollection.document(user.id).setData(from: user, merge: false)
return user
}

Expand Down
28 changes: 24 additions & 4 deletions Splito/Localization/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@
},
"%@" : {

},
"%@ %@ " : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "%1$@ %2$@ "
}
}
}
},
"%@ %@ %@" : {
"localizations" : {
Expand All @@ -61,9 +71,6 @@
},
"%@ and %@" : {
"extractionState" : "manual"
},
"%@ owes " : {

},
"%@ owes you " : {

Expand All @@ -88,6 +95,16 @@
}
}
},
"%@ paid %@ for '%@'" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "%1$@ paid %2$@ for '%3$@'"
}
}
}
},
"%@ people" : {
"extractionState" : "manual"
},
Expand Down Expand Up @@ -311,6 +328,9 @@
"Enter a description" : {
"extractionState" : "manual"
},
"Enter a reason for this payment" : {
"extractionState" : "manual"
},
"Enter a valid phone number." : {
"extractionState" : "manual"
},
Expand All @@ -336,7 +356,7 @@
"extractionState" : "manual"
},
"Enter your note here..." : {

"extractionState" : "manual"
},
"Enter your phone number" : {
"extractionState" : "manual"
Expand Down
2 changes: 1 addition & 1 deletion Splito/UI/Home/Account/AccountHomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct AccountHomeView: View {
}
.background(surfaceColor)
.toastView(toast: $viewModel.toast)
.backport.alert(isPresented: $viewModel.showAlert, alertStruct: viewModel.alert)
.alertView.alert(isPresented: $viewModel.showAlert, alertStruct: viewModel.alert)
.sheet(isPresented: $viewModel.showShareSheet) {
MailComposeView(logFilePath: viewModel.logFilePath, showToast: viewModel.showMailSendToast)
}
Expand Down
2 changes: 1 addition & 1 deletion Splito/UI/Home/Account/User Profile/UserProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ struct UserProfileView: View {
.frame(maxWidth: isIpad ? 600 : nil, alignment: .center)
.frame(maxWidth: .infinity, alignment: .center)
.background(surfaceColor)
.backport.alert(isPresented: $viewModel.showAlert, alertStruct: viewModel.alert)
.alertView.alert(isPresented: $viewModel.showAlert, alertStruct: viewModel.alert)
.toastView(toast: $viewModel.toast)
.toolbarRole(.editor)
.toolbar {
Expand Down
Loading
Loading