Centralize kanban state in TaskViewModel to eliminate duplicate code

Move tasksResponse state and updateTaskInKanban logic from individual views
into TaskViewModel. Both AllTasksView and ResidenceDetailView now delegate
to the shared ViewModel, reducing code duplication and ensuring consistent
task state management across the app.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-02 22:07:52 -06:00
parent 00e303c3be
commit b79fda8aee
3 changed files with 168 additions and 169 deletions

View File

@@ -6,10 +6,11 @@ struct ResidenceDetailView: View {
@StateObject private var viewModel = ResidenceViewModel()
@StateObject private var taskViewModel = TaskViewModel()
@State private var tasksResponse: TaskColumnsResponse?
@State private var isLoadingTasks = false
@State private var tasksError: String?
// Use TaskViewModel's state instead of local state
private var tasksResponse: TaskColumnsResponse? { taskViewModel.tasksResponse }
private var isLoadingTasks: Bool { taskViewModel.isLoadingTasks }
private var tasksError: String? { taskViewModel.tasksError }
@State private var contractors: [ContractorSummary] = []
@State private var isLoadingContractors = false
@@ -377,89 +378,11 @@ private extension ResidenceDetailView {
}
func loadResidenceTasks(forceRefresh: Bool = false) {
guard TokenStorage.shared.getToken() != nil else { return }
isLoadingTasks = true
tasksError = nil
Task {
do {
let result = try await APILayer.shared.getTasksByResidence(
residenceId: Int32(Int(residenceId)),
forceRefresh: forceRefresh
)
await MainActor.run {
if let successResult = result as? ApiResultSuccess<TaskColumnsResponse> {
self.tasksResponse = successResult.data
self.isLoadingTasks = false
} else if let errorResult = result as? ApiResultError {
self.tasksError = errorResult.message
self.isLoadingTasks = false
} else {
self.tasksError = "Failed to load tasks"
self.isLoadingTasks = false
}
}
} catch {
await MainActor.run {
self.tasksError = error.localizedDescription
self.isLoadingTasks = false
}
}
}
taskViewModel.loadTasks(residenceId: residenceId, forceRefresh: forceRefresh)
}
/// Updates a task in the kanban board by moving it to the correct column based on kanban_column
func updateTaskInKanban(_ updatedTask: TaskResponse) {
print("DEBUG: updateTaskInKanban called")
guard let currentResponse = tasksResponse else {
print("DEBUG: tasksResponse is nil, returning")
return
}
let targetColumn = updatedTask.kanbanColumn ?? "completed_tasks"
print("DEBUG: targetColumn = \(targetColumn)")
// Build new columns array
var newColumns: [TaskColumn] = []
for column in currentResponse.columns {
print("DEBUG: Processing column: \(column.name)")
// Remove task from this column if it exists
var filteredTasks = column.tasks.filter { $0.id != updatedTask.id }
let removed = column.tasks.count - filteredTasks.count
if removed > 0 {
print("DEBUG: Removed \(removed) task(s) from \(column.name)")
}
// Add task to target column
if column.name == targetColumn {
filteredTasks.append(updatedTask)
print("DEBUG: Added task to \(column.name)")
}
// Create new column with updated tasks and count
let newColumn = TaskColumn(
name: column.name,
displayName: column.displayName,
buttonTypes: column.buttonTypes,
icons: column.icons,
color: column.color,
tasks: filteredTasks,
count: Int32(filteredTasks.count)
)
newColumns.append(newColumn)
}
// Update the response
print("DEBUG: Updating tasksResponse with new columns")
tasksResponse = TaskColumnsResponse(
columns: newColumns,
daysThreshold: currentResponse.daysThreshold,
residenceId: currentResponse.residenceId
)
print("DEBUG: tasksResponse updated")
taskViewModel.updateTaskInKanban(updatedTask)
}
func deleteResidence() {