Wire onboarding task suggestions to backend, delete hardcoded catalog
Both "For You" and "Browse All" tabs are now fully server-driven on iOS and Android. No on-device task list, no client-side scoring rules. When the API fails the screen shows error + Retry + Skip so onboarding can still complete on a flaky network. Shared (KMM) - TaskCreateRequest + TaskResponse carry templateId - New BulkCreateTasksRequest/Response, TaskApi.bulkCreateTasks, APILayer.bulkCreateTasks (updates DataManager + TotalSummary) - OnboardingViewModel: templatesGroupedState + loadTemplatesGrouped; createTasks(residenceId, requests) posts once via the bulk path - Deleted regional-template plumbing: APILayer.getRegionalTemplates, OnboardingViewModel.loadRegionalTemplates, TaskTemplateApi. getTemplatesByRegion, TaskTemplate.regionId/regionName - 5 new AnalyticsEvents constants for the onboarding funnel Android (Compose) - OnboardingFirstTaskContent rewritten against the server catalog; ~70 lines of hardcoded taskCategories gone. Loading / Error / Empty panes with Retry + Skip buttons. Category icons derived from name keywords, colours from a 5-value palette keyed by category id - Browse selection carries template.id into the bulk request so task_template_id is populated server-side iOS (SwiftUI) - New OnboardingTasksViewModel (@MainActor ObservableObject) wrapping APILayer.shared for suggestions / grouped / bulk-submit with loading + error state (mirrors the TaskViewModel.swift pattern) - OnboardingFirstTaskView rewritten: buildForYouSuggestions (130 lines) and fallbackCategories (68 lines) deleted; both tabs show the same error+skip UX as Android; ForYouSuggestion/SuggestionRelevance gone - 5 new AnalyticsEvent cases with identical PostHog event names to the Kotlin constants so cross-platform funnels join cleanly - Existing TaskCreateRequest / TaskResponse call sites in TaskCard, TasksSection, TaskFormView updated for the new templateId parameter Docs - CLAUDE.md gains an "Onboarding task suggestions (server-driven)" subsection covering the data flow, key files on both platforms, and the KotlinInt(int: template.id) wrapping requirement Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,9 @@ data class TaskResponse(
|
||||
@SerialName("is_cancelled") val isCancelled: Boolean = false,
|
||||
@SerialName("is_archived") val isArchived: Boolean = false,
|
||||
@SerialName("parent_task_id") val parentTaskId: Int? = null,
|
||||
// Backlink to the TaskTemplate this task was spawned from (onboarding
|
||||
// suggestion or browse catalog). Null for user-created custom tasks.
|
||||
@SerialName("template_id") val templateId: Int? = null,
|
||||
@SerialName("completion_count") val completionCount: Int = 0,
|
||||
@SerialName("kanban_column") val kanbanColumn: String? = null, // Which kanban column this task belongs to
|
||||
// Note: Go API does not return completions inline with TaskResponse.
|
||||
@@ -133,7 +136,33 @@ data class TaskCreateRequest(
|
||||
@SerialName("assigned_to_id") val assignedToId: Int? = null,
|
||||
@SerialName("due_date") val dueDate: String? = null,
|
||||
@SerialName("estimated_cost") val estimatedCost: Double? = null,
|
||||
@SerialName("contractor_id") val contractorId: Int? = null
|
||||
@SerialName("contractor_id") val contractorId: Int? = null,
|
||||
// Set when the task is spawned from a TaskTemplate (onboarding
|
||||
// suggestion or browse catalog). Null for free-form custom tasks.
|
||||
@SerialName("template_id") val templateId: Int? = null
|
||||
)
|
||||
|
||||
/**
|
||||
* Bulk create request matching Go API BulkCreateTasksRequest.
|
||||
* Used by onboarding to insert 1-50 tasks atomically in a single
|
||||
* transaction. The server forces every entry's residence_id to the
|
||||
* top-level value, so any mismatch in the list is silently corrected.
|
||||
*/
|
||||
@Serializable
|
||||
data class BulkCreateTasksRequest(
|
||||
@SerialName("residence_id") val residenceId: Int,
|
||||
val tasks: List<TaskCreateRequest>
|
||||
)
|
||||
|
||||
/**
|
||||
* Bulk create response matching Go API BulkCreateTasksResponse.
|
||||
* All [tasks] are created-or-none — partial state never reaches the client.
|
||||
*/
|
||||
@Serializable
|
||||
data class BulkCreateTasksResponse(
|
||||
val tasks: List<TaskResponse>,
|
||||
val summary: TotalSummary,
|
||||
@SerialName("created_count") val createdCount: Int
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,9 +20,7 @@ data class TaskTemplate(
|
||||
@SerialName("icon_android") val iconAndroid: String = "",
|
||||
val tags: List<String> = emptyList(),
|
||||
@SerialName("display_order") val displayOrder: Int = 0,
|
||||
@SerialName("is_active") val isActive: Boolean = true,
|
||||
@SerialName("region_id") val regionId: Int? = null,
|
||||
@SerialName("region_name") val regionName: String? = null
|
||||
@SerialName("is_active") val isActive: Boolean = true
|
||||
) {
|
||||
/**
|
||||
* Human-readable frequency display
|
||||
|
||||
Reference in New Issue
Block a user