# Rides Listing Page Implementation Prompt ## Django Parity Reference **Django Implementation**: `rides/views.py` - `RideListView` (lines 215-278) **Django Template**: `rides/templates/rides/ride_list.html` **Django Features**: Multi-term search, category filtering, manufacturer filtering, status filtering, pagination with HTMX, eager loading optimization ## Core Implementation Requirements ### Laravel/Livewire Architecture Generate the rides listing system using ThrillWiki's custom generators: ```bash # Generate the main listing component with optimizations php artisan make:thrillwiki-livewire RidesListing --paginated --cached --with-tests # Generate reusable search suggestions component php artisan make:thrillwiki-livewire RidesSearchSuggestions --reusable --with-tests # Generate advanced filters component php artisan make:thrillwiki-livewire RidesFilters --reusable --cached # Generate context-aware listing for park-specific rides php artisan make:thrillwiki-livewire ParkRidesListing --paginated --cached --with-tests ``` ### Django Parity Features #### 1. Search Functionality **Django Implementation**: Multi-term search across: - Ride name (`name__icontains`) - Ride description (`description__icontains`) - Park name (`park__name__icontains`) - Manufacturer name (`manufacturer__name__icontains`) - Designer name (`designer__name__icontains`) **Laravel Implementation**: ```php public function search($query) { return Ride::query() ->when($query, function ($q) use ($query) { $terms = explode(' ', $query); foreach ($terms as $term) { $q->where(function ($subQuery) use ($term) { $subQuery->where('name', 'ilike', "%{$term}%") ->orWhere('description', 'ilike', "%{$term}%") ->orWhereHas('park', fn($q) => $q->where('name', 'ilike', "%{$term}%")) ->orWhereHas('manufacturer', fn($q) => $q->where('name', 'ilike', "%{$term}%")) ->orWhereHas('designer', fn($q) => $q->where('name', 'ilike', "%{$term}%")); }); } }) ->with(['park', 'manufacturer', 'designer', 'photos']) ->orderBy('name'); } ``` #### 2. Advanced Filtering **Django Filters**: - Category (ride_type) - Status (status) - Manufacturer (manufacturer__id) - Opening year range - Height restrictions - Park context (when viewing park-specific rides) **Laravel Filters Implementation**: ```php public function applyFilters($query, $filters) { return $query ->when($filters['category'] ?? null, fn($q, $category) => $q->where('ride_type', $category)) ->when($filters['status'] ?? null, fn($q, $status) => $q->where('status', $status)) ->when($filters['manufacturer_id'] ?? null, fn($q, $manufacturerId) => $q->where('manufacturer_id', $manufacturerId)) ->when($filters['opening_year_from'] ?? null, fn($q, $year) => $q->where('opening_date', '>=', "{$year}-01-01")) ->when($filters['opening_year_to'] ?? null, fn($q, $year) => $q->where('opening_date', '<=', "{$year}-12-31")) ->when($filters['min_height'] ?? null, fn($q, $height) => $q->where('height_requirement', '>=', $height)) ->when($filters['max_height'] ?? null, fn($q, $height) => $q->where('height_requirement', '<=', $height)); } ``` #### 3. Context-Aware Views **Global Listing**: All rides across all parks **Park-Specific Listing**: Rides filtered by specific park **Category-Specific Listing**: Rides filtered by ride type/category ### Screen-Agnostic Design Implementation #### Mobile Layout (320px - 767px) - **Single Column**: Full-width ride cards - **Touch Targets**: Minimum 44px touch areas - **Gesture Support**: Pull-to-refresh, swipe navigation - **Bottom Navigation**: Sticky filters and search - **Thumb Navigation**: Search and filter controls within thumb reach **Mobile Component Structure**: ```blade
@foreach($rides as $ride) @endforeach
{{ $rides->links('pagination.mobile') }}
``` #### Tablet Layout (768px - 1023px) - **Dual-Pane**: Filter sidebar + main content - **Grid Layout**: 2-column ride cards - **Advanced Filters**: Expandable filter panels - **Touch + Keyboard**: Support both interaction modes **Tablet Component Structure**: ```blade
@foreach($rides as $ride) @endforeach
{{ $rides->links() }}
``` #### Desktop Layout (1024px - 1919px) - **Three-Pane**: Filter sidebar + main content + quick info panel - **Advanced Grid**: 3-4 column layout - **Keyboard Navigation**: Full keyboard shortcuts - **Mouse Interactions**: Hover effects, context menus **Desktop Component Structure**: ```blade
@foreach($rides as $ride) @endforeach
{{ $rides->links('pagination.desktop') }}
``` #### Large Screen Layout (1920px+) - **Dashboard Style**: Multi-column layout with statistics - **Ultra-Wide Optimization**: Up to 6-column grid - **Advanced Analytics**: Statistics panels and data visualization - **Multi-Monitor Support**: Optimized for extended displays ### Performance Optimization Strategy #### Caching Implementation ```php public function mount() { $this->cachedFilters = Cache::remember( "rides.filters.{$this->currentUser->id}", now()->addHours(1), fn() => $this->loadFilterOptions() ); } public function getRidesProperty() { $cacheKey = "rides.listing." . md5(serialize([ 'search' => $this->search, 'filters' => $this->filters, 'sort' => $this->sort, 'page' => $this->page ])); return Cache::remember($cacheKey, now()->addMinutes(15), function() { return $this->search($this->search) ->applyFilters($this->filters) ->orderBy($this->sort['column'], $this->sort['direction']) ->paginate(24); }); } ``` #### Database Optimization ```php // Query optimization with eager loading public function optimizedQuery() { return Ride::select([ 'id', 'name', 'description', 'ride_type', 'status', 'park_id', 'manufacturer_id', 'designer_id', 'opening_date', 'height_requirement', 'created_at', 'updated_at' ]) ->with([ 'park:id,name,slug', 'manufacturer:id,name,slug', 'designer:id,name,slug', 'photos' => fn($q) => $q->select(['id', 'ride_id', 'url', 'thumbnail_url'])->limit(1) ]) ->withCount(['reviews', 'favorites']); } ``` ### Component Reuse Strategy #### Shared Components - **`RidesSearchSuggestions`**: Reusable across all ride-related pages - **`RidesFilters`**: Extensible filter component with device-aware UI - **`RideCard`**: Responsive ride display component - **`RideQuickView`**: Modal/sidebar quick view component #### Context Variations - **`GlobalRidesListing`**: All rides across all parks - **`ParkRidesListing`**: Park-specific rides (extends base listing) - **`CategoryRidesListing`**: Category-specific rides (extends base listing) - **`UserFavoriteRides`**: User's favorite rides (extends base listing) ### Testing Requirements #### Feature Tests ```php /** @test */ public function can_search_rides_across_multiple_fields() { // Test multi-term search across name, description, park, manufacturer $ride = Ride::factory()->create(['name' => 'Space Mountain']); $park = $ride->park; $park->update(['name' => 'Magic Kingdom']); Livewire::test(RidesListing::class) ->set('search', 'Space Magic') ->assertSee($ride->name) ->assertSee($park->name); } /** @test */ public function filters_rides_by_multiple_criteria() { $coaster = Ride::factory()->create(['ride_type' => 'roller-coaster']); $kiddie = Ride::factory()->create(['ride_type' => 'kiddie']); Livewire::test(RidesListing::class) ->set('filters.category', 'roller-coaster') ->assertSee($coaster->name) ->assertDontSee($kiddie->name); } /** @test */ public function maintains_django_parity_performance() { Ride::factory()->count(100)->create(); $start = microtime(true); Livewire::test(RidesListing::class); $end = microtime(true); $this->assertLessThan(0.5, $end - $start); // < 500ms initial load } ``` #### Cross-Device Tests ```php /** @test */ public function renders_appropriately_on_mobile() { $this->browse(function (Browser $browser) { $browser->resize(375, 667) // iPhone dimensions ->visit('/rides') ->assertVisible('.rides-mobile-layout') ->assertMissing('.rides-desktop-layout'); }); } /** @test */ public function supports_touch_gestures_on_tablet() { $this->browse(function (Browser $browser) { $browser->resize(768, 1024) // iPad dimensions ->visit('/rides') ->assertVisible('.rides-tablet-layout') ->swipeLeft('.horizontal-scroll') ->assertMissing('.rides-mobile-layout'); }); } ``` ### Performance Targets #### Universal Performance Standards - **Initial Load**: < 500ms (Django parity requirement) - **Filter Response**: < 200ms - **Search Response**: < 300ms - **3G Network**: < 3 seconds total page load - **First Contentful Paint**: < 1.5 seconds across all devices #### Device-Specific Targets - **Mobile (3G)**: Core functionality in < 3 seconds - **Tablet (WiFi)**: Full functionality in < 2 seconds - **Desktop (Broadband)**: Advanced features in < 1 second - **Large Screen**: Dashboard mode in < 1.5 seconds ### Success Criteria Checklist #### Django Parity Verification - [ ] Multi-term search matches Django behavior exactly - [ ] All Django filters implemented and functional - [ ] Pagination performance matches or exceeds Django - [ ] Eager loading prevents N+1 queries like Django - [ ] Context-aware views work identically to Django #### Screen-Agnostic Compliance - [ ] Mobile layout optimized for 320px+ screens - [ ] Tablet layout utilizes dual-pane effectively - [ ] Desktop layout provides advanced functionality - [ ] Large screen layout maximizes available space - [ ] All touch targets meet 44px minimum requirement - [ ] Keyboard navigation works on all layouts #### Performance Benchmarks - [ ] Initial load under 500ms (matches Django target) - [ ] Filter/search responses under 200ms - [ ] 3G network performance under 3 seconds - [ ] Memory usage optimized with proper caching - [ ] Database queries optimized with eager loading #### Component Reusability - [ ] Search component reusable across ride-related pages - [ ] Filter component extensible for different contexts - [ ] Card components work across all screen sizes - [ ] Modal/sidebar quick view components functional #### Testing Coverage - [ ] All Django functionality covered by feature tests - [ ] Performance tests validate speed requirements - [ ] Cross-device browser tests pass - [ ] Component integration tests complete - [ ] User interaction tests cover all form factors ## Implementation Priority Order 1. **Generate Base Components** (Day 1) - Use ThrillWiki generators for rapid scaffolding - Implement core search and filter functionality - Set up responsive layouts 2. **Django Parity Implementation** (Day 2) - Implement exact search behavior - Add all Django filter options - Optimize database queries 3. **Screen-Agnostic Optimization** (Day 3) - Fine-tune responsive layouts - Implement device-specific features - Add touch and keyboard interactions 4. **Performance Optimization** (Day 4) - Implement caching strategies - Optimize database queries - Add lazy loading where appropriate 5. **Testing and Validation** (Day 5) - Complete test suite implementation - Validate Django parity - Verify performance targets This prompt ensures complete Django parity while leveraging Laravel/Livewire advantages and maintaining ThrillWiki's screen-agnostic design principles.