import Foundation import SwiftUI import Combine @MainActor class PDSViewModel: ObservableObject { @Published var pdsService = PDSService() @Published var alertItem: AlertItem? @Published var demoMode: Bool = false // Mock data for demo mode private var mockUsers: [PDSUser] = [] private var mockInviteCodes: [InviteCode] = [] var errorMessage: String? { pdsService.errorMessage } var isLoading: Bool { pdsService.isLoading } var isAuthenticated: Bool { get { if demoMode { return true // Always authenticated in demo mode } let value = pdsService.isAuthenticated print("PDSViewModel: isAuthenticated getter called, value = \(value)") return value } } var users: [PDSUser] { if demoMode { return mockUsers } return pdsService.users } var inviteCodes: [InviteCode] { if demoMode { return mockInviteCodes } return pdsService.inviteCodes } // Add listeners for PDSService changes init() { // Subscribe to PDSService objectWillChange events pdsService.objectWillChange.sink { [weak self] _ in // Forward the change notification to our own objectWillChange DispatchQueue.main.async { self?.objectWillChange.send() } } .store(in: &cancellables) } // Storage for cancellables private var cancellables = Set() // Method to manually refresh UI data func refreshUI() { print("PDSViewModel: refreshUI called") DispatchQueue.main.async { print("PDSViewModel: sending objectWillChange notification") self.objectWillChange.send() if self.demoMode { print("Demo users status: \(self.mockUsers.map { "\($0.handle): \($0.isActive)" }.joined(separator: ", "))") } } } // Enable demo mode with mock data func enableDemoMode() { demoMode = true createMockData() refreshUI() } // Disable demo mode func disableDemoMode() { demoMode = false refreshUI() } // Create mock data for demo mode private func createMockData() { // Create mock users mockUsers = [ PDSUser( id: "did:plc:abcdef123456", handle: "alice", displayName: "Alice Smith", description: "Product designer and developer. Working on decentralized social apps.", joinedAt: Date().addingTimeInterval(-86400 * 30), // 30 days ago avatar: nil, isActive: true ), PDSUser( id: "did:plc:ghijkl789012", handle: "bob", displayName: "Bob Johnson", description: "Software engineer. Interested in decentralized protocols and privacy.", joinedAt: Date().addingTimeInterval(-86400 * 15), // 15 days ago avatar: nil, isActive: true ), PDSUser( id: "did:plc:mnopqr345678", handle: "charlie", displayName: "Charlie Brown", description: "Community manager and content creator.", joinedAt: Date().addingTimeInterval(-86400 * 5), // 5 days ago avatar: nil, isActive: false ) ] // Create mock invite codes mockInviteCodes = [ InviteCode( id: "abc-123-xyz", uses: [], createdAt: Date().addingTimeInterval(-86400 * 20), // 20 days ago disabled: false ), InviteCode( id: "def-456-uvw", uses: [ CodeUse(usedBy: "did:plc:abcdef123456", usedAt: ISO8601DateFormatter().string(from: Date().addingTimeInterval(-86400 * 10))) ], createdAt: Date().addingTimeInterval(-86400 * 25), // 25 days ago disabled: false ), InviteCode( id: "ghi-789-rst", uses: [], createdAt: Date().addingTimeInterval(-86400 * 15), // 15 days ago disabled: true ) ] } // Refresh invite codes with UI update func refreshInviteCodes() async { if demoMode { // No need to do anything in demo mode, data is already loaded refreshUI() return } await pdsService.fetchInviteCodes() refreshUI() } // Refresh users with UI update func refreshUsers() async { if demoMode { // No need to do anything in demo mode, data is already loaded refreshUI() return } await pdsService.fetchUsers() refreshUI() } // Disable invite code with guaranteed UI update func disableInviteCode(_ code: String) async -> Bool { if demoMode { // In demo mode, just update our mock data if let index = mockInviteCodes.firstIndex(where: { $0.id == code }) { mockInviteCodes[index].disabled = true refreshUI() return true } return false } let result = await pdsService.disableInviteCode(code) refreshUI() return result } // Create invite code in demo mode func createInviteCode() async -> InviteCode? { if demoMode { // Generate a random code in demo mode let randomCode = "demo-\(Int.random(in: 100...999))-\(UUID().uuidString.prefix(4))" let newCode = InviteCode( id: randomCode, uses: [], createdAt: Date(), disabled: false ) mockInviteCodes.append(newCode) refreshUI() return newCode } let code = await pdsService.createInviteCode() await refreshInviteCodes() return code } // Suspend user in demo mode func suspendUser(userId: String) async -> Bool { if demoMode { print("Suspending user in demo mode: \(userId)") return await withCheckedContinuation { continuation in DispatchQueue.main.async { if let user = self.mockUsers.first(where: { $0.id == userId }) { print("Found user \(user.displayName), setting isActive to false") user.isActive = false self.refreshUI() continuation.resume(returning: true) } else { print("User not found in mockUsers: \(userId)") continuation.resume(returning: false) } } } } let success = await pdsService.suspendUser(userId: userId, reason: "Demo suspension") await refreshUsers() return success } // Reactivate user in demo mode func reactivateUser(userId: String) async -> Bool { if demoMode { print("Reactivating user in demo mode: \(userId)") return await withCheckedContinuation { continuation in DispatchQueue.main.async { if let user = self.mockUsers.first(where: { $0.id == userId }) { print("Found user \(user.displayName), setting isActive to true") user.isActive = true self.refreshUI() continuation.resume(returning: true) } else { print("User not found in mockUsers: \(userId)") continuation.resume(returning: false) } } } } let success = await pdsService.reactivateUser(userId: userId) await refreshUsers() return success } // Edit user handle in demo mode func editUserHandle(userId: String, newHandle: String) async -> Bool { if demoMode { if let user = mockUsers.first(where: { $0.id == userId }) { user.handle = newHandle refreshUI() return true } return false } let success = await pdsService.editUserHandle(userId: userId, newHandle: newHandle) await refreshUsers() return success } func login(serverURL: String, username: String, password: String) async { print("PDSViewModel: login called") if let credentials = PDSCredentials(serverURL: serverURL, username: username, password: password) { let success = await pdsService.login(credentials: credentials) print("PDSViewModel: login completed, success = \(success), isAuthenticated = \(pdsService.isAuthenticated)") // Force update the view by triggering objectWillChange objectWillChange.send() } else { pdsService.errorMessage = "Invalid credentials" } } func logout() { print("PDSViewModel: logout called") if demoMode { disableDemoMode() } else { pdsService.logout() } objectWillChange.send() } } struct AlertItem: Identifiable { let id = UUID() let title: String let message: String }