Add documentation and remove hardcoded task threshold from API calls
Added comprehensive usage documentation for dynamic task summary components and updated TaskApi to rely on backend's default threshold value. **Changes:** **New: TASK_SUMMARY_USAGE.md** - Complete Android usage guide for TaskSummaryCard component - Examples of basic usage, filtering categories, and customization - Documents all available categories and their metadata - Shows how to use dynamic task summary in different screens **New: iosApp/TASK_SUMMARY_USAGE_IOS.md** - Complete iOS usage guide for TaskSummaryCard SwiftUI component - Examples for ResidenceDetailView, ResidenceCard, and HomeScreen - Documents SF Symbol icon usage and color parsing - Integration examples and troubleshooting tips **New: TaskConstants.kt** - Created client-side constants file (currently unused) - Contains TASK_CURRENT_THRESHOLD_DAYS = 29 - Available for future use if client needs local threshold **Updated: TaskApi.kt** - Changed days parameter from `days: Int = 30` to `days: Int? = null` - Now only sends days parameter to backend if explicitly provided - Allows backend's default threshold (29 days) to be used - Applied to both getTasks() and getTasksByResidence() **Updated: ApiConfig.kt** - Minor configuration update **Benefits:** ✅ Comprehensive documentation for both platforms ✅ Apps now use backend's default threshold value ✅ Cleaner API calls without unnecessary parameters ✅ Client can still override threshold if needed ✅ Documentation includes troubleshooting and best practices 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
254
iosApp/TASK_SUMMARY_USAGE_IOS.md
Normal file
254
iosApp/TASK_SUMMARY_USAGE_IOS.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# Task Summary Card - iOS Usage Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The `TaskSummaryCard` SwiftUI component displays task statistics dynamically based on backend data. All metadata (icons, colors, display names) comes from the API.
|
||||
|
||||
## Files Created
|
||||
|
||||
1. **`Components/TaskSummaryCard.swift`** - Main component
|
||||
|
||||
**Note:** The component uses the existing `Color(hex:)` initializer from `Design/DesignSystem.swift`, so no additional files are needed.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Example 1: Show All Categories
|
||||
|
||||
In `ResidenceDetailView.swift` or `ResidencesListView.swift`:
|
||||
|
||||
```swift
|
||||
import SwiftUI
|
||||
import Shared
|
||||
|
||||
struct ResidenceDetailView: View {
|
||||
let residence: ResidenceSummary
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(spacing: 16) {
|
||||
// Residence info...
|
||||
|
||||
// Task summary with all categories
|
||||
TaskSummaryCard(taskSummary: residence.taskSummary)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Show Only Specific Categories
|
||||
|
||||
For the main residence list, show only key categories:
|
||||
|
||||
```swift
|
||||
struct ResidenceCard: View {
|
||||
let residence: ResidenceSummary
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text(residence.name)
|
||||
.font(.title2)
|
||||
.fontWeight(.bold)
|
||||
|
||||
Text(residence.streetAddress)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
// Only show overdue, current, and in progress
|
||||
TaskSummaryCard(
|
||||
taskSummary: residence.taskSummary,
|
||||
visibleCategories: [
|
||||
"overdue_tasks",
|
||||
"current_tasks",
|
||||
"in_progress_tasks"
|
||||
]
|
||||
)
|
||||
}
|
||||
.padding()
|
||||
.background(Color(.systemBackground))
|
||||
.cornerRadius(12)
|
||||
.shadow(radius: 2)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: In Home Screen
|
||||
|
||||
```swift
|
||||
struct HomeScreenView: View {
|
||||
@StateObject private var viewModel = ResidenceViewModel()
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(spacing: 20) {
|
||||
ForEach(viewModel.residences, id: \.id) { residence in
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
NavigationLink(destination: ResidenceDetailView(residence: residence)) {
|
||||
VStack(alignment: .leading) {
|
||||
Text(residence.name)
|
||||
.font(.headline)
|
||||
|
||||
// Show task summary for quick overview
|
||||
TaskSummaryCard(
|
||||
taskSummary: residence.taskSummary,
|
||||
visibleCategories: ["overdue_tasks", "current_tasks"]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Available Categories
|
||||
|
||||
The backend provides these categories (can filter with `visibleCategories`):
|
||||
|
||||
1. **overdue_tasks** - Red (#FF3B30) - `exclamationmark.triangle`
|
||||
2. **current_tasks** - Blue (#007AFF) - `calendar`
|
||||
3. **in_progress_tasks** - Orange (#FF9500) - `play.circle`
|
||||
4. **backlog_tasks** - Purple (#5856D6) - `tray`
|
||||
5. **done_tasks** - Green (#34C759) - `checkmark.circle`
|
||||
6. **archived_tasks** - Gray (#8E8E93) - `archivebox`
|
||||
|
||||
## Customization
|
||||
|
||||
### Custom Styling
|
||||
|
||||
```swift
|
||||
TaskSummaryCard(taskSummary: taskSummary)
|
||||
.padding()
|
||||
.background(Color(.secondarySystemBackground))
|
||||
.cornerRadius(16)
|
||||
.shadow(color: Color.black.opacity(0.2), radius: 8, x: 0, y: 4)
|
||||
```
|
||||
|
||||
### Filter Specific Categories
|
||||
|
||||
```swift
|
||||
// Show only active tasks
|
||||
TaskSummaryCard(
|
||||
taskSummary: taskSummary,
|
||||
visibleCategories: [
|
||||
"overdue_tasks",
|
||||
"current_tasks",
|
||||
"in_progress_tasks",
|
||||
"backlog_tasks"
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
### Access Individual Category Counts
|
||||
|
||||
If you need to access counts programmatically:
|
||||
|
||||
```swift
|
||||
extension TaskSummary {
|
||||
func categoryCount(for name: String) -> Int {
|
||||
categories.first { $0.name == name }?.count ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
// Usage:
|
||||
let overdueCount = taskSummary.categoryCount(for: "overdue_tasks")
|
||||
```
|
||||
|
||||
## Component Features
|
||||
|
||||
✅ **Dynamic Icons** - Uses SF Symbols from backend (e.g., `calendar`, `exclamationmark.triangle`)
|
||||
✅ **Dynamic Colors** - Parses hex colors from backend
|
||||
✅ **Flexible Filtering** - Show only categories you need
|
||||
✅ **Live Preview** - Includes SwiftUI preview with mock data
|
||||
✅ **Responsive** - Adapts to different screen sizes
|
||||
✅ **Native Look** - Uses iOS design patterns and typography
|
||||
|
||||
## Preview
|
||||
|
||||
The component includes a preview for development. In Xcode:
|
||||
|
||||
1. Open `Components/TaskSummaryCard.swift`
|
||||
2. Click "Resume" in the preview canvas
|
||||
3. See both "all categories" and "filtered" versions
|
||||
|
||||
## Integration Example
|
||||
|
||||
Here's a complete example for ResidenceDetailView:
|
||||
|
||||
```swift
|
||||
import SwiftUI
|
||||
import Shared
|
||||
|
||||
struct ResidenceDetailView: View {
|
||||
let residence: ResidenceSummary
|
||||
@State private var showingManageUsers = false
|
||||
@State private var showingTasks = false
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
// Header
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(residence.name)
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
|
||||
Text(residence.streetAddress)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
// Task Summary Card
|
||||
TaskSummaryCard(
|
||||
taskSummary: residence.taskSummary,
|
||||
visibleCategories: [
|
||||
"overdue_tasks",
|
||||
"current_tasks",
|
||||
"in_progress_tasks"
|
||||
]
|
||||
)
|
||||
.padding(.horizontal)
|
||||
.onTapGesture {
|
||||
showingTasks = true
|
||||
}
|
||||
|
||||
// Other residence details...
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
.navigationTitle("Residence Details")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.sheet(isPresented: $showingTasks) {
|
||||
TasksView(residenceId: residence.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Backend-Driven** - All icons, colors, names from API
|
||||
✅ **Single Source of Truth** - Change in `task/constants.py` updates everywhere
|
||||
✅ **Type-Safe** - Full Swift type safety with Shared models
|
||||
✅ **Reusable** - Use in any view that has TaskSummary
|
||||
✅ **Consistent** - Matches Android implementation
|
||||
✅ **Maintainable** - No hardcoded values
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Colors not showing correctly
|
||||
Make sure `Extensions/Color+Hex.swift` is included in your target.
|
||||
|
||||
### Icons not appearing
|
||||
The component uses SF Symbols. Ensure the icon names from backend are valid SF Symbol names.
|
||||
|
||||
### Type errors
|
||||
Make sure you're importing `Shared` module which contains the TaskSummary models.
|
||||
|
||||
### Preview not working
|
||||
The preview uses mock data. If you get compiler errors, make sure all model types are properly imported.
|
||||
Reference in New Issue
Block a user