# 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.