import SwiftUI import ComposeApp struct ManageUsersView: View { let residenceId: Int32 let residenceName: String let isPrimaryOwner: Bool @Environment(\.dismiss) private var dismiss @State private var users: [ResidenceUserResponse] = [] @State private var ownerId: Int32? @State private var shareCode: ShareCodeResponse? @State private var isLoading = true @State private var errorMessage: String? @State private var isGeneratingCode = false var body: some View { NavigationView { ZStack { Color.appBackgroundPrimary .ignoresSafeArea() if isLoading { ProgressView() } else if let error = errorMessage { ErrorView(message: error) { loadUsers() } } else { ScrollView { VStack(spacing: 16) { // Share code section (primary owner only) if isPrimaryOwner { ShareCodeCard( shareCode: shareCode, residenceName: residenceName, isGeneratingCode: isGeneratingCode, onGenerateCode: generateShareCode ) .padding(.horizontal) .padding(.top) } // Users list VStack(alignment: .leading, spacing: 12) { Text("\(L10n.Residences.users) (\(users.count))") .font(.headline) .padding(.horizontal) ForEach(users, id: \.id) { user in UserListItem( user: user, isOwner: user.id == ownerId, isPrimaryOwner: isPrimaryOwner, onRemove: { removeUser(userId: user.id) } ) } } .padding(.bottom) } } } } .listStyle(.plain) .scrollContentBackground(.hidden) .background(Color.appBackgroundPrimary) .navigationTitle(L10n.Residences.manageUsers) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(L10n.Common.close) { dismiss() } } } } .onAppear { // Clear share code on appear so it's always blank shareCode = nil loadUsers() } } private func loadUsers() { guard TokenStorage.shared.getToken() != nil else { errorMessage = "Not authenticated" return } isLoading = true errorMessage = nil Task { do { let result = try await APILayer.shared.getResidenceUsers(residenceId: Int32(Int(residenceId))) await MainActor.run { if let successResult = result as? ApiResultSuccess, let responseData = successResult.data as? ResidenceUsersResponse { self.users = Array(responseData.users) self.ownerId = Int32(responseData.owner.id) self.isLoading = false } else if let errorResult = result as? ApiResultError { self.errorMessage = ErrorMessageParser.parse(errorResult.message) self.isLoading = false } else { self.errorMessage = "Failed to load users" self.isLoading = false } } } catch { await MainActor.run { self.errorMessage = error.localizedDescription self.isLoading = false } } } } private func loadShareCode() { guard TokenStorage.shared.getToken() != nil else { return } Task { do { let result = try await APILayer.shared.getShareCode(residenceId: Int32(Int(residenceId))) await MainActor.run { if let successResult = result as? ApiResultSuccess { self.shareCode = successResult.data } // It's okay if there's no active share code } } catch { // It's okay if there's no active share code } } } private func generateShareCode() { guard TokenStorage.shared.getToken() != nil else { return } isGeneratingCode = true Task { do { let result = try await APILayer.shared.generateShareCode(residenceId: Int32(Int(residenceId))) await MainActor.run { if let successResult = result as? ApiResultSuccess { self.shareCode = successResult.data self.isGeneratingCode = false } else if let errorResult = result as? ApiResultError { self.errorMessage = ErrorMessageParser.parse(errorResult.message) self.isGeneratingCode = false } else { self.errorMessage = "Failed to generate share code" self.isGeneratingCode = false } } } catch { await MainActor.run { self.errorMessage = error.localizedDescription self.isGeneratingCode = false } } } } private func removeUser(userId: Int32) { guard TokenStorage.shared.getToken() != nil else { return } Task { do { let result = try await APILayer.shared.removeUser(residenceId: Int32(Int(residenceId)), userId: Int32(Int(userId))) await MainActor.run { if result is ApiResultSuccess { // Remove user from local list self.users.removeAll { $0.id == userId } } else if let errorResult = result as? ApiResultError { self.errorMessage = ErrorMessageParser.parse(errorResult.message) } else { self.errorMessage = "Failed to remove user" } } } catch { await MainActor.run { self.errorMessage = error.localizedDescription } } } } } #Preview { ManageUsersView(residenceId: 1, residenceName: "My Home", isPrimaryOwner: true) }