mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 05:31:10 -05:00
Add comprehensive implementation prompts for Reviews and Rides listing pages with Django parity, Laravel/Livewire architecture, and screen-agnostic design principles
This commit is contained in:
596
memory-bank/prompts/OperatorsListingPagePrompt.md
Normal file
596
memory-bank/prompts/OperatorsListingPagePrompt.md
Normal file
@@ -0,0 +1,596 @@
|
||||
# Operators Listing Page Implementation Prompt
|
||||
|
||||
## Django Parity Reference
|
||||
**Django Implementation**: `companies/views.py` - `CompanyListView` & `ManufacturerListView` (lines 62-126)
|
||||
**Django Template**: `companies/templates/companies/company_list.html`
|
||||
**Django Features**: Dual-role filtering (park operators vs ride manufacturers), industry statistics, portfolio showcases, corporate hierarchy display, market analysis
|
||||
|
||||
## Core Implementation Requirements
|
||||
|
||||
### Laravel/Livewire Architecture
|
||||
Generate the operators listing system using ThrillWiki's custom generators:
|
||||
|
||||
```bash
|
||||
# Generate unified operators listing with dual-role support
|
||||
php artisan make:thrillwiki-livewire OperatorsListing --paginated --cached --with-tests
|
||||
|
||||
# Generate role-specific filtering component
|
||||
php artisan make:thrillwiki-livewire OperatorsRoleFilter --reusable --with-tests
|
||||
|
||||
# Generate portfolio showcase component
|
||||
php artisan make:thrillwiki-livewire OperatorPortfolioCard --reusable --with-tests
|
||||
|
||||
# Generate industry statistics dashboard
|
||||
php artisan make:thrillwiki-livewire OperatorsIndustryStats --reusable --cached
|
||||
|
||||
# Generate corporate hierarchy visualization
|
||||
php artisan make:thrillwiki-livewire OperatorHierarchyView --reusable --with-tests
|
||||
|
||||
# Generate market analysis component
|
||||
php artisan make:thrillwiki-livewire OperatorsMarketAnalysis --reusable --cached
|
||||
```
|
||||
|
||||
### Django Parity Features
|
||||
|
||||
#### 1. Dual-Role Search Functionality
|
||||
**Django Implementation**: Multi-role search across:
|
||||
- Operator name (`name__icontains`)
|
||||
- Company description (`description__icontains`)
|
||||
- Founded year range (`founded_year__range`)
|
||||
- Headquarters location (`headquarters__city__icontains`)
|
||||
- Role-specific filtering (park_operator, ride_manufacturer, or both)
|
||||
- Industry sector (`industry_sector__icontains`)
|
||||
|
||||
**Laravel Implementation**:
|
||||
```php
|
||||
public function dualRoleSearch($query, $roles = [])
|
||||
{
|
||||
return Operator::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}%")
|
||||
->orWhere('industry_sector', 'ilike', "%{$term}%")
|
||||
->orWhereHas('location', function($locQuery) use ($term) {
|
||||
$locQuery->where('city', 'ilike', "%{$term}%")
|
||||
->orWhere('state', 'ilike', "%{$term}%")
|
||||
->orWhere('country', 'ilike', "%{$term}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
->when($roles, function ($q) use ($roles) {
|
||||
$q->where(function ($roleQuery) use ($roles) {
|
||||
if (in_array('park_operator', $roles)) {
|
||||
$roleQuery->whereExists(function ($exists) {
|
||||
$exists->select(DB::raw(1))
|
||||
->from('parks')
|
||||
->whereRaw('parks.operator_id = operators.id');
|
||||
});
|
||||
}
|
||||
if (in_array('ride_manufacturer', $roles)) {
|
||||
$roleQuery->orWhereExists(function ($exists) {
|
||||
$exists->select(DB::raw(1))
|
||||
->from('rides')
|
||||
->whereRaw('rides.manufacturer_id = operators.id');
|
||||
});
|
||||
}
|
||||
if (in_array('ride_designer', $roles)) {
|
||||
$roleQuery->orWhereExists(function ($exists) {
|
||||
$exists->select(DB::raw(1))
|
||||
->from('rides')
|
||||
->whereRaw('rides.designer_id = operators.id');
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
->with(['location', 'parks', 'manufactured_rides', 'designed_rides'])
|
||||
->withCount(['parks', 'manufactured_rides', 'designed_rides']);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Advanced Industry Filtering
|
||||
**Django Filters**:
|
||||
- Role type (park_operator, manufacturer, designer, mixed)
|
||||
- Industry sector (entertainment, manufacturing, technology)
|
||||
- Company size (small, medium, large, enterprise)
|
||||
- Founded year range
|
||||
- Geographic presence (regional, national, international)
|
||||
- Market capitalization range
|
||||
- Annual revenue range
|
||||
|
||||
**Laravel Filters Implementation**:
|
||||
```php
|
||||
public function applyIndustryFilters($query, $filters)
|
||||
{
|
||||
return $query
|
||||
->when($filters['role_type'] ?? null, function ($q, $roleType) {
|
||||
switch ($roleType) {
|
||||
case 'park_operator_only':
|
||||
$q->whereHas('parks')->whereDoesntHave('manufactured_rides');
|
||||
break;
|
||||
case 'manufacturer_only':
|
||||
$q->whereHas('manufactured_rides')->whereDoesntHave('parks');
|
||||
break;
|
||||
case 'mixed':
|
||||
$q->whereHas('parks')->whereHas('manufactured_rides');
|
||||
break;
|
||||
case 'designer':
|
||||
$q->whereHas('designed_rides');
|
||||
break;
|
||||
}
|
||||
})
|
||||
->when($filters['industry_sector'] ?? null, fn($q, $sector) =>
|
||||
$q->where('industry_sector', $sector))
|
||||
->when($filters['company_size'] ?? null, function ($q, $size) {
|
||||
$ranges = [
|
||||
'small' => [1, 100],
|
||||
'medium' => [101, 1000],
|
||||
'large' => [1001, 10000],
|
||||
'enterprise' => [10001, PHP_INT_MAX]
|
||||
];
|
||||
if (isset($ranges[$size])) {
|
||||
$q->whereBetween('employee_count', $ranges[$size]);
|
||||
}
|
||||
})
|
||||
->when($filters['founded_year_from'] ?? null, fn($q, $year) =>
|
||||
$q->where('founded_year', '>=', $year))
|
||||
->when($filters['founded_year_to'] ?? null, fn($q, $year) =>
|
||||
$q->where('founded_year', '<=', $year))
|
||||
->when($filters['geographic_presence'] ?? null, function ($q, $presence) {
|
||||
switch ($presence) {
|
||||
case 'regional':
|
||||
$q->whereHas('parks', function ($parkQ) {
|
||||
$parkQ->whereHas('location', function ($locQ) {
|
||||
$locQ->havingRaw('COUNT(DISTINCT country) = 1');
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'international':
|
||||
$q->whereHas('parks', function ($parkQ) {
|
||||
$parkQ->whereHas('location', function ($locQ) {
|
||||
$locQ->havingRaw('COUNT(DISTINCT country) > 1');
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
})
|
||||
->when($filters['min_revenue'] ?? null, fn($q, $revenue) =>
|
||||
$q->where('annual_revenue', '>=', $revenue))
|
||||
->when($filters['max_revenue'] ?? null, fn($q, $revenue) =>
|
||||
$q->where('annual_revenue', '<=', $revenue));
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Portfolio and Statistics Display
|
||||
**Portfolio Metrics**:
|
||||
- Total parks operated
|
||||
- Total rides manufactured/designed
|
||||
- Geographic reach (countries, continents)
|
||||
- Market share analysis
|
||||
- Revenue and financial metrics
|
||||
- Industry influence score
|
||||
|
||||
### Screen-Agnostic Design Implementation
|
||||
|
||||
#### Mobile Layout (320px - 767px)
|
||||
- **Corporate Cards**: Compact operator cards with key metrics
|
||||
- **Role Badges**: Visual indicators for operator/manufacturer/designer roles
|
||||
- **Portfolio Highlights**: Key statistics prominently displayed
|
||||
- **Industry Filters**: Simplified filtering for mobile users
|
||||
|
||||
**Mobile Component Structure**:
|
||||
```blade
|
||||
<div class="operators-mobile-layout">
|
||||
<!-- Industry Search Bar -->
|
||||
<div class="sticky top-0 bg-white dark:bg-gray-900 z-20 p-4">
|
||||
<livewire:operators-industry-search />
|
||||
<div class="flex items-center mt-2 space-x-2">
|
||||
<button wire:click="filterByRole('park_operator')"
|
||||
class="flex items-center space-x-1 px-3 py-1 {{ $activeRole === 'park_operator' ? 'bg-blue-500 text-white' : 'bg-blue-100 dark:bg-blue-900' }} rounded-full">
|
||||
<span class="text-sm">Operators</span>
|
||||
</button>
|
||||
<button wire:click="filterByRole('manufacturer')"
|
||||
class="flex items-center space-x-1 px-3 py-1 {{ $activeRole === 'manufacturer' ? 'bg-green-500 text-white' : 'bg-green-100 dark:bg-green-900' }} rounded-full">
|
||||
<span class="text-sm">Manufacturers</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Industry Statistics Banner -->
|
||||
<div class="bg-gradient-to-r from-blue-500 to-purple-600 text-white p-4 m-4 rounded-lg">
|
||||
<livewire:operators-industry-stats :compact="true" />
|
||||
</div>
|
||||
|
||||
<!-- Quick Filters -->
|
||||
<div class="horizontal-scroll p-4 pb-2">
|
||||
<livewire:operators-quick-filters />
|
||||
</div>
|
||||
|
||||
<!-- Operator Cards -->
|
||||
<div class="space-y-4 p-4">
|
||||
@foreach($operators as $operator)
|
||||
<livewire:operator-mobile-card :operator="$operator" :show-portfolio="true" :key="$operator->id" />
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<!-- Mobile Pagination -->
|
||||
<div class="sticky bottom-0 bg-white dark:bg-gray-900 p-4">
|
||||
{{ $operators->links('pagination.mobile') }}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Tablet Layout (768px - 1023px)
|
||||
- **Dual-Pane Layout**: Filter sidebar + operator grid
|
||||
- **Portfolio Showcases**: Detailed portfolio cards for each operator
|
||||
- **Industry Dashboard**: Real-time industry statistics and trends
|
||||
- **Comparison Mode**: Side-by-side operator comparisons
|
||||
|
||||
**Tablet Component Structure**:
|
||||
```blade
|
||||
<div class="operators-tablet-layout flex h-screen">
|
||||
<!-- Industry Filter Sidebar -->
|
||||
<div class="w-80 bg-gray-50 dark:bg-gray-800 overflow-y-auto">
|
||||
<div class="p-6">
|
||||
<livewire:operators-industry-search :advanced="true" />
|
||||
<div class="mt-6">
|
||||
<livewire:operators-role-filter :expanded="true" />
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<livewire:operators-industry-filters :show-financial="true" />
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<livewire:operators-industry-stats :detailed="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<div class="flex-1 flex flex-col">
|
||||
<!-- Industry Header -->
|
||||
<div class="bg-white dark:bg-gray-900 p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center space-x-4">
|
||||
<h2 class="text-xl font-semibold">{{ $operators->total() }} Industry Leaders</h2>
|
||||
<livewire:operators-market-overview />
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<livewire:operators-sort-selector />
|
||||
<livewire:operators-view-toggle />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Grid -->
|
||||
<div class="flex-1 overflow-y-auto p-6">
|
||||
@if($view === 'grid')
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
@foreach($operators as $operator)
|
||||
<livewire:operator-tablet-card :operator="$operator" :detailed="true" :key="$operator->id" />
|
||||
@endforeach
|
||||
</div>
|
||||
@elseif($view === 'portfolio')
|
||||
<div class="space-y-6">
|
||||
@foreach($operators as $operator)
|
||||
<livewire:operator-portfolio-showcase :operator="$operator" :key="$operator->id" />
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<livewire:operators-market-analysis :operators="$operators" />
|
||||
@endif
|
||||
|
||||
<div class="mt-6">
|
||||
{{ $operators->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Desktop Layout (1024px - 1919px)
|
||||
- **Three-Pane Layout**: Filters + main content + industry insights
|
||||
- **Advanced Analytics**: Market share analysis and industry trends
|
||||
- **Corporate Hierarchies**: Visual representation of corporate structures
|
||||
- **Portfolio Deep Dives**: Comprehensive portfolio analysis
|
||||
|
||||
**Desktop Component Structure**:
|
||||
```blade
|
||||
<div class="operators-desktop-layout flex h-screen">
|
||||
<!-- Advanced Filter Sidebar -->
|
||||
<div class="w-80 bg-gray-50 dark:bg-gray-800 overflow-y-auto">
|
||||
<div class="p-6">
|
||||
<livewire:operators-industry-search :advanced="true" :autocomplete="true" />
|
||||
<div class="mt-6">
|
||||
<livewire:operators-role-filter :advanced="true" :show-statistics="true" />
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<livewire:operators-industry-filters :advanced="true" :show-financial="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="flex-1 flex flex-col">
|
||||
<!-- Industry Dashboard Header -->
|
||||
<div class="bg-white dark:bg-gray-900 p-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-6">
|
||||
<h1 class="text-2xl font-bold">{{ $operators->total() }} Industry Operators</h1>
|
||||
<livewire:operators-market-summary />
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<livewire:operators-sort-selector :advanced="true" />
|
||||
<livewire:operators-view-selector />
|
||||
<livewire:operators-export-options />
|
||||
</div>
|
||||
</div>
|
||||
<livewire:operators-advanced-search />
|
||||
</div>
|
||||
|
||||
<!-- Content Area -->
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
@if($view === 'grid')
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
@foreach($operators as $operator)
|
||||
<livewire:operator-desktop-card :operator="$operator" :comprehensive="true" :key="$operator->id" />
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="mt-8">
|
||||
{{ $operators->links('pagination.desktop') }}
|
||||
</div>
|
||||
</div>
|
||||
@elseif($view === 'portfolio')
|
||||
<div class="p-6 space-y-8">
|
||||
@foreach($operators as $operator)
|
||||
<livewire:operator-portfolio-detailed :operator="$operator" :key="$operator->id" />
|
||||
@endforeach
|
||||
</div>
|
||||
@elseif($view === 'hierarchy')
|
||||
<div class="p-6">
|
||||
<livewire:operators-hierarchy-visualization :operators="$operators" />
|
||||
</div>
|
||||
@else
|
||||
<div class="p-6">
|
||||
<livewire:operators-market-dashboard :operators="$operators" />
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Industry Insights Panel -->
|
||||
<div class="w-80 bg-gray-50 dark:bg-gray-800 overflow-y-auto">
|
||||
<div class="p-6">
|
||||
<livewire:operators-industry-insights />
|
||||
<div class="mt-6">
|
||||
<livewire:operators-market-trends />
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<livewire:operators-recent-activity />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Large Screen Layout (1920px+)
|
||||
- **Dashboard-Style Interface**: Comprehensive industry analytics
|
||||
- **Multi-Panel Views**: Simultaneous portfolio and market analysis
|
||||
- **Advanced Visualizations**: Corporate network maps and market dynamics
|
||||
- **Real-Time Market Data**: Live industry statistics and trends
|
||||
|
||||
### Performance Optimization Strategy
|
||||
|
||||
#### Industry-Specific Caching
|
||||
```php
|
||||
public function mount()
|
||||
{
|
||||
$this->industryStats = Cache::remember(
|
||||
'operators.industry.stats',
|
||||
now()->addHours(6),
|
||||
fn() => $this->calculateIndustryStatistics()
|
||||
);
|
||||
|
||||
$this->marketData = Cache::remember(
|
||||
'operators.market.data',
|
||||
now()->addHours(12),
|
||||
fn() => $this->loadMarketAnalysis()
|
||||
);
|
||||
}
|
||||
|
||||
public function getOperatorsProperty()
|
||||
{
|
||||
$cacheKey = "operators.listing." . md5(serialize([
|
||||
'search' => $this->search,
|
||||
'filters' => $this->filters,
|
||||
'role_filter' => $this->roleFilter,
|
||||
'sort' => $this->sort,
|
||||
'page' => $this->page
|
||||
]));
|
||||
|
||||
return Cache::remember($cacheKey, now()->addMinutes(30), function() {
|
||||
return $this->dualRoleSearch($this->search, $this->roleFilter)
|
||||
->applyIndustryFilters($this->filters)
|
||||
->orderBy($this->sort['column'], $this->sort['direction'])
|
||||
->paginate(20);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### Financial Data Optimization
|
||||
```php
|
||||
// Optimized query for financial and portfolio data
|
||||
public function optimizedFinancialQuery()
|
||||
{
|
||||
return Operator::select([
|
||||
'operators.*',
|
||||
DB::raw('COALESCE(parks_count.count, 0) as parks_count'),
|
||||
DB::raw('COALESCE(rides_count.count, 0) as manufactured_rides_count'),
|
||||
DB::raw('COALESCE(designed_rides_count.count, 0) as designed_rides_count'),
|
||||
DB::raw('CASE
|
||||
WHEN annual_revenue > 10000000000 THEN "enterprise"
|
||||
WHEN annual_revenue > 1000000000 THEN "large"
|
||||
WHEN annual_revenue > 100000000 THEN "medium"
|
||||
ELSE "small"
|
||||
END as company_size_category')
|
||||
])
|
||||
->leftJoin(DB::raw('(SELECT operator_id, COUNT(*) as count FROM parks GROUP BY operator_id) as parks_count'),
|
||||
'operators.id', '=', 'parks_count.operator_id')
|
||||
->leftJoin(DB::raw('(SELECT manufacturer_id, COUNT(*) as count FROM rides GROUP BY manufacturer_id) as rides_count'),
|
||||
'operators.id', '=', 'rides_count.manufacturer_id')
|
||||
->leftJoin(DB::raw('(SELECT designer_id, COUNT(*) as count FROM rides GROUP BY designer_id) as designed_rides_count'),
|
||||
'operators.id', '=', 'designed_rides_count.designer_id')
|
||||
->with([
|
||||
'location:id,city,state,country',
|
||||
'parks:id,operator_id,name,opening_date',
|
||||
'manufactured_rides:id,manufacturer_id,name,ride_type',
|
||||
'designed_rides:id,designer_id,name,ride_type'
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
### Component Reuse Strategy
|
||||
|
||||
#### Shared Components
|
||||
- **`OperatorsRoleFilter`**: Multi-role filtering with statistics
|
||||
- **`OperatorPortfolioCard`**: Comprehensive portfolio display
|
||||
- **`OperatorsIndustryStats`**: Real-time industry analytics
|
||||
- **`OperatorFinancialMetrics`**: Financial performance indicators
|
||||
|
||||
#### Context Variations
|
||||
- **`ParkOperatorsListing`**: Park operators only with park portfolios
|
||||
- **`ManufacturersListing`**: Ride manufacturers with product catalogs
|
||||
- **`DesignersListing`**: Ride designers with design portfolios
|
||||
- **`CorporateGroupsListing`**: Corporate hierarchies and subsidiaries
|
||||
|
||||
### Testing Requirements
|
||||
|
||||
#### Feature Tests
|
||||
```php
|
||||
/** @test */
|
||||
public function can_filter_operators_by_dual_roles()
|
||||
{
|
||||
$pureOperator = Operator::factory()->create(['name' => 'Disney Parks']);
|
||||
$pureOperator->parks()->create(['name' => 'Magic Kingdom']);
|
||||
|
||||
$pureManufacturer = Operator::factory()->create(['name' => 'Intamin']);
|
||||
$pureManufacturer->manufactured_rides()->create(['name' => 'Millennium Force']);
|
||||
|
||||
$mixedOperator = Operator::factory()->create(['name' => 'Universal']);
|
||||
$mixedOperator->parks()->create(['name' => 'Universal Studios']);
|
||||
$mixedOperator->manufactured_rides()->create(['name' => 'Custom Ride']);
|
||||
|
||||
Livewire::test(OperatorsListing::class)
|
||||
->set('roleFilter', ['park_operator'])
|
||||
->assertSee($pureOperator->name)
|
||||
->assertSee($mixedOperator->name)
|
||||
->assertDontSee($pureManufacturer->name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function calculates_industry_statistics_correctly()
|
||||
{
|
||||
Operator::factory()->count(10)->create(['industry_sector' => 'entertainment']);
|
||||
Operator::factory()->count(5)->create(['industry_sector' => 'manufacturing']);
|
||||
|
||||
$component = Livewire::test(OperatorsListing::class);
|
||||
$stats = $component->get('industryStats');
|
||||
|
||||
$this->assertEquals(15, $stats['total_operators']);
|
||||
$this->assertEquals(10, $stats['entertainment_operators']);
|
||||
$this->assertEquals(5, $stats['manufacturing_operators']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function maintains_django_parity_performance_with_portfolio_data()
|
||||
{
|
||||
Operator::factory()->count(50)->create();
|
||||
|
||||
$start = microtime(true);
|
||||
Livewire::test(OperatorsListing::class);
|
||||
$end = microtime(true);
|
||||
|
||||
$this->assertLessThan(0.5, $end - $start); // < 500ms with portfolio data
|
||||
}
|
||||
```
|
||||
|
||||
#### Financial Data Tests
|
||||
```php
|
||||
/** @test */
|
||||
public function categorizes_company_size_correctly()
|
||||
{
|
||||
$enterprise = Operator::factory()->create(['annual_revenue' => 15000000000]);
|
||||
$large = Operator::factory()->create(['annual_revenue' => 5000000000]);
|
||||
$medium = Operator::factory()->create(['annual_revenue' => 500000000]);
|
||||
$small = Operator::factory()->create(['annual_revenue' => 50000000]);
|
||||
|
||||
Livewire::test(OperatorsListing::class)
|
||||
->set('filters.company_size', 'enterprise')
|
||||
->assertSee($enterprise->name)
|
||||
->assertDontSee($large->name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function handles_portfolio_metrics_calculation()
|
||||
{
|
||||
$operator = Operator::factory()->create();
|
||||
$operator->parks()->createMany(3, ['name' => 'Test Park']);
|
||||
$operator->manufactured_rides()->createMany(5, ['name' => 'Test Ride']);
|
||||
|
||||
$component = Livewire::test(OperatorsListing::class);
|
||||
$portfolioData = $component->get('operators')->first();
|
||||
|
||||
$this->assertEquals(3, $portfolioData->parks_count);
|
||||
$this->assertEquals(5, $portfolioData->manufactured_rides_count);
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Targets
|
||||
|
||||
#### Universal Performance Standards with Financial Data
|
||||
- **Initial Load**: < 500ms (including industry statistics)
|
||||
- **Portfolio Calculation**: < 200ms for 100 operators
|
||||
- **Financial Filtering**: < 150ms with complex criteria
|
||||
- **Market Analysis**: < 1 second for trend calculations
|
||||
- **Industry Statistics**: < 100ms (cached)
|
||||
|
||||
#### Industry-Specific Caching Strategy
|
||||
- **Market Data Cache**: 12 hours (financial markets change)
|
||||
- **Industry Statistics**: 6 hours (relatively stable)
|
||||
- **Portfolio Metrics**: 1 hour (operational data)
|
||||
- **Company Profiles**: 24 hours (corporate data stable)
|
||||
|
||||
### Success Criteria Checklist
|
||||
|
||||
#### Django Parity Verification
|
||||
- [ ] Dual-role filtering matches Django behavior exactly
|
||||
- [ ] Industry statistics calculated identically to Django
|
||||
- [ ] Portfolio metrics match Django calculations
|
||||
- [ ] Financial filtering provides same results as Django
|
||||
- [ ] Corporate hierarchy display matches Django structure
|
||||
|
||||
#### Screen-Agnostic Compliance
|
||||
- [ ] Mobile layout optimized for corporate data consumption
|
||||
- [ ] Tablet layout provides effective portfolio comparisons
|
||||
- [ ] Desktop layout maximizes industry analytics
|
||||
- [ ] Large screen layout provides comprehensive market view
|
||||
- [ ] All layouts handle complex financial data gracefully
|
||||
|
||||
#### Performance Benchmarks
|
||||
- [ ] Initial load under 500ms including portfolio data
|
||||
- [ ] Financial calculations under 200ms
|
||||
- [ ] Industry statistics under 100ms (cached)
|
||||
- [ ] Market analysis under 1 second
|
||||
- [ ] Portfolio caching reduces server load by 60%
|
||||
|
||||
#### Industry Feature Completeness
|
||||
- [ ] Dual-role filtering works across all operator types
|
||||
- [ ] Financial metrics display accurately
|
||||
- [ ] Portfolio showcases provide comprehensive overviews
|
||||
- [ ] Market analysis provides meaningful insights
|
||||
- [ ] Corporate hierarchies visualize relationships correctly
|
||||
|
||||
This prompt ensures complete Django parity while providing comprehensive industry analysis capabilities that leverage modern data visualization and maintain ThrillWiki's screen-agnostic design principles.
|
||||
Reference in New Issue
Block a user