mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 06:31:10 -05:00
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.
This commit is contained in:
445
resources/views/livewire/designers-listing-universal.blade.php
Normal file
445
resources/views/livewire/designers-listing-universal.blade.php
Normal file
@@ -0,0 +1,445 @@
|
||||
<div>
|
||||
{{-- Universal Listing System Integration --}}
|
||||
<x-universal-listing
|
||||
:entity-type="$entityType"
|
||||
:items="$designers"
|
||||
:search="$search"
|
||||
:sort-by="$sortBy"
|
||||
:sort-direction="$sortDirection"
|
||||
:view-mode="$viewMode"
|
||||
:per-page="$perPage"
|
||||
>
|
||||
{{-- Custom Creative Portfolio Header --}}
|
||||
<x-slot name="header">
|
||||
<div class="bg-gradient-to-r from-purple-500 to-pink-600 text-white p-6 rounded-lg mb-6">
|
||||
<div class="text-center">
|
||||
<h2 class="text-2xl font-bold mb-4">Creative Portfolio Overview</h2>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6">
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-bold">{{ $portfolioStats['total_designers'] ?? 0 }}</div>
|
||||
<div class="text-sm opacity-90">Total Designers</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-bold">{{ $portfolioStats['coaster_designers'] ?? 0 }}</div>
|
||||
<div class="text-sm opacity-90">Coaster Designers</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-bold">{{ $portfolioStats['dark_ride_designers'] ?? 0 }}</div>
|
||||
<div class="text-sm opacity-90">Dark Ride Designers</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-3xl font-bold">{{ number_format($portfolioStats['average_innovation_score'] ?? 0, 1) }}</div>
|
||||
<div class="text-sm opacity-90">Avg Innovation Score</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
{{-- Custom Search Placeholder --}}
|
||||
<x-slot name="search-placeholder">
|
||||
Search designers, specialties, projects...
|
||||
</x-slot>
|
||||
|
||||
{{-- Custom Filters Sidebar --}}
|
||||
<x-slot name="filters">
|
||||
{{-- Specialty Filters --}}
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">Design Specialties</h3>
|
||||
<div class="space-y-2">
|
||||
<label class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
wire:model.live="specialties"
|
||||
value="roller_coaster"
|
||||
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">
|
||||
Roller Coasters ({{ $portfolioStats['coaster_designers'] ?? 0 }})
|
||||
</span>
|
||||
</label>
|
||||
<label class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
wire:model.live="specialties"
|
||||
value="dark_ride"
|
||||
class="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
>
|
||||
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">
|
||||
Dark Rides ({{ $portfolioStats['dark_ride_designers'] ?? 0 }})
|
||||
</span>
|
||||
</label>
|
||||
<label class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
wire:model.live="specialties"
|
||||
value="themed_experience"
|
||||
class="rounded border-gray-300 text-pink-600 focus:ring-pink-500"
|
||||
>
|
||||
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">
|
||||
Themed Experiences ({{ $portfolioStats['themed_experience_designers'] ?? 0 }})
|
||||
</span>
|
||||
</label>
|
||||
<label class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
wire:model.live="specialties"
|
||||
value="water_attraction"
|
||||
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">
|
||||
Water Attractions ({{ $portfolioStats['water_attraction_designers'] ?? 0 }})
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Creative Filters --}}
|
||||
<div class="mb-6">
|
||||
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">Creative Filters</h3>
|
||||
<div class="space-y-4">
|
||||
{{-- Design Style --}}
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-700 dark:text-gray-300 mb-1">Design Style</label>
|
||||
<select wire:model.live="designStyle" 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 Styles</option>
|
||||
@if(isset($portfolioStats['design_styles']))
|
||||
@foreach($portfolioStats['design_styles'] as $style => $count)
|
||||
<option value="{{ $style }}">{{ ucfirst($style) }} ({{ $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>
|
||||
|
||||
{{-- Innovation Score 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 Innovation</label>
|
||||
<input
|
||||
type="number"
|
||||
wire:model.live="minInnovationScore"
|
||||
placeholder="0"
|
||||
step="0.1"
|
||||
min="0"
|
||||
max="10"
|
||||
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 Innovation</label>
|
||||
<input
|
||||
type="number"
|
||||
wire:model.live="maxInnovationScore"
|
||||
placeholder="10"
|
||||
step="0.1"
|
||||
min="0"
|
||||
max="10"
|
||||
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>
|
||||
|
||||
{{-- Active Years 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 Active Years</label>
|
||||
<input
|
||||
type="number"
|
||||
wire:model.live="minActiveYears"
|
||||
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 Active Years</label>
|
||||
<input
|
||||
type="number"
|
||||
wire:model.live="maxActiveYears"
|
||||
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>
|
||||
|
||||
{{-- Innovation Timeline Panel --}}
|
||||
<div class="bg-purple-50 dark:bg-purple-900/20 rounded-lg p-4 mb-6">
|
||||
<h3 class="text-sm font-medium text-purple-900 dark:text-purple-100 mb-3">Innovation Timeline</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
@if(isset($innovationTimeline['innovation_milestones']))
|
||||
@foreach(array_slice($innovationTimeline['innovation_milestones'], 0, 3) as $milestone)
|
||||
<div class="flex justify-between">
|
||||
<span class="text-purple-700 dark:text-purple-300 truncate">{{ $milestone['name'] }}</span>
|
||||
<span class="font-medium text-purple-900 dark:text-purple-100">{{ number_format($milestone['innovation_score'], 1) }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Portfolio Statistics Panel --}}
|
||||
<div class="bg-pink-50 dark:bg-pink-900/20 rounded-lg p-4">
|
||||
<h3 class="text-sm font-medium text-pink-900 dark:text-pink-100 mb-3">Portfolio Stats</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-pink-700 dark:text-pink-300">Total Designs</span>
|
||||
<span class="font-medium text-pink-900 dark:text-pink-100">{{ $portfolioStats['total_designs'] ?? 0 }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-pink-700 dark:text-pink-300">Avg Innovation</span>
|
||||
<span class="font-medium text-pink-900 dark:text-pink-100">{{ number_format($portfolioStats['average_innovation_score'] ?? 0, 1) }}</span>
|
||||
</div>
|
||||
@if(isset($collaborationNetworks['network_hubs']))
|
||||
<div class="flex justify-between">
|
||||
<span class="text-pink-700 dark:text-pink-300">Network Hubs</span>
|
||||
<span class="font-medium text-pink-900 dark:text-pink-100">{{ count($collaborationNetworks['network_hubs']) }}</span>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
{{-- Custom Mobile Specialty Filter Buttons --}}
|
||||
<x-slot name="mobile-filters">
|
||||
<div class="flex flex-wrap gap-2 mb-4">
|
||||
<button
|
||||
wire:click="toggleSpecialtyFilter('roller_coaster')"
|
||||
class="px-3 py-1.5 text-sm rounded-full border transition-colors {{ in_array('roller_coaster', $specialties) ? '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' }}"
|
||||
>
|
||||
Coasters
|
||||
@if(isset($portfolioStats['coaster_designers']))
|
||||
<span class="ml-1 text-xs opacity-75">({{ $portfolioStats['coaster_designers'] }})</span>
|
||||
@endif
|
||||
</button>
|
||||
<button
|
||||
wire:click="toggleSpecialtyFilter('dark_ride')"
|
||||
class="px-3 py-1.5 text-sm rounded-full border transition-colors {{ in_array('dark_ride', $specialties) ? 'bg-indigo-500 text-white border-indigo-500' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600' }}"
|
||||
>
|
||||
Dark Rides
|
||||
@if(isset($portfolioStats['dark_ride_designers']))
|
||||
<span class="ml-1 text-xs opacity-75">({{ $portfolioStats['dark_ride_designers'] }})</span>
|
||||
@endif
|
||||
</button>
|
||||
<button
|
||||
wire:click="toggleSpecialtyFilter('themed_experience')"
|
||||
class="px-3 py-1.5 text-sm rounded-full border transition-colors {{ in_array('themed_experience', $specialties) ? 'bg-pink-500 text-white border-pink-500' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600' }}"
|
||||
>
|
||||
Experiences
|
||||
@if(isset($portfolioStats['themed_experience_designers']))
|
||||
<span class="ml-1 text-xs opacity-75">({{ $portfolioStats['themed_experience_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="innovation_score">Innovation Score</option>
|
||||
<option value="designed_rides_count">Designs Count</option>
|
||||
<option value="active_years">Active Years</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-purple-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-purple-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="$designer">
|
||||
{{-- Designer 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">
|
||||
{{ $designer->name }}
|
||||
</h3>
|
||||
@if($designer->headquarters)
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
{{ $designer->headquarters }}
|
||||
</p>
|
||||
@endif
|
||||
</div>
|
||||
@if($designer->innovation_score)
|
||||
<div class="text-right">
|
||||
<div class="text-lg font-bold text-purple-600 dark:text-purple-400">
|
||||
{{ number_format($designer->innovation_score, 1) }}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500">Innovation Score</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Specialty Badge --}}
|
||||
<div class="flex flex-wrap gap-2 mb-4">
|
||||
@if($designer->specialty)
|
||||
<span class="px-3 py-1 text-sm bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded-full">
|
||||
{{ ucfirst(str_replace('_', ' ', $designer->specialty)) }}
|
||||
</span>
|
||||
@endif
|
||||
@if($designer->rides_count > 0)
|
||||
<span class="px-3 py-1 text-sm bg-pink-100 dark:bg-pink-900 text-pink-800 dark:text-pink-200 rounded-full">
|
||||
{{ $designer->rides_count }} Designs
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Key Metrics --}}
|
||||
<div class="grid grid-cols-2 gap-4 text-sm">
|
||||
@if($designer->founded_year)
|
||||
<div>
|
||||
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ $designer->founded_year }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Founded</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($designer->active_years)
|
||||
<div>
|
||||
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ $designer->active_years }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Active Years</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($designer->design_style)
|
||||
<div>
|
||||
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ ucfirst($designer->design_style) }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Style</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($designer->rides_count)
|
||||
<div>
|
||||
<div class="font-semibold text-gray-900 dark:text-gray-100">{{ $designer->rides_count }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Designs</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</x-slot>
|
||||
|
||||
{{-- Custom Portfolio View Content --}}
|
||||
<x-slot name="portfolio-content" :item="$designer">
|
||||
<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">
|
||||
{{ $designer->name }}
|
||||
</h3>
|
||||
@if($designer->description)
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-3">{{ $designer->description }}</p>
|
||||
@endif
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@if($designer->specialty)
|
||||
<span class="px-3 py-1 text-sm bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200 rounded-full">
|
||||
Specialty: {{ ucfirst(str_replace('_', ' ', $designer->specialty)) }}
|
||||
</span>
|
||||
@endif
|
||||
@if($designer->design_style)
|
||||
<span class="px-3 py-1 text-sm bg-pink-100 dark:bg-pink-900 text-pink-800 dark:text-pink-200 rounded-full">
|
||||
Style: {{ ucfirst($designer->design_style) }}
|
||||
</span>
|
||||
@endif
|
||||
@if($designer->rides_count > 0)
|
||||
<span class="px-3 py-1 text-sm bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200 rounded-full">
|
||||
{{ $designer->rides_count }} designs
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@if($designer->innovation_score)
|
||||
<div class="text-right ml-6">
|
||||
<div class="text-2xl font-bold text-purple-600 dark:text-purple-400">
|
||||
{{ number_format($designer->innovation_score, 1) }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-500">Innovation Score</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-6 text-sm">
|
||||
@if($designer->founded_year)
|
||||
<div>
|
||||
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $designer->founded_year }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Founded</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($designer->active_years)
|
||||
<div>
|
||||
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $designer->active_years }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Active Years</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($designer->rides_count)
|
||||
<div>
|
||||
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $designer->rides_count }}</div>
|
||||
<div class="text-gray-600 dark:text-gray-400">Total Designs</div>
|
||||
</div>
|
||||
@endif
|
||||
@if($designer->headquarters)
|
||||
<div>
|
||||
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">{{ $designer->headquarters }}</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="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
|
||||
</svg>
|
||||
<h3 class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">No designers 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-purple-700 bg-purple-100 hover:bg-purple-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-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-purple-600 hover:text-purple-800 dark:text-purple-400 dark:hover:text-purple-200"
|
||||
>
|
||||
Clear all filters
|
||||
</button>
|
||||
</x-slot>
|
||||
</x-universal-listing>
|
||||
</div>
|
||||
Reference in New Issue
Block a user