Fix logout, share code display, loading states, and multi-user support

iOS Logout Fix:
- Use @EnvironmentObject in MainTabView and ProfileTabView
- Pass loginViewModel from LoginView to MainTabView
- Handle logout by dismissing main tab when isAuthenticated becomes false
- Logout button now properly returns user to login screen

Share Code UX:
- Clear share code on ManageUsers screen open (iOS & Android)
- Remove auto-loading of share codes
- User must explicitly generate code each time
- Improves security with fresh codes

Loading State Improvements:
- iOS ResidenceDetailView shows loading immediately on navigation
- Android ResidenceDetailScreen enhanced with "Loading residence..." text
- Better user feedback during API calls

Multi-User Support:
- Add isPrimaryOwner and userCount to ResidenceWithTasks model
- Update iOS toResidences() extension to include new fields
- Sync with backend API changes for shared user access

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-08 10:51:51 -06:00
parent e271403d9b
commit 364f98a303
8 changed files with 686 additions and 8 deletions

View File

@@ -11,16 +11,23 @@ struct ResidenceDetailView: View {
@State private var showAddTask = false
@State private var showEditResidence = false
@State private var showEditTask = false
@State private var showManageUsers = false
@State private var selectedTaskForEdit: TaskDetail?
@State private var selectedTaskForComplete: TaskDetail?
@State private var hasAppeared = false
var body: some View {
ZStack {
Color(.systemGroupedBackground)
.ignoresSafeArea()
if viewModel.isLoading {
ProgressView()
if !hasAppeared || viewModel.isLoading {
VStack(spacing: 16) {
ProgressView()
Text("Loading residence...")
.font(.subheadline)
.foregroundColor(.secondary)
}
} else if let error = viewModel.errorMessage {
ErrorView(message: error) {
loadResidenceData()
@@ -85,7 +92,6 @@ struct ResidenceDetailView: View {
}
}
}
.navigationTitle("Property Details")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
@@ -98,7 +104,16 @@ struct ResidenceDetailView: View {
}
}
ToolbarItem(placement: .navigationBarTrailing) {
ToolbarItemGroup(placement: .navigationBarTrailing) {
// Manage Users button - only show for primary owners
if let residence = viewModel.selectedResidence, residence.isPrimaryOwner {
Button(action: {
showManageUsers = true
}) {
Image(systemName: "person.2")
}
}
Button(action: {
showAddTask = true
}) {
@@ -125,6 +140,15 @@ struct ResidenceDetailView: View {
loadResidenceTasks()
}
}
.sheet(isPresented: $showManageUsers) {
if let residence = viewModel.selectedResidence {
ManageUsersView(
residenceId: residence.id,
residenceName: residence.name,
isPrimaryOwner: residence.isPrimaryOwner
)
}
}
.onChange(of: showAddTask) { isShowing in
if !isShowing {
loadResidenceTasks()
@@ -143,6 +167,11 @@ struct ResidenceDetailView: View {
.onAppear {
loadResidenceData()
}
.onChange(of: viewModel.selectedResidence) { _, residence in
if residence != nil {
hasAppeared = true
}
}
}
private func loadResidenceData() {