diff --git a/ios/LibNovel/LibNovel/Views/BookDetail/CommentsView.swift b/ios/LibNovel/LibNovel/Views/BookDetail/CommentsView.swift index 462341a..0103094 100644 --- a/ios/LibNovel/LibNovel/Views/BookDetail/CommentsView.swift +++ b/ios/LibNovel/LibNovel/Views/BookDetail/CommentsView.swift @@ -104,21 +104,43 @@ class CommentsViewModel: ObservableObject { func deleteComment(commentId: String, parentId: String? = nil) async { guard !deletingIds.contains(commentId) else { return } 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 { 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 { - // 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 {