Remove API pagination and fix contractor UI issues
- Remove pagination from all Django REST Framework endpoints - Update Kotlin API clients to return direct lists instead of paginated responses - Update iOS ViewModels to handle direct list responses - Remove ContractorListResponse, DocumentListResponse, and PaginatedResponse models - Fix contractor form specialty selector loading with improved DataCache access - Fix contractor sheet presentation to use full screen (.presentationDetents([.large])) - Improve UI test scrolling to handle lists of any size with smart end detection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,7 @@ struct ContractorCard: View {
|
||||
Text(contractor.name)
|
||||
.font(.title3.weight(.semibold))
|
||||
.foregroundColor(Color.appTextPrimary)
|
||||
.lineLimit(1)
|
||||
// .lineLimit(1)
|
||||
|
||||
if contractor.isFavorite {
|
||||
Image(systemName: "star.fill")
|
||||
@@ -39,7 +39,7 @@ struct ContractorCard: View {
|
||||
Text(company)
|
||||
.font(.body)
|
||||
.foregroundColor(Color.appTextSecondary)
|
||||
.lineLimit(1)
|
||||
// .lineLimit(1)
|
||||
}
|
||||
|
||||
// Info row
|
||||
|
||||
@@ -203,6 +203,7 @@ struct ContractorDetailView: View {
|
||||
viewModel.loadContractorDetail(id: contractorId)
|
||||
}
|
||||
)
|
||||
.presentationDetents([.large])
|
||||
}
|
||||
.alert("Delete Contractor", isPresented: $showingDeleteAlert) {
|
||||
Button("Cancel", role: .cancel) {}
|
||||
|
||||
@@ -38,7 +38,7 @@ struct ContractorFormSheet: View {
|
||||
@State private var contractorSpecialties: [ContractorSpecialty] = []
|
||||
|
||||
private var specialties: [String] {
|
||||
contractorSpecialties.map { $0.name }
|
||||
return DataCache.shared.contractorSpecialties.value.map { $0.name }
|
||||
}
|
||||
|
||||
private var canSave: Bool {
|
||||
@@ -290,11 +290,10 @@ struct ContractorFormSheet: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.presentationDetents([.medium, .large])
|
||||
.presentationDetents([.large])
|
||||
}
|
||||
.onAppear {
|
||||
loadContractorData()
|
||||
loadContractorSpecialties()
|
||||
}
|
||||
.handleErrors(
|
||||
error: viewModel.errorMessage,
|
||||
@@ -324,16 +323,6 @@ struct ContractorFormSheet: View {
|
||||
isFavorite = contractor.isFavorite
|
||||
}
|
||||
|
||||
private func loadContractorSpecialties() {
|
||||
Task {
|
||||
await MainActor.run {
|
||||
if let specialties = DataCache.shared.contractorSpecialties.value as? [ContractorSpecialty] {
|
||||
self.contractorSpecialties = specialties
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Save Action
|
||||
|
||||
private func saveContractor() {
|
||||
|
||||
@@ -49,9 +49,9 @@ class ContractorViewModel: ObservableObject {
|
||||
await MainActor.run {
|
||||
self.isLoading = true
|
||||
}
|
||||
} else if let success = state as? ApiResultSuccess<ContractorListResponse> {
|
||||
} else if let success = state as? ApiResultSuccess<NSArray> {
|
||||
await MainActor.run {
|
||||
self.contractors = success.data?.results ?? []
|
||||
self.contractors = success.data as? [ContractorSummary] ?? []
|
||||
self.isLoading = false
|
||||
}
|
||||
break
|
||||
|
||||
@@ -159,6 +159,7 @@ struct ContractorsListView: View {
|
||||
loadContractors()
|
||||
}
|
||||
)
|
||||
.presentationDetents([.large])
|
||||
}
|
||||
.onAppear {
|
||||
loadContractors()
|
||||
@@ -183,8 +184,17 @@ struct ContractorsListView: View {
|
||||
|
||||
private func loadContractorSpecialties() {
|
||||
Task {
|
||||
// Small delay to ensure DataCache is populated
|
||||
try? await Task.sleep(nanoseconds: 100_000_000) // 0.1 seconds
|
||||
|
||||
await MainActor.run {
|
||||
self.contractorSpecialties = DataCache.shared.contractorSpecialties.value as! [ContractorSpecialty]
|
||||
if let specialties = DataCache.shared.contractorSpecialties.value as? [ContractorSpecialty] {
|
||||
self.contractorSpecialties = specialties
|
||||
print("✅ ContractorsList: Loaded \(specialties.count) contractor specialties")
|
||||
} else {
|
||||
print("❌ ContractorsList: Failed to load contractor specialties from DataCache")
|
||||
self.contractorSpecialties = []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ struct DocumentCard: View {
|
||||
.font(.title3.weight(.semibold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(Color.appTextPrimary)
|
||||
.lineLimit(1)
|
||||
// .lineLimit(1)
|
||||
|
||||
if let description = document.description_, !description.isEmpty {
|
||||
Text(description)
|
||||
|
||||
@@ -49,9 +49,9 @@ class DocumentViewModel: ObservableObject {
|
||||
await MainActor.run {
|
||||
self.isLoading = true
|
||||
}
|
||||
} else if let success = state as? ApiResultSuccess<DocumentListResponse> {
|
||||
} else if let success = state as? ApiResultSuccess<NSArray> {
|
||||
await MainActor.run {
|
||||
self.documents = success.data?.results as? [Document] ?? []
|
||||
self.documents = success.data as? [Document] ?? []
|
||||
self.isLoading = false
|
||||
}
|
||||
break
|
||||
|
||||
@@ -94,8 +94,8 @@ class DocumentViewModelWrapper: ObservableObject {
|
||||
)
|
||||
|
||||
await MainActor.run {
|
||||
if let success = result as? ApiResultSuccess<DocumentListResponse> {
|
||||
let documents = success.data?.results as? [Document] ?? []
|
||||
if let success = result as? ApiResultSuccess<NSArray> {
|
||||
let documents = success.data as? [Document] ?? []
|
||||
self.documentsState = DocumentStateSuccess(documents: documents)
|
||||
} else if let error = result as? ApiResultError {
|
||||
self.documentsState = DocumentStateError(message: error.message)
|
||||
|
||||
@@ -24,7 +24,7 @@ struct ResidenceCard: View {
|
||||
.font(.title3.weight(.semibold))
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(Color.appTextPrimary)
|
||||
.lineLimit(1)
|
||||
// .lineLimit(1)
|
||||
|
||||
if let propertyType = residence.propertyType {
|
||||
Text(propertyType)
|
||||
|
||||
Reference in New Issue
Block a user