Commit Graph

117 Commits

Author SHA1 Message Date
Trey t
af2a5cd204 chore: remove legacy itinerary models and services
Removed:
- CustomItineraryItem
- TravelDayOverride
- CustomItemService
- CustomItemSubscriptionService
- TravelOverrideService
- CustomItemRow

These are replaced by unified ItineraryItem model and service.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:24:47 -06:00
Trey t
cae24efa90 feat: add ItineraryItemService with CloudKit sync
Debounced updates (1.5s), local-first with silent retry.
Supports game, travel, and custom item kinds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:23:01 -06:00
Trey t
12c2de8a1b feat: add ItineraryConstraints with full test coverage
Validates travel positions based on game locations:
- Travel must be after ALL departure city games
- Travel must be before ALL arrival city games
- Custom items have no constraints
- Games are fixed (cannot be moved)

12 tests covering all constraint scenarios including edge cases.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 21:14:02 -06:00
Trey t
d14976812a feat: add unified ItineraryItem model
Replaces CustomItineraryItem and TravelDayOverride with single model.
Supports game, travel, and custom item kinds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 20:57:56 -06:00
Trey t
c658d5f9f4 refactor(itinerary): embed Add button in day header row
Merge Add button into DaySectionHeaderView to prevent items from being
dragged between the day header and Add button. The Add button now uses
a SwiftUI Button with its own tap handler instead of row selection.

Changes:
- Remove .addButton case from ItineraryRowItem enum
- Update DaySectionHeaderView to include Add button on the right
- Pass onAddTapped callback through configureDayHeaderCell
- Remove AddButtonRowView (no longer needed)
- Update documentation to reflect new row structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 10:13:03 -06:00
Trey t
f84addb39d feat(itinerary): reorder Add button after day header + comprehensive docs
- Move Add button to appear immediately after Day header (before games)
- Split games out of dayHeader into separate row for correct ordering
- Add 600+ lines of inline documentation to ItineraryTableViewController
- Document architecture decisions, data flow, constraints, and algorithms
- Add function-level comments explaining drag/drop, sortOrder calculation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 10:07:37 -06:00
Trey t
2a8bfeeff8 refactor(itinerary): replace anchor-based positioning with day/sortOrder
Replace complex anchor system (anchorType, anchorId, anchorDay) with
simple (day: Int, sortOrder: Double) positioning for custom items.

Changes:
- CustomItineraryItem: Remove anchor fields, add day and sortOrder
- CKModels: Add migration fallback from old CloudKit fields
- ItineraryTableViewController: Add calculateSortOrder() for midpoint insertion
- TripDetailView: Simplify callbacks, itinerarySections, and routeWaypoints
- AddItemSheet: Take simple day parameter instead of anchor
- SavedTrip: Update LocalCustomItem SwiftData model

Benefits:
- Items freely movable via drag-and-drop
- Route waypoints follow exact visual order
- Simpler mental model: position = (day, sortOrder)
- Midpoint insertion allows unlimited reordering

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 09:47:11 -06:00
Trey t
8df33a5614 WIP: map route updates and custom item drag/drop fixes (broken)
- Fixed map header not updating in ItineraryTableViewWrapper using Coordinator pattern
- Added routeVersion UUID to force Map re-render when routes change
- Fixed determineAnchor to scan backwards for correct anchor context
- Added location support to CustomItineraryItem (lat/lng/address)
- Added MapKit place search to AddItemSheet
- Added extensive debug logging for route waypoint calculation

Known issues:
- Custom items still not routing correctly after drag/drop
- Anchor type determination may still have bugs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 00:00:57 -06:00
Trey t
43501b6ac1 feat(itinerary): add UITableView-based itinerary with unified scrolling
- Replace SwiftUI drag-drop with native UITableViewController for fluid reordering
- Add ItineraryTableViewController with native cell reordering and validation
- Add ItineraryTableViewWrapper for SwiftUI integration with header support
- Fix infinite layout loop by tracking header adjustment state
- Map and stats now scroll as table header with itinerary content
- Travel segments constrained to valid day ranges during drag
- One Add button per day (after game > after travel > rest day)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 22:35:27 -06:00
Trey t
bf9619a207 feat(itinerary): add draggable travel day positioning with CloudKit persistence
- Add TravelDayOverride model for storing user-customized travel day positions
- Add TravelOverrideService for CloudKit CRUD operations on travel overrides
- Add CKTravelDayOverride CloudKit model wrapper
- Refactor itinerarySections to validate travel day bounds (must be after last game in departure city)
- Travel segments can now be dragged to different days within valid range
- Persist travel day overrides to CloudKit for cross-device sync

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 19:00:52 -06:00
Trey t
29942eee57 fix(polls): prevent jarring reload when switching to My Trips tab
- Only load polls once on initial view appearance, not every tab switch
- Only show spinner when there's no existing data (first load)
- Subsequent refreshes update content in place without showing spinner

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 15:42:25 -06:00
Trey t
0130141f8a Merge branch 'custom_ish' 2026-01-16 15:38:28 -06:00
Trey t
aca394cefa fix(itinerary): improve drag-drop reordering with stable anchors and visual feedback
- Add visual drop target indicator showing where items will land
- Use stable travel anchor IDs (city names) instead of UUIDs that regenerate
- Fix findDayForTravelSegment to look forward to arrival day, not backward
- Add moveItemToBeginning() for inserting at position 0 when dropping on sections
- Sort custom items by sortOrder in all filters
- Sync shifted items to CloudKit after reorder
- Add opaque backgrounds to CustomItemRow and TravelSection to hide timeline

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 15:35:09 -06:00
Trey t
8162b4a029 refactor(tests): TDD rewrite of all unit tests with spec documentation
Complete rewrite of unit test suite using TDD methodology:

Planning Engine Tests:
- GameDAGRouterTests: Beam search, anchor games, transitions
- ItineraryBuilderTests: Stop connection, validators, EV enrichment
- RouteFiltersTests: Region, time window, scoring filters
- ScenarioA/B/C/D PlannerTests: All planning scenarios
- TravelEstimatorTests: Distance, duration, travel days
- TripPlanningEngineTests: Orchestration, caching, preferences

Domain Model Tests:
- AchievementDefinitionsTests, AnySportTests, DivisionTests
- GameTests, ProgressTests, RegionTests, StadiumTests
- TeamTests, TravelSegmentTests, TripTests, TripPollTests
- TripPreferencesTests, TripStopTests, SportTests

Service Tests:
- FreeScoreAPITests, RouteDescriptionGeneratorTests
- SuggestedTripsGeneratorTests

Export Tests:
- ShareableContentTests (card types, themes, dimensions)

Bug fixes discovered through TDD:
- ShareCardDimensions: mapSnapshotSize exceeded available width (960x480)
- ScenarioBPlanner: Added anchor game validation filter

All tests include:
- Specification tests (expected behavior)
- Invariant tests (properties that must always hold)
- Edge case tests (boundary conditions)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 14:07:41 -06:00
Trey t
495ef88303 feat(itinerary): add custom itinerary items with drag-to-reorder
- Add CustomItineraryItem domain model with sortOrder for ordering
- Add CKCustomItineraryItem CloudKit wrapper for persistence
- Create CustomItemService for CRUD operations
- Create CustomItemSubscriptionService for real-time sync
- Add AppDelegate for push notification handling
- Add AddItemSheet for creating/editing items
- Add CustomItemRow with drag handle
- Update TripDetailView with continuous vertical timeline
- Enable drag-to-reorder using .draggable/.dropDestination
- Add inline "Add" buttons after games and travel segments

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 00:31:44 -06:00
Trey t
00a5e4ef0e fix(planning): enforce daily driving limit for same-day games and group itinerary by city
Two fixes for route planning and display:

1. GameDAGRouter: Same-day game transitions now respect maxDailyDrivingHours
   constraint. Previously, a 12:05 AM game in Arlington could connect to an
   11:40 PM game in Milwaukee (19+ hour drive) because the code only checked
   available time, not the 8-hour daily limit.

2. TripDetailView: Itinerary sections now group by (day, city) not just day.
   Games in different cities on the same calendar day are shown as separate
   sections with travel segments between them.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 09:42:08 -06:00
Trey t
57eab22746 fix(polls): fetch existing CloudKit record before updating vote
When updating a vote, CloudKit requires the server's changeTag to modify
existing records. Creating a new CKRecord caused "record to insert already
exists" errors. Now fetches the existing record first before saving.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 23:59:40 -06:00
Trey t
aa34c6585a feat(wizard): add mode-specific trip wizard inputs
- Add GamePickerStep with sheet-based Sport → Team → Game selection
- Add TeamPickerStep with sheet-based Sport → Team selection
- Add LocationsStep for start/end location selection with round trip toggle
- Update TripWizardViewModel with mode-specific fields and validation
- Update TripWizardView with conditional step rendering per mode
- Update ReviewStep with mode-aware validation display
- Fix gameFirst mode to derive date range from selected games

Each planning mode now shows only relevant steps:
- By Dates: Dates → Sports → Regions → Route → Repeat → Must Stops
- By Games: Game Picker → Route → Repeat → Must Stops
- By Route: Locations → Dates → Sports → Route → Repeat → Must Stops
- Follow Team: Team Picker → Dates → Route → Repeat → Must Stops

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 22:21:57 -06:00
Trey t
1301442604 fix(ui): improve SuggestedTripCard padding and height
Increase card height from 160 to 175 and add extra bottom padding
to prevent date text from being cut off.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 13:28:20 -06:00
Trey t
d34be05d61 feat(design): add Classic Animated home screen style
New design style combines the Classic layout with subtle animated
backgrounds featuring floating sports icons and route lines.
Animations are slow and unobtrusive to avoid distracting from content.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 13:23:13 -06:00
Trey t
f7f1bbd87a feat(settings): add dark/light/system appearance mode toggle
- Add AppearanceMode enum with system, light, and dark options
- Add AppearanceManager singleton to persist user preference
- Add appearance section in SettingsView with icon and description
- Apply preferredColorScheme at app root for immediate effect
- Include appearance mode in reset to defaults

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 13:08:38 -06:00
Trey t
3d4952e5ff feat(ui): add sport backgrounds to share cards, achievement filtering, and wizard validation
- Add ShareCardSportBackground with floating sport icons for share cards
- Share cards now show sport-specific backgrounds (single or multiple sports)
- Achievement collection share respects sport filter selection
- Add ability to share individual achievements from detail sheet
- Trip wizard ReviewStep highlights missing required fields in red
- Add FieldValidation model to TripWizardViewModel

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 12:02:57 -06:00
Trey t
1e26cfebc8 fix: standardize trip name display with arrow separators app-wide
- Add `displayName` computed property to Trip model that always
  generates city list with " → " separator for consistent display
- Replace all `trip.name` usages with `trip.displayName` in UI files
- Update SuggestedTripsGenerator to use " → " separator
- Update PDFGenerator to use displayName for PDF titles

This ensures all trip names display consistently regardless of when
the trip was created or how the name was originally stored.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 11:36:13 -06:00
Trey t
2ad458bffd refactor: TripDetailView loads games on demand, improve poll UI
- Refactor TripDetailView to fetch games from AppDataProvider when not
  provided, adding loading state indicator for better UX
- Update all callers (25+ HomeContent variants, TripOptionsView, HomeView)
  to use simpler TripDetailView(trip:) initializer
- Fix PollDetailView sheet issue by using sheet(item:) instead of
  sheet(isPresented:) to prevent blank screen on first tap
- Improve PollDetailView UI with Theme styling, icons, and better
  visual hierarchy for share code, voting status, and results sections

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 11:31:05 -06:00
Trey t
b5aea31b1a refactor: remove legacy trip creation flow, extract shared components
- Delete TripCreationView.swift and TripCreationViewModel.swift (unused)
- Extract TripOptionsView to standalone file
- Extract DateRangePicker and DayCell to standalone file
- Extract LocationSearchSheet and CityInputType to standalone file
- Fix TripWizardView to pass games dictionary to TripOptionsView
- Remove debug print statements from TripDetailView

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 11:02:39 -06:00
Trey t
d034ee8612 fix: multiple bug fixes and improvements
- Fix suggested trips showing wrong sports for cross-country trips
- Remove quick start sections from home variants (Classic, Spotify)
- Remove dead quickActions code from HomeView
- Fix pace capsule animation in TripCreationView
- Add text wrapping to achievement descriptions
- Improve poll parsing with better error handling
- Various sharing system improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 09:35:18 -06:00
Trey t
fe36f99bca feat(sharing): implement unified sharing system for social media
Replace old ProgressCardGenerator with protocol-based sharing architecture
supporting trips, achievements, and stadium progress. Features 8 color
themes, Instagram Stories optimization (1080x1920), and reusable card
components with map snapshots.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 08:54:37 -06:00
Trey t
16514a40ac Merge branch 'feature/sync-reliability' 2026-01-13 22:09:26 -06:00
Trey t
573c57aead random ish 2026-01-13 22:07:20 -06:00
Trey t
2f9546f792 feat(polls): add DeepLinkHandler and test mock helpers
- Extract deep link handling into dedicated DeepLinkHandler service
- Add MockData+Polls.swift with reusable test mocks for Trip, TripStop,
  TripPoll, PollVote, and PollResults
- Update SportsTimeApp to use DeepLinkHandler.shared
- Add error alert for deep link failures

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 22:03:22 -06:00
Trey t
136c356384 Merge branch 'feature/group-trip-polling' into group_voting
# Conflicts:
#	SportsTime/Core/Store/StoreManager.swift
2026-01-13 21:55:27 -06:00
Trey t
13385b6562 feat(polls): implement group trip polling MVP
Add complete group trip polling feature allowing users to share trips
with friends for voting using Borda count scoring.

New components:
- TripPoll and PollVote domain models with share codes and rankings
- LocalTripPoll and LocalPollVote SwiftData models for persistence
- CKTripPoll and CKPollVote CloudKit record wrappers
- PollService actor for CloudKit CRUD operations and subscriptions
- PollCreation/Detail/Voting views and view models
- Deep link handling for sportstime://poll/{code} URLs
- Debug Pro status override toggle in Settings

Integration:
- HomeView shows polls section in My Trips
- SportsTimeApp registers SwiftData models and handles deep links

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:54:42 -06:00
Trey t
e66f8056c8 fix(wizard): enable Plan My Trip button with default values
- Add debug toggle in Settings to override Pro subscription status (DEBUG builds only, defaults to true)
- Auto-validate wizard step flags on appear so button enables without explicit user interaction:
  - DatesStep: calls updateHasSetDates() on appear
  - RoutePreferenceStep: sets hasSetRoutePreference on appear
  - RepeatCitiesStep: sets hasSetRepeatCities on appear

Previously, canPlanTrip required all flags to be explicitly set by user interaction, even when valid defaults were showing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 21:49:58 -06:00
Trey t
bb332ade3c feat(paywall): enhance onboarding with rich backgrounds and intro pricing
- Add themed backgrounds for each onboarding feature page:
  - Unlimited Trips: animated route map with dotted paths and traveling car
  - Export & Share: floating documents with radiating share lines
  - Track Your Journey: stadium map with pins and achievement badges
- Add sports-themed pricing page background with random glow effects
- Display introductory offer pricing in subscription rows
- Add feature bullets to each onboarding page for better value prop
- Add crown icon header and feature pills to pricing page
- Add debug button in Settings to preview onboarding flow
- Create StoreKit configuration file for testing IAP

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:07:47 -06:00
Trey t
5686af262f feat(sync): add pagination, cancellation, and network restoration
- CloudKit pagination: fetchAllRecords() handles >400 record batches
  with cursor-based pagination (400 records per page)
- Cancellation support: SyncCancellationToken protocol enables graceful
  sync termination when background tasks expire
- Per-entity progress: SyncState now tracks timestamps per entity type
  so interrupted syncs resume where they left off
- NetworkMonitor: NWPathMonitor integration triggers sync on network
  restoration with 2.5s debounce to handle WiFi↔cellular flapping
- wasCancelled flag in SyncResult distinguishes partial from full syncs

This addresses critical data sync issues:
- CloudKit queries were limited to ~400 records but bundled data has ~5000 games
- Background tasks could be killed mid-sync without saving progress
- App had no awareness of network state changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 19:18:55 -06:00
Trey t
b99c25d8f6 feat(sync): add background task system for nightly CloudKit sync
Add BGTaskScheduler-based background sync for keeping local data fresh:

- BackgroundSyncManager: New singleton managing background tasks
  - BGAppRefreshTask for periodic CloudKit sync (system-determined frequency)
  - BGProcessingTask for overnight sync + database cleanup (2 AM)
  - Auto-archives games older than 1 year during cleanup

- Info.plist: Added BGTaskSchedulerPermittedIdentifiers
  - com.sportstime.app.refresh (periodic sync)
  - com.sportstime.app.db-cleanup (overnight processing)

- SportsTimeApp: Integrated background task lifecycle
  - Register tasks in init() (required before app finishes launching)
  - Schedule tasks after bootstrap and when app enters background

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 18:36:35 -06:00
Trey t
f180e5bfed feat(sync): add CloudKit sync for dynamic sports
- Add CKSport model to parse CloudKit Sport records
- Add fetchSportsForSync() to CloudKitService for delta fetching
- Add syncSports() and mergeSport() to CanonicalSyncService
- Update DataProvider with dynamicSports support and allSports computed property
- Update MockAppDataProvider with matching dynamic sports support
- Add comprehensive documentation for adding new sports

The app can now sync sport definitions from CloudKit, enabling new sports
to be added without app updates. Sports are fetched, merged into SwiftData,
and exposed via AppDataProvider.allSports alongside built-in Sport enum cases.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 18:27:56 -06:00
Trey t
dc278085de feat(domain): add DynamicSport model for CloudKit-defined sports
Struct representing sports synced from CloudKit. Conforms to AnySport
protocol for interchangeable use with Sport enum in UI and planning.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 16:22:02 -06:00
Trey t
e781eaa17c feat(domain): add AnySport conformance to Sport enum
Existing Sport enum now conforms to AnySport protocol, enabling
unified handling with future DynamicSport types.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 16:17:04 -06:00
Trey t
3b1add024f feat(domain): add AnySport protocol for unified sport handling
Defines protocol that both Sport enum and DynamicSport will conform to,
enabling interchangeable use in UI and planning engine.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 16:11:53 -06:00
Trey t
56869ce479 feat(ui): add 23 home screen design variants with picker
Add design style system with 23 unique home screen aesthetics:
- Classic (original SportsTime design, now default)
- 12 experimental styles (Brutalist, Luxury Editorial, etc.)
- 10 polished app-inspired styles (Flighty, SeatGeek, Apple Maps,
  Things 3, Airbnb, Spotify, Nike Run Club, Fantastical, Strava,
  Carrot Weather)

Includes settings picker to switch between styles and persists
selection via UserDefaults.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 14:44:30 -06:00
Trey t
04b62f147e fix: resolve compiler warnings across codebase
- PaywallView: remove unnecessary nil coalescing for currencyCode
- GameDAGRouter: change var to let for immutable compositeKeys
- GamesHistoryRow/View: add missing wnba and nwsl switch cases
- VisitDetailView: fix unused variable in preview
- AchievementEngine: use convenience init to avoid default parameter warning
- ProgressCardGenerator: use method overload instead of default parameter
- StadiumProximityMatcher: extract constants to ProximityConstants enum

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 13:16:40 -06:00
Trey t
22772fa57f feat(store): add In-App Purchase system with Pro subscription
Implement freemium model with StoreKit 2:
- StoreManager singleton for purchase/restore/entitlements
- ProFeature enum defining gated features
- PaywallView and OnboardingPaywallView for upsell UI
- ProGate view modifier and ProBadge component

Feature gating:
- Trip saving: 1 free trip, then requires Pro
- PDF export: Pro only with badge indicator
- Progress tab: Shows ProLockedView for free users
- Settings: Subscription management section

Also fixes pre-existing test issues with StadiumVisit
and ItineraryOption model signature changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:41:40 -06:00
Trey t
c0f1645434 feat(ui): replace loading indicators with Apple-style LoadingSpinner
- Add LoadingSpinner component with small/medium/large sizes using system gray color
- Add LoadingPlaceholder for skeleton loading states
- Add LoadingSheet for full-screen blocking overlays
- Replace ThemedSpinner/ThemedSpinnerCompact across all views
- Remove deprecated loading components from AnimatedComponents.swift
- Delete LoadingTextGenerator.swift
- Fix PhotoImportView layout to fill full width

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 22:43:33 -06:00
Trey t
ba3ea6daeb fix(sync): add foreground sync, remove manual sync button
- Add scenePhase observer to sync when app returns to foreground
- Remove misleading "Sync Schedules" button from Settings (it only
  reloaded local data, didn't actually sync from CloudKit)
- Fix GamesHistoryView to refresh list after deleting a visit

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 22:04:10 -06:00
Trey t
0524284ab8 feat: add planning tips and grouped trip options sorting
- Add PlanningTips data model with 105 tips across 7 categories
- Wire random tips into HomeView (3 tips per session)
- Add TripOptionsGrouper for grouping by city/game count and mileage
- Update TripOptionsView with sectioned display when sorting
- Recommended and Best Efficiency remain flat lists

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 21:49:04 -06:00
Trey t
89167c01d7 feat(progress): add progress tracking enhancements
- Enable zoom/pan on progress map with reset button
- Add visit count badges to stadium chips
- Create GamesHistoryView with year grouping and sport filters
- Create StadiumVisitHistoryView for viewing all visits to a stadium
- Add VisitListCard and GamesHistoryRow components
- Add "See All" navigation from Recent Visits to Games History
- Add tests for map interactions, visit lists, and games history

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 21:34:33 -06:00
Trey t
ed526cabeb refactor(wizard): show all steps at once with validation gating
- Replace progressive reveal with single fade-in of all steps
- Add canPlanTrip validation requiring all fields before planning
- Disable Plan Trip button until all selections are made
- Simplify ViewModel by removing step-by-step visibility logic
- Update tests for new validation-based approach

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 21:19:35 -06:00
Trey t
94bb68d431 fix(wizard): improve UX with step reordering and UI polish
- Reorder wizard steps: dates before sports (enables availability check)
- Add contentShape(Rectangle()) for full tap targets on all cards
- Fix route preference showing preselected value
- Fix sport cards having inconsistent heights
- Speed up step reveal animation (0.3s → 0.15s)
- Add debounced scroll delay to avoid interrupting selection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 21:13:45 -06:00
Trey t
8a958a0f7e feat: replace TripCreationView with TripWizardView in HomeView
Remove classic trip creation form and use new wizard flow directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 20:52:29 -06:00