add delete user from blacklist
This commit is contained in:
parent
43a5d8193d
commit
2eabbd59c3
@ -3,6 +3,7 @@ import Foundation
|
||||
enum BlockedUsersServiceError: LocalizedError {
|
||||
case unexpectedStatus(String)
|
||||
case decoding(debugDescription: String)
|
||||
case encoding(String)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
@ -12,6 +13,8 @@ enum BlockedUsersServiceError: LocalizedError {
|
||||
return AppConfig.DEBUG
|
||||
? debugDescription
|
||||
: NSLocalizedString("Не удалось загрузить список.", comment: "Blocked users service decoding error")
|
||||
case .encoding(let message):
|
||||
return message
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,6 +81,60 @@ final class BlockedUsersService {
|
||||
}
|
||||
}
|
||||
|
||||
func remove(userId: UUID, completion: @escaping (Result<String, Error>) -> Void) {
|
||||
let request = BlockedUserDeleteRequest(userId: userId)
|
||||
let encoder = JSONEncoder()
|
||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
||||
|
||||
guard let body = try? encoder.encode(request) else {
|
||||
let message = NSLocalizedString("Не удалось подготовить данные запроса.", comment: "Blocked users delete encoding error")
|
||||
completion(.failure(BlockedUsersServiceError.encoding(message)))
|
||||
return
|
||||
}
|
||||
|
||||
client.request(
|
||||
path: "/v1/user/blacklist/remove",
|
||||
method: .delete,
|
||||
body: body,
|
||||
requiresAuth: true
|
||||
) { [decoder] result in
|
||||
switch result {
|
||||
case .success(let response):
|
||||
do {
|
||||
let apiResponse = try decoder.decode(APIResponse<MessagePayload>.self, from: response.data)
|
||||
guard apiResponse.status == "fine" else {
|
||||
let message = apiResponse.detail ?? NSLocalizedString("Не удалось удалить пользователя из списка.", comment: "Blocked users delete unexpected status")
|
||||
completion(.failure(BlockedUsersServiceError.unexpectedStatus(message)))
|
||||
return
|
||||
}
|
||||
completion(.success(apiResponse.data.message))
|
||||
} catch {
|
||||
let debugMessage = Self.describeDecodingError(error: error, data: response.data)
|
||||
if AppConfig.DEBUG {
|
||||
print("[BlockedUsersService] decode delete response failed: \(debugMessage)")
|
||||
}
|
||||
completion(.failure(BlockedUsersServiceError.decoding(debugDescription: debugMessage)))
|
||||
}
|
||||
case .failure(let error):
|
||||
if case let NetworkError.server(_, data) = error,
|
||||
let data,
|
||||
let message = Self.errorMessage(from: data) {
|
||||
completion(.failure(BlockedUsersServiceError.unexpectedStatus(message)))
|
||||
return
|
||||
}
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func remove(userId: UUID) async throws -> String {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
remove(userId: userId) { result in
|
||||
continuation.resume(with: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func decodeDate(from decoder: Decoder) throws -> Date {
|
||||
let container = try decoder.singleValueContainer()
|
||||
let string = try container.decode(String.self)
|
||||
@ -170,3 +227,7 @@ final class BlockedUsersService {
|
||||
return formatter
|
||||
}()
|
||||
}
|
||||
|
||||
private struct BlockedUserDeleteRequest: Encodable {
|
||||
let userId: UUID
|
||||
}
|
||||
|
||||
@ -993,7 +993,7 @@
|
||||
|
||||
},
|
||||
"Не удалось подготовить данные запроса." : {
|
||||
"comment" : "Profile update encoding error"
|
||||
"comment" : "Blocked users delete encoding error\nProfile update encoding error"
|
||||
},
|
||||
"Не удалось сериализовать данные запроса." : {
|
||||
"localizations" : {
|
||||
@ -1011,6 +1011,9 @@
|
||||
"Не удалось сохранить изменения профиля." : {
|
||||
"comment" : "Profile update unexpected status"
|
||||
},
|
||||
"Не удалось удалить пользователя из списка." : {
|
||||
"comment" : "Blocked users delete unexpected status"
|
||||
},
|
||||
"Неверный запрос (400)." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1323,7 +1326,7 @@
|
||||
}
|
||||
},
|
||||
"Ошибка" : {
|
||||
"comment" : "Profile update error title",
|
||||
"comment" : "Common error title\nProfile update error title",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
|
||||
@ -4,9 +4,10 @@ struct BlockedUsersView: View {
|
||||
@State private var blockedUsers: [BlockedUser] = []
|
||||
@State private var isLoading = false
|
||||
@State private var loadError: String?
|
||||
@State private var showAddBlockedUserAlert = false
|
||||
@State private var pendingUnblock: BlockedUser?
|
||||
@State private var showUnblockConfirmation = false
|
||||
@State private var removingUserIds: Set<UUID> = []
|
||||
@State private var activeAlert: ActiveAlert?
|
||||
|
||||
private let blockedUsersService = BlockedUsersService()
|
||||
|
||||
@ -49,6 +50,7 @@ struct BlockedUsersView: View {
|
||||
} label: {
|
||||
Label(NSLocalizedString("Разблокировать", comment: ""), systemImage: "person.crop.circle.badge.xmark")
|
||||
}
|
||||
.disabled(removingUserIds.contains(user.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +61,7 @@ struct BlockedUsersView: View {
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
showAddBlockedUserAlert = true
|
||||
activeAlert = .addPlaceholder
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
@ -71,10 +73,21 @@ struct BlockedUsersView: View {
|
||||
.refreshable {
|
||||
await loadBlockedUsers()
|
||||
}
|
||||
.alert(NSLocalizedString("Скоро", comment: "Add blocked user placeholder title"), isPresented: $showAddBlockedUserAlert) {
|
||||
Button(NSLocalizedString("OK", comment: "Common OK"), role: .cancel) {}
|
||||
} message: {
|
||||
Text(NSLocalizedString("Добавление новых блокировок появится позже.", comment: "Add blocked user placeholder message"))
|
||||
.alert(item: $activeAlert) { alert in
|
||||
switch alert {
|
||||
case .addPlaceholder:
|
||||
return Alert(
|
||||
title: Text(NSLocalizedString("Скоро", comment: "Add blocked user placeholder title")),
|
||||
message: Text(NSLocalizedString("Добавление новых блокировок появится позже.", comment: "Add blocked user placeholder message")),
|
||||
dismissButton: .default(Text(NSLocalizedString("OK", comment: "Common OK")))
|
||||
)
|
||||
case .error(_, let message):
|
||||
return Alert(
|
||||
title: Text(NSLocalizedString("Ошибка", comment: "Common error title")),
|
||||
message: Text(message),
|
||||
dismissButton: .default(Text(NSLocalizedString("OK", comment: "Common OK")))
|
||||
)
|
||||
}
|
||||
}
|
||||
.confirmationDialog(
|
||||
NSLocalizedString("Удалить из заблокированных?", comment: "Unblock confirmation title"),
|
||||
@ -82,11 +95,15 @@ struct BlockedUsersView: View {
|
||||
presenting: pendingUnblock
|
||||
) { user in
|
||||
Button(NSLocalizedString("Разблокировать", comment: "Unblock confirmation action"), role: .destructive) {
|
||||
unblock(user)
|
||||
pendingUnblock = nil
|
||||
showUnblockConfirmation = false
|
||||
Task {
|
||||
await unblock(user)
|
||||
}
|
||||
}
|
||||
Button(NSLocalizedString("Отмена", comment: "Common cancel"), role: .cancel) {
|
||||
pendingUnblock = nil
|
||||
showUnblockConfirmation = false
|
||||
}
|
||||
} message: { user in
|
||||
Text(String(format: NSLocalizedString("Пользователь \"%1$@\" будет удалён из списка заблокированных.", comment: "Unblock confirmation message"), user.displayName))
|
||||
@ -141,17 +158,27 @@ struct BlockedUsersView: View {
|
||||
blockedUsers = payloads.map(BlockedUser.init)
|
||||
} catch {
|
||||
loadError = error.localizedDescription
|
||||
if AppConfig.DEBUG {
|
||||
print("[BlockedUsersView] load blocked users failed: \(error)")
|
||||
}
|
||||
activeAlert = .error(message: error.localizedDescription)
|
||||
if AppConfig.DEBUG { print("[BlockedUsersView] load blocked users failed: \(error)") }
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
private func unblock(_ user: BlockedUser) {
|
||||
// TODO: implement unblock logic when backend is ready
|
||||
blockedUsers.removeAll { $0.id == user.id }
|
||||
@MainActor
|
||||
private func unblock(_ user: BlockedUser) async {
|
||||
guard !removingUserIds.contains(user.id) else { return }
|
||||
|
||||
removingUserIds.insert(user.id)
|
||||
defer { removingUserIds.remove(user.id) }
|
||||
|
||||
do {
|
||||
_ = try await blockedUsersService.remove(userId: user.id)
|
||||
blockedUsers.removeAll { $0.id == user.id }
|
||||
} catch {
|
||||
activeAlert = .error(message: error.localizedDescription)
|
||||
if AppConfig.DEBUG { print("[BlockedUsersView] unblock failed: \(error)") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,3 +233,17 @@ private struct BlockedUser: Identifiable, Equatable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum ActiveAlert: Identifiable {
|
||||
case addPlaceholder
|
||||
case error(id: UUID = UUID(), message: String)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .addPlaceholder:
|
||||
return "addPlaceholder"
|
||||
case .error(let id, _):
|
||||
return id.uuidString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user