fix(ios): optimistic comment deletion with revert on failure
Some checks failed
CI / Scraper / Lint (pull_request) Failing after 10s
CI / UI / Build (pull_request) Successful in 16s
CI / UI / Docker Push (pull_request) Has been skipped
CI / Scraper / Test (pull_request) Successful in 19s
CI / Scraper / Docker Push (pull_request) Has been skipped
iOS CI / Test (push) Has been cancelled
iOS CI / Build (push) Has been cancelled
iOS CI / Build (pull_request) Successful in 1m56s
iOS CI / Test (pull_request) Successful in 5m27s
Some checks failed
CI / Scraper / Lint (pull_request) Failing after 10s
CI / UI / Build (pull_request) Successful in 16s
CI / UI / Docker Push (pull_request) Has been skipped
CI / Scraper / Test (pull_request) Successful in 19s
CI / Scraper / Docker Push (pull_request) Has been skipped
iOS CI / Test (push) Has been cancelled
iOS CI / Build (push) Has been cancelled
iOS CI / Build (pull_request) Successful in 1m56s
iOS CI / Test (pull_request) Successful in 5m27s
This commit is contained in:
@@ -104,21 +104,43 @@ class CommentsViewModel: ObservableObject {
|
|||||||
func deleteComment(commentId: String, parentId: String? = nil) async {
|
func deleteComment(commentId: String, parentId: String? = nil) async {
|
||||||
guard !deletingIds.contains(commentId) else { return }
|
guard !deletingIds.contains(commentId) else { return }
|
||||||
deletingIds.insert(commentId)
|
deletingIds.insert(commentId)
|
||||||
defer { deletingIds.remove(commentId) }
|
|
||||||
|
// Optimistic removal — update the UI immediately before the network call
|
||||||
|
var removedComment: BookComment?
|
||||||
|
var removedAtIndex: Int?
|
||||||
|
if let parentId {
|
||||||
|
if let idx = comments.firstIndex(where: { $0.id == parentId }) {
|
||||||
|
var parent = comments[idx]
|
||||||
|
removedComment = parent.replies?.first(where: { $0.id == commentId })
|
||||||
|
removedAtIndex = idx
|
||||||
|
parent.replies = (parent.replies ?? []).filter { $0.id != commentId }
|
||||||
|
comments[idx] = parent
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removedAtIndex = comments.firstIndex(where: { $0.id == commentId })
|
||||||
|
removedComment = removedAtIndex.map { comments[$0] }
|
||||||
|
comments.removeAll { $0.id == commentId }
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await APIClient.shared.deleteComment(commentId: commentId)
|
try await APIClient.shared.deleteComment(commentId: commentId)
|
||||||
if let parentId {
|
|
||||||
if let idx = comments.firstIndex(where: { $0.id == parentId }) {
|
|
||||||
var parent = comments[idx]
|
|
||||||
parent.replies = (parent.replies ?? []).filter { $0.id != commentId }
|
|
||||||
comments[idx] = parent
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
comments.removeAll { $0.id == commentId }
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
// Silently ignore — comment may have already been deleted
|
// Revert the optimistic removal on failure
|
||||||
|
if let removed = removedComment {
|
||||||
|
if let parentId, let idx = removedAtIndex {
|
||||||
|
var parent = comments[idx]
|
||||||
|
var replies = parent.replies ?? []
|
||||||
|
replies.append(removed)
|
||||||
|
replies.sort { $0.created < $1.created }
|
||||||
|
parent.replies = replies
|
||||||
|
comments[idx] = parent
|
||||||
|
} else if let idx = removedAtIndex {
|
||||||
|
comments.insert(removed, at: min(idx, comments.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deletingIds.remove(commentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func vote(commentId: String, vote: String, parentId: String? = nil) async {
|
func vote(commentId: String, vote: String, parentId: String? = nil) async {
|
||||||
|
|||||||
Reference in New Issue
Block a user