import SwiftUI import ComposeApp struct ResidencesListView: View { @StateObject private var viewModel = ResidenceViewModel() @State private var showingAddResidence = false @State private var showingJoinResidence = false @State private var showingUpgradePrompt = false @StateObject private var authManager = AuthenticationManager.shared @StateObject private var subscriptionCache = SubscriptionCacheWrapper.shared var body: some View { ZStack { Color.appBackgroundPrimary .ignoresSafeArea() if let response = viewModel.myResidences { ListAsyncContentView( items: response.residences, isLoading: viewModel.isLoading, errorMessage: viewModel.errorMessage, content: { residences in ResidencesContent( response: response, residences: residences ) }, emptyContent: { EmptyResidencesView() }, onRefresh: { viewModel.loadMyResidences(forceRefresh: true) }, onRetry: { viewModel.loadMyResidences() } ) } else if viewModel.isLoading { DefaultLoadingView() } else if let error = viewModel.errorMessage { DefaultErrorView(message: error, onRetry: { viewModel.loadMyResidences() }) } } .navigationTitle("My Properties") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing) { Button(action: { // Check if we should show upgrade prompt before joining let currentCount = viewModel.myResidences?.residences.count ?? 0 if subscriptionCache.shouldShowUpgradePrompt(currentCount: currentCount, limitKey: "properties") { showingUpgradePrompt = true } else { showingJoinResidence = true } }) { Image(systemName: "person.badge.plus") .font(.system(size: 18, weight: .semibold)) .foregroundColor(Color.appPrimary) } Button(action: { // Check if we should show upgrade prompt before adding let currentCount = viewModel.myResidences?.residences.count ?? 0 if subscriptionCache.shouldShowUpgradePrompt(currentCount: currentCount, limitKey: "properties") { showingUpgradePrompt = true } else { showingAddResidence = true } }) { Image(systemName: "plus.circle.fill") .font(.system(size: 22, weight: .semibold)) .foregroundColor(Color.appPrimary) } .accessibilityIdentifier(AccessibilityIdentifiers.Residence.addButton) } } .sheet(isPresented: $showingAddResidence) { AddResidenceView( isPresented: $showingAddResidence, onResidenceCreated: { viewModel.loadMyResidences(forceRefresh: true) } ) } .sheet(isPresented: $showingJoinResidence) { JoinResidenceView(onJoined: { viewModel.loadMyResidences() }) } .sheet(isPresented: $showingUpgradePrompt) { UpgradePromptView(triggerKey: "add_second_property", isPresented: $showingUpgradePrompt) } .onAppear { if authManager.isAuthenticated { viewModel.loadMyResidences() } } .fullScreenCover(isPresented: $authManager.isAuthenticated.negated) { LoginView(onLoginSuccess: { authManager.isAuthenticated = true viewModel.loadMyResidences() }) .interactiveDismissDisabled() } .onChange(of: authManager.isAuthenticated) { isAuth in if isAuth { // User just logged in or registered - load their residences viewModel.loadMyResidences() } else { // User logged out - clear data viewModel.myResidences = nil } } } } // MARK: - Residences Content View private struct ResidencesContent: View { let response: MyResidencesResponse let residences: [ResidenceWithTasks] var body: some View { ScrollView(showsIndicators: false) { VStack(spacing: AppSpacing.lg) { // Summary Card SummaryCard(summary: response.summary) .padding(.horizontal, AppSpacing.md) .padding(.top, AppSpacing.sm) // Properties Header HStack { VStack(alignment: .leading, spacing: AppSpacing.xxs) { Text("Your Properties") .font(.title3.weight(.semibold)) .foregroundColor(Color.appTextPrimary) Text("\(residences.count) \(residences.count == 1 ? "property" : "properties")") .font(.callout) .foregroundColor(Color.appTextSecondary) } Spacer() } .padding(.horizontal, AppSpacing.md) // Residences List ForEach(residences, id: \.id) { residence in NavigationLink(destination: ResidenceDetailView(residenceId: residence.id)) { ResidenceCard(residence: residence) .padding(.horizontal, AppSpacing.md) } .buttonStyle(PlainButtonStyle()) } } .padding(.bottom, AppSpacing.xxxl) } .safeAreaInset(edge: .bottom) { Color.clear.frame(height: 0) } } } #Preview { NavigationView { ResidencesListView() } } extension Binding where Value == Bool { var negated: Binding { Binding( get: { !self.wrappedValue }, set: { self.wrappedValue = !$0 } ) } }