Files
thrillwiki_laravel/resources/views/livewire/operators-listing-universal.blade.php
pacnpal 97a7682eb7 Add Livewire components for parks, rides, and manufacturers
- Implemented ParksLocationSearch component with loading state and refresh functionality.
- Created ParksMapView component with similar structure and functionality.
- Added RegionalParksListing component for displaying regional parks.
- Developed RidesListingUniversal component for universal listing integration.
- Established ManufacturersListing view with navigation and Livewire integration.
- Added feature tests for various Livewire components including OperatorHierarchyView, OperatorParksListing, OperatorPortfolioCard, OperatorsListing, OperatorsRoleFilter, ParksListing, ParksLocationSearch, ParksMapView, and RegionalParksListing to ensure proper rendering and adherence to patterns.
2025-06-23 21:31:05 -04:00

419 lines
23 KiB
PHP

<div>
{{-- Universal Listing System Integration --}}
<x-universal-listing
:entity-type="$entityType"
:items="$operators"
:search="$search"
:sort-by="$sortBy"
:sort-direction="$sortDirection"
:view-mode="$viewMode"
:per-page="$perPage"
>
{{-- Custom Industry Statistics Header --}}
<x-slot name="header">
<div class="bg-gradient-to-r from-blue-500 to-purple-600 text-white p-6 rounded-lg mb-6">
<div class="text-center">
<h2 class="text-2xl font-bold mb-4">Industry Overview</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
<div class="text-center">
<div class="text-3xl font-bold">{{ $industryStats['total_operators'] ?? 0 }}</div>
<div class="text-sm opacity-90">Total Operators</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold">{{ $industryStats['park_operators'] ?? 0 }}</div>
<div class="text-sm opacity-90">Park Operators</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold">{{ $industryStats['manufacturers'] ?? 0 }}</div>
<div class="text-sm opacity-90">Manufacturers</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold">{{ $industryStats['mixed_role'] ?? 0 }}</div>
<div class="text-sm opacity-90">Multi-Role</div>
</div>
</div>
</div>
</div>
</x-slot>
{{-- Custom Search Placeholder --}}
<x-slot name="search-placeholder">
Search operators, manufacturers, designers...
</x-slot>
{{-- Custom Filters Sidebar --}}
<x-slot name="filters">
{{-- Role Filters --}}
<div class="mb-6">
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">Operator Roles</h3>
<div class="space-y-2">
<label class="flex items-center">
<input
type="checkbox"
wire:model.live="roleFilter"
value="park_operator"
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
>
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">
Park Operators ({{ $industryStats['park_operators'] ?? 0 }})
</span>
</label>
<label class="flex items-center">
<input
type="checkbox"
wire:model.live="roleFilter"
value="ride_manufacturer"
class="rounded border-gray-300 text-green-600 focus:ring-green-500"
>
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">
Manufacturers ({{ $industryStats['manufacturers'] ?? 0 }})
</span>
</label>
<label class="flex items-center">
<input
type="checkbox"
wire:model.live="roleFilter"
value="ride_designer"
class="rounded border-gray-300 text-purple-600 focus:ring-purple-500"
>
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">
Designers ({{ $industryStats['designers'] ?? 0 }})
</span>
</label>
</div>
</div>
{{-- Industry Filters --}}
<div class="mb-6">
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">Industry Filters</h3>
<div class="space-y-4">
{{-- Company Size --}}
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Company Size</label>
<select wire:model.live="companySize" class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
<option value="">All Sizes</option>
<option value="small">Small (1-100)</option>
<option value="medium">Medium (101-1000)</option>
<option value="large">Large (1001-10000)</option>
<option value="enterprise">Enterprise (10000+)</option>
</select>
</div>
{{-- Industry Sector --}}
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Industry Sector</label>
<select wire:model.live="industrySector" class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
<option value="">All Sectors</option>
@if(isset($industryStats['sectors']))
@foreach($industryStats['sectors'] as $sector => $count)
<option value="{{ $sector }}">{{ ucfirst($sector) }} ({{ $count }})</option>
@endforeach
@endif
</select>
</div>
{{-- Founded Year Range --}}
<div class="grid grid-cols-2 gap-2">
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">From Year</label>
<input
type="number"
wire:model.live="foundedYearFrom"
placeholder="1900"
class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
>
</div>
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">To Year</label>
<input
type="number"
wire:model.live="foundedYearTo"
placeholder="{{ date('Y') }}"
class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
>
</div>
</div>
{{-- Geographic Presence --}}
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Geographic Presence</label>
<select wire:model.live="geographicPresence" class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
<option value="">All Levels</option>
<option value="regional">Regional</option>
<option value="international">International</option>
</select>
</div>
{{-- Revenue Range --}}
<div class="grid grid-cols-2 gap-2">
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Min Revenue</label>
<input
type="number"
wire:model.live="minRevenue"
placeholder="0"
class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
>
</div>
<div>
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Max Revenue</label>
<input
type="number"
wire:model.live="maxRevenue"
placeholder=""
class="w-full text-sm border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
>
</div>
</div>
</div>
</div>
{{-- Industry Statistics Panel --}}
<div class="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4">
<h3 class="text-sm font-medium text-blue-900 dark:text-blue-100 mb-3">Industry Stats</h3>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span class="text-blue-700 dark:text-blue-300">Total Operators</span>
<span class="font-medium text-blue-900 dark:text-blue-100">{{ $industryStats['total_operators'] ?? 0 }}</span>
</div>
<div class="flex justify-between">
<span class="text-blue-700 dark:text-blue-300">Multi-Role</span>
<span class="font-medium text-blue-900 dark:text-blue-100">{{ $industryStats['mixed_role'] ?? 0 }}</span>
</div>
@if(isset($marketData['total_market_cap']))
<div class="flex justify-between">
<span class="text-blue-700 dark:text-blue-300">Market Cap</span>
<span class="font-medium text-blue-900 dark:text-blue-100">${{ number_format($marketData['total_market_cap'] / 1000000000, 1) }}B</span>
</div>
@endif
</div>
</div>
</x-slot>
{{-- Custom Mobile Role Filter Buttons --}}
<x-slot name="mobile-filters">
<div class="flex flex-wrap gap-2 mb-4">
<button
wire:click="toggleRoleFilter('park_operator')"
class="px-3 py-1.5 text-sm rounded-full border transition-colors {{ in_array('park_operator', $roleFilter) ? 'bg-blue-500 text-white border-blue-500' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600' }}"
>
Operators
@if(isset($industryStats['park_operators']))
<span class="ml-1 text-xs opacity-75">({{ $industryStats['park_operators'] }})</span>
@endif
</button>
<button
wire:click="toggleRoleFilter('ride_manufacturer')"
class="px-3 py-1.5 text-sm rounded-full border transition-colors {{ in_array('ride_manufacturer', $roleFilter) ? 'bg-green-500 text-white border-green-500' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600' }}"
>
Manufacturers
@if(isset($industryStats['manufacturers']))
<span class="ml-1 text-xs opacity-75">({{ $industryStats['manufacturers'] }})</span>
@endif
</button>
<button
wire:click="toggleRoleFilter('ride_designer')"
class="px-3 py-1.5 text-sm rounded-full border transition-colors {{ in_array('ride_designer', $roleFilter) ? 'bg-purple-500 text-white border-purple-500' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600' }}"
>
Designers
@if(isset($industryStats['designers']))
<span class="ml-1 text-xs opacity-75">({{ $industryStats['designers'] }})</span>
@endif
</button>
</div>
</x-slot>
{{-- Custom Sort Options --}}
<x-slot name="sort-options">
<option value="name">Name</option>
<option value="founded_year">Founded Year</option>
<option value="parks_count">Parks Count</option>
<option value="rides_count">Rides Count</option>
<option value="revenue">Revenue</option>
<option value="market_influence">Market Influence</option>
</x-slot>
{{-- Custom View Mode Options --}}
<x-slot name="view-modes">
<button
wire:click="setViewMode('grid')"
class="px-3 py-1 text-sm {{ $viewMode === 'grid' ? 'bg-blue-500 text-white' : 'bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300' }} rounded-l-md border border-gray-300 dark:border-gray-600"
>
Grid
</button>
<button
wire:click="setViewMode('portfolio')"
class="px-3 py-1 text-sm {{ $viewMode === 'portfolio' ? 'bg-blue-500 text-white' : 'bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300' }} rounded-r-md border-t border-r border-b border-gray-300 dark:border-gray-600"
>
Portfolio
</button>
</x-slot>
{{-- Custom Card Content for Grid View --}}
<x-slot name="card-content" :item="$operator">
{{-- Operator Header --}}
<div class="flex items-start justify-between mb-4">
<div class="flex-1">
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
{{ $operator->name }}
</h3>
@if($operator->location)
<p class="text-sm text-gray-600 dark:text-gray-400">
{{ $operator->location->city }}, {{ $operator->location->country }}
</p>
@endif
</div>
@if($operator->market_influence_score)
<div class="text-right">
<div class="text-lg font-bold text-blue-600 dark:text-blue-400">
{{ number_format($operator->market_influence_score, 1) }}
</div>
<div class="text-xs text-gray-500">Influence Score</div>
</div>
@endif
</div>
{{-- Role Badges --}}
<div class="flex flex-wrap gap-2 mb-4">
@if($operator->parks_count > 0)
<span class="px-3 py-1 text-sm bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded-full">
{{ $operator->parks_count }} Parks
</span>
@endif
@if($operator->manufactured_rides_count > 0)
<span class="px-3 py-1 text-sm bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 rounded-full">
{{ $operator->manufactured_rides_count }} Manufactured
</span>
@endif
@if($operator->designed_rides_count > 0)
<span class="px-3 py-1 text-sm bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded-full">
{{ $operator->designed_rides_count }} Designed
</span>
@endif
</div>
{{-- Key Metrics --}}
<div class="grid grid-cols-2 gap-4 text-sm">
@if($operator->founded_year)
<div>
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ $operator->founded_year }}</div>
<div class="text-gray-600 dark:text-gray-400">Founded</div>
</div>
@endif
@if($operator->industry_sector)
<div>
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ ucfirst($operator->industry_sector) }}</div>
<div class="text-gray-600 dark:text-gray-400">Sector</div>
</div>
@endif
@if($operator->employee_count)
<div>
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ number_format($operator->employee_count) }}</div>
<div class="text-gray-600 dark:text-gray-400">Employees</div>
</div>
@endif
@if($operator->geographic_presence_level)
<div>
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ ucfirst($operator->geographic_presence_level) }}</div>
<div class="text-gray-600 dark:text-gray-400">Presence</div>
</div>
@endif
</div>
</x-slot>
{{-- Custom Portfolio View Content --}}
<x-slot name="portfolio-content" :item="$operator">
<div class="flex items-start justify-between mb-4">
<div class="flex-1">
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-2">
{{ $operator->name }}
</h3>
@if($operator->description)
<p class="text-gray-600 dark:text-gray-400 mb-3">{{ $operator->description }}</p>
@endif
<div class="flex flex-wrap gap-2">
@if($operator->parks_count > 0)
<span class="px-3 py-1 text-sm bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded-full">
Park Operator: {{ $operator->parks_count }} parks
</span>
@endif
@if($operator->manufactured_rides_count > 0)
<span class="px-3 py-1 text-sm bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 rounded-full">
Manufacturer: {{ $operator->manufactured_rides_count }} rides
</span>
@endif
@if($operator->designed_rides_count > 0)
<span class="px-3 py-1 text-sm bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded-full">
Designer: {{ $operator->designed_rides_count }} rides
</span>
@endif
</div>
</div>
@if($operator->market_influence_score)
<div class="text-right ml-6">
<div class="text-2xl font-bold text-blue-600 dark:text-blue-400">
{{ number_format($operator->market_influence_score, 1) }}
</div>
<div class="text-sm text-gray-500">Market Influence</div>
</div>
@endif
</div>
<div class="grid grid-cols-4 gap-6 text-sm">
@if($operator->founded_year)
<div>
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $operator->founded_year }}</div>
<div class="text-gray-600 dark:text-gray-400">Founded</div>
</div>
@endif
@if($operator->industry_sector)
<div>
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ ucfirst($operator->industry_sector) }}</div>
<div class="text-gray-600 dark:text-gray-400">Industry</div>
</div>
@endif
@if($operator->employee_count)
<div>
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ number_format($operator->employee_count) }}</div>
<div class="text-gray-600 dark:text-gray-400">Employees</div>
</div>
@endif
@if($operator->location)
<div>
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $operator->location->country }}</div>
<div class="text-gray-600 dark:text-gray-400">Headquarters</div>
</div>
@endif
</div>
</x-slot>
{{-- Custom Empty State --}}
<x-slot name="empty-state">
<div class="text-center py-12">
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<h3 class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">No operators found</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Try adjusting your search or filters.</p>
<div class="mt-6">
<button
wire:click="clearFilters"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
Clear all filters
</button>
</div>
</div>
</x-slot>
{{-- Custom Clear Filters Action --}}
<x-slot name="clear-filters">
<button
wire:click="clearFilters"
class="text-sm text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-200"
>
Clear all filters
</button>
</x-slot>
</x-universal-listing>
</div>