Files
Sportstime/docs/plans/2026-01-12-trip-planning-enhancements-design.md
Trey t 3530b31cca docs: add 3 feature enhancement design plans
- Trip Planning Enhancements: progressive reveal single-screen wizard
- Progress Tracking Enhancements: multiple visits, games history, zoomable map
- Polish Enhancements: grouped sorting, 100+ planning tips

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 19:07:46 -06:00

136 lines
5.1 KiB
Markdown

# Trip Planning Enhancements Design
**Date:** 2026-01-12
**Status:** Draft
**Scope:** High-level overview for scoping/prioritization
## Goal
Transform trip creation from a dense single-form into a guided, progressive-reveal flow that walks users through planning one decision at a time—while keeping everything on a single scrolling screen.
## Current State
- Single `TripCreationView` (~2500 lines) with all options visible at once
- Planning mode selector controls which sections appear
- 4 planning modes: Date Range, Game First, Locations, Follow Team
- Sports without games in date range are not indicated
## Target State
- Progressive disclosure: sections reveal as user makes selections
- Conversational headers guide the user ("Great! When would you like to travel?")
- Each section is a small, focused view component (~100-150 lines)
- Sports with no games in selected date range are grayed out
- Current form remains accessible via Settings toggle for power users
## Approach: Progressive Single-Screen Flow
### Container Architecture
```swift
struct TripWizardView: View {
@State var viewModel = TripWizardViewModel()
var body: some View {
ScrollView {
VStack(spacing: Theme.Spacing.lg) {
// Always visible
PlanningModeStep(selection: $viewModel.planningMode)
// Reveals after planning mode selected
if viewModel.planningMode != nil {
SportsStep(...)
.transition(.move(edge: .bottom).combined(with: .opacity))
}
// Reveals after at least one sport selected
if !viewModel.selectedSports.isEmpty {
DatesStep(...)
.transition(.move(edge: .bottom).combined(with: .opacity))
}
// Continues for each step...
}
.animation(.easeInOut(duration: 0.3), value: viewModel.revealState)
}
}
}
```
### Step Sequence
| Step | Question | Reveals When |
|------|----------|--------------|
| 1 | "How do you want to plan?" | Always visible |
| 2 | "Which sports interest you?" | After planning mode selected |
| 3 | "When would you like to travel?" | After sport(s) selected |
| 4 | "Where do you want to go?" | After dates set |
| 5 | "What's your route preference?" | After region(s) selected |
| 6 | "Visit cities more than once?" | After route preference |
| 7 | "Any must-stop locations?" | After repeat cities choice |
| 8 | Review & Plan button | After all required steps complete |
Note: Step order varies by planning mode (e.g., "Game First" skips dates, shows game picker).
### Behavior
- Steps slide in from bottom with fade animation
- Auto-scroll to newly revealed section (300ms after animation starts)
- User can scroll back up and change earlier answers
- Changing an answer resets/updates downstream sections as needed
- Conversational headers: "Nice! Now pick your travel dates"
### Sport Availability (Graying)
After date selection:
1. Fetch game counts per sport for selected date range
2. Use existing `AppDataProvider.shared.filterGames(sports:startDate:endDate:)`
3. Cache results; re-fetch if dates change
4. Display: grayed card + disabled + subtitle "No games in this period"
## File Structure
```
Features/Trip/Views/Wizard/
├── TripWizardView.swift # Container with progressive reveal logic
├── TripWizardViewModel.swift # Shared state across all steps
├── Steps/
│ ├── PlanningModeStep.swift # "How do you want to plan?"
│ ├── SportsStep.swift # Sport grid with availability graying
│ ├── DatesStep.swift # Date range picker
│ ├── RegionsStep.swift # Region map
│ ├── RoutePreferenceStep.swift # Efficient/Scenic/Flexible
│ ├── RepeatCitiesStep.swift # Yes/No toggle
│ ├── MustStopsStep.swift # Optional locations
│ └── ReviewStep.swift # Summary + Plan button
```
## Key Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Keep old `TripCreationView`? | Yes | Power users, accessible via Settings toggle |
| Reset downstream on change? | Yes | Changing sports resets dates, changing dates refetches sport availability |
| Sport graying | Grayed + disabled + subtitle | Clear feedback why sport unavailable |
| Auto-scroll | 300ms delay after reveal | Let animation start before scrolling |
| Step headers | Conversational tone | Guides user, feels less like a form |
## Not Included (YAGNI)
- Progress indicator (single screen doesn't need it)
- Save draft functionality (overkill for single-session flow)
- Undo/redo beyond scrolling back up
- Swipe gestures between steps (intentional friction for decisions)
## Dependencies
- None - uses existing data providers and models
- `AppDataProvider.shared.filterGames()` for sport availability
## Testing Considerations
- Test progressive reveal with all 4 planning modes
- Test sport availability graying with various date ranges
- Test downstream reset when changing earlier selections
- Test auto-scroll behavior on different screen sizes