9ececfa48a
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>
57 lines
1.6 KiB
Kotlin
57 lines
1.6 KiB
Kotlin
package com.tt.honeyDue.models
|
|
|
|
import kotlinx.serialization.SerialName
|
|
import kotlinx.serialization.Serializable
|
|
|
|
/**
|
|
* Represents a task template fetched from the backend API.
|
|
* Users can select these when adding a new task to auto-fill form fields.
|
|
*/
|
|
@Serializable
|
|
data class TaskTemplate(
|
|
val id: Int,
|
|
val title: String,
|
|
val description: String = "",
|
|
@SerialName("category_id") val categoryId: Int? = null,
|
|
val category: TaskCategory? = null,
|
|
@SerialName("frequency_id") val frequencyId: Int? = null,
|
|
val frequency: TaskFrequency? = null,
|
|
@SerialName("icon_ios") val iconIos: String = "",
|
|
@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
|
|
) {
|
|
/**
|
|
* Human-readable frequency display
|
|
*/
|
|
val frequencyDisplay: String
|
|
get() = frequency?.displayName ?: "One time"
|
|
|
|
/**
|
|
* Category name for display
|
|
*/
|
|
val categoryName: String
|
|
get() = category?.name ?: "Uncategorized"
|
|
}
|
|
|
|
/**
|
|
* Response for grouped templates by category
|
|
*/
|
|
@Serializable
|
|
data class TaskTemplateCategoryGroup(
|
|
@SerialName("category_name") val categoryName: String,
|
|
@SerialName("category_id") val categoryId: Int? = null,
|
|
val templates: List<TaskTemplate>,
|
|
val count: Int
|
|
)
|
|
|
|
/**
|
|
* Response for all templates grouped by category
|
|
*/
|
|
@Serializable
|
|
data class TaskTemplatesGroupedResponse(
|
|
val categories: List<TaskTemplateCategoryGroup>,
|
|
@SerialName("total_count") val totalCount: Int
|
|
)
|