mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 02:31:09 -05:00
- 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.
362 lines
13 KiB
PHP
362 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
use App\Models\Manufacturer;
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
|
|
class ManufacturersListingUniversal extends Component
|
|
{
|
|
use WithPagination;
|
|
|
|
// Universal Listing System Integration
|
|
public string $entityType = 'manufacturers';
|
|
|
|
// Search and Filtering
|
|
public string $search = '';
|
|
public string $sortBy = 'name';
|
|
public string $sortDirection = 'asc';
|
|
public string $viewMode = 'grid';
|
|
public int $perPage = 12;
|
|
|
|
// Manufacturer-specific filters
|
|
public array $specializations = [];
|
|
public array $totalRidesRange = [0, 1000];
|
|
public array $industryPresenceRange = [0, 100];
|
|
public array $foundedYearRange = [1800, 2025];
|
|
public bool $activeOnly = false;
|
|
public bool $innovationLeadersOnly = false;
|
|
|
|
// Performance optimization
|
|
private string $cacheKeyPrefix = 'manufacturers_listing';
|
|
private int $cacheProductPortfolioTtl = 21600; // 6 hours
|
|
private int $cacheIndustryPresenceTtl = 43200; // 12 hours
|
|
private int $cacheListingTtl = 1800; // 30 minutes
|
|
|
|
protected $queryString = [
|
|
'search' => ['except' => ''],
|
|
'sortBy' => ['except' => 'name'],
|
|
'sortDirection' => ['except' => 'asc'],
|
|
'viewMode' => ['except' => 'grid'],
|
|
'perPage' => ['except' => 12],
|
|
'specializations' => ['except' => []],
|
|
'totalRidesRange' => ['except' => [0, 1000]],
|
|
'industryPresenceRange' => ['except' => [0, 100]],
|
|
'foundedYearRange' => ['except' => [1800, 2025]],
|
|
'activeOnly' => ['except' => false],
|
|
'innovationLeadersOnly' => ['except' => false],
|
|
'page' => ['except' => 1],
|
|
];
|
|
|
|
public function mount()
|
|
{
|
|
// Initialize filters with cached values for performance
|
|
$this->initializeFilters();
|
|
}
|
|
|
|
public function updatedSearch()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedSpecializations()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedTotalRidesRange()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedIndustryPresenceRange()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedFoundedYearRange()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedActiveOnly()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatedInnovationLeadersOnly()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function clearFilters()
|
|
{
|
|
$this->reset([
|
|
'search',
|
|
'specializations',
|
|
'totalRidesRange',
|
|
'industryPresenceRange',
|
|
'foundedYearRange',
|
|
'activeOnly',
|
|
'innovationLeadersOnly'
|
|
]);
|
|
$this->totalRidesRange = [0, 1000];
|
|
$this->industryPresenceRange = [0, 100];
|
|
$this->foundedYearRange = [1800, 2025];
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function setViewMode(string $mode)
|
|
{
|
|
$this->viewMode = $mode;
|
|
}
|
|
|
|
public function setSortBy(string $field)
|
|
{
|
|
if ($this->sortBy === $field) {
|
|
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
$this->sortBy = $field;
|
|
$this->sortDirection = 'asc';
|
|
}
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
$manufacturers = $this->getManufacturers();
|
|
$statistics = $this->getStatistics();
|
|
$productPortfolioData = $this->getProductPortfolioData();
|
|
$industryPresenceData = $this->getIndustryPresenceData();
|
|
|
|
return view('livewire.manufacturers-listing-universal', [
|
|
'manufacturers' => $manufacturers,
|
|
'statistics' => $statistics,
|
|
'productPortfolioData' => $productPortfolioData,
|
|
'industryPresenceData' => $industryPresenceData,
|
|
'hasActiveFilters' => $this->hasActiveFilters(),
|
|
]);
|
|
}
|
|
|
|
private function getManufacturers()
|
|
{
|
|
$cacheKey = $this->generateCacheKey();
|
|
|
|
return Cache::remember($cacheKey, $this->cacheListingTtl, function () {
|
|
$query = Manufacturer::query()
|
|
->select([
|
|
'id', 'name', 'slug', 'headquarters', 'description', 'website',
|
|
'total_rides', 'total_roller_coasters', 'founded_year',
|
|
'industry_presence_score', 'specialization', 'is_active',
|
|
'is_major_manufacturer', 'market_share_percentage', 'created_at'
|
|
]);
|
|
|
|
// Apply search with Django parity algorithms
|
|
if (!empty($this->search)) {
|
|
$searchTerms = explode(' ', trim($this->search));
|
|
$query->where(function (Builder $q) use ($searchTerms) {
|
|
foreach ($searchTerms as $term) {
|
|
$q->where(function (Builder $subQ) use ($term) {
|
|
$subQ->where('name', 'ILIKE', "%{$term}%")
|
|
->orWhere('description', 'ILIKE', "%{$term}%")
|
|
->orWhere('headquarters', 'ILIKE', "%{$term}%")
|
|
->orWhere('specialization', 'ILIKE', "%{$term}%");
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Apply specialization filters
|
|
if (!empty($this->specializations)) {
|
|
$query->whereIn('specialization', $this->specializations);
|
|
}
|
|
|
|
// Apply total rides range filter
|
|
if ($this->totalRidesRange[0] > 0 || $this->totalRidesRange[1] < 1000) {
|
|
$query->whereBetween('total_rides', $this->totalRidesRange);
|
|
}
|
|
|
|
// Apply industry presence score range filter
|
|
if ($this->industryPresenceRange[0] > 0 || $this->industryPresenceRange[1] < 100) {
|
|
$query->whereBetween('industry_presence_score', $this->industryPresenceRange);
|
|
}
|
|
|
|
// Apply founded year range filter
|
|
if ($this->foundedYearRange[0] > 1800 || $this->foundedYearRange[1] < 2025) {
|
|
$query->whereBetween('founded_year', $this->foundedYearRange);
|
|
}
|
|
|
|
// Apply active filter
|
|
if ($this->activeOnly) {
|
|
$query->where('is_active', true);
|
|
}
|
|
|
|
// Apply major manufacturers filter
|
|
if ($this->innovationLeadersOnly) {
|
|
$query->where('is_major_manufacturer', true);
|
|
}
|
|
|
|
// Apply sorting
|
|
$query->orderBy($this->sortBy, $this->sortDirection);
|
|
|
|
// Add secondary sort for consistency
|
|
if ($this->sortBy !== 'name') {
|
|
$query->orderBy('name', 'asc');
|
|
}
|
|
|
|
return $query->paginate($this->perPage);
|
|
});
|
|
}
|
|
|
|
private function getStatistics()
|
|
{
|
|
$cacheKey = "{$this->cacheKeyPrefix}_statistics";
|
|
|
|
return Cache::remember($cacheKey, $this->cacheListingTtl, function () {
|
|
$baseQuery = Manufacturer::query();
|
|
|
|
// Apply same filters as main query for accurate statistics
|
|
if (!empty($this->search)) {
|
|
$searchTerms = explode(' ', trim($this->search));
|
|
$baseQuery->where(function (Builder $q) use ($searchTerms) {
|
|
foreach ($searchTerms as $term) {
|
|
$q->where(function (Builder $subQ) use ($term) {
|
|
$subQ->where('name', 'ILIKE', "%{$term}%")
|
|
->orWhere('description', 'ILIKE', "%{$term}%")
|
|
->orWhere('headquarters', 'ILIKE', "%{$term}%")
|
|
->orWhere('specialization', 'ILIKE', "%{$term}%");
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!empty($this->specializations)) {
|
|
$baseQuery->whereIn('specialization', $this->specializations);
|
|
}
|
|
|
|
if ($this->totalRidesRange[0] > 0 || $this->totalRidesRange[1] < 1000) {
|
|
$baseQuery->whereBetween('total_rides', $this->totalRidesRange);
|
|
}
|
|
|
|
if ($this->industryPresenceRange[0] > 0 || $this->industryPresenceRange[1] < 100) {
|
|
$baseQuery->whereBetween('industry_presence_score', $this->industryPresenceRange);
|
|
}
|
|
|
|
if ($this->foundedYearRange[0] > 1800 || $this->foundedYearRange[1] < 2025) {
|
|
$baseQuery->whereBetween('founded_year', $this->foundedYearRange);
|
|
}
|
|
|
|
if ($this->activeOnly) {
|
|
$baseQuery->where('is_active', true);
|
|
}
|
|
|
|
if ($this->innovationLeadersOnly) {
|
|
$baseQuery->where('is_major_manufacturer', true);
|
|
}
|
|
|
|
return [
|
|
'count' => $baseQuery->count(),
|
|
'active_count' => (clone $baseQuery)->where('is_active', true)->count(),
|
|
'total_rides_sum' => $baseQuery->sum('total_rides'),
|
|
'avg_industry_presence' => round($baseQuery->avg('industry_presence_score'), 1),
|
|
];
|
|
});
|
|
}
|
|
|
|
private function getProductPortfolioData()
|
|
{
|
|
$cacheKey = "{$this->cacheKeyPrefix}_product_portfolio";
|
|
|
|
return Cache::remember($cacheKey, $this->cacheProductPortfolioTtl, function () {
|
|
return [
|
|
'specialization_distribution' => Manufacturer::selectRaw('specialization, COUNT(*) as count')
|
|
->groupBy('specialization')
|
|
->pluck('count', 'specialization')
|
|
->toArray(),
|
|
'top_manufacturers_by_rides' => Manufacturer::orderBy('total_rides', 'desc')
|
|
->limit(10)
|
|
->pluck('total_rides', 'name')
|
|
->toArray(),
|
|
'major_manufacturers_count' => Manufacturer::where('is_major_manufacturer', true)->count(),
|
|
'average_market_share' => round(Manufacturer::avg('market_share_percentage'), 2),
|
|
];
|
|
});
|
|
}
|
|
|
|
private function getIndustryPresenceData()
|
|
{
|
|
$cacheKey = "{$this->cacheKeyPrefix}_industry_presence";
|
|
|
|
return Cache::remember($cacheKey, $this->cacheIndustryPresenceTtl, function () {
|
|
return [
|
|
'presence_score_ranges' => [
|
|
'high' => Manufacturer::where('industry_presence_score', '>=', 80)->count(),
|
|
'medium' => Manufacturer::whereBetween('industry_presence_score', [50, 79])->count(),
|
|
'low' => Manufacturer::where('industry_presence_score', '<', 50)->count(),
|
|
],
|
|
'founding_decades' => Manufacturer::selectRaw('FLOOR(founded_year / 10) * 10 as decade, COUNT(*) as count')
|
|
->groupBy('decade')
|
|
->orderBy('decade')
|
|
->pluck('count', 'decade')
|
|
->toArray(),
|
|
'active_vs_inactive' => [
|
|
'active' => Manufacturer::where('is_active', true)->count(),
|
|
'inactive' => Manufacturer::where('is_active', false)->count(),
|
|
],
|
|
'market_concentration' => Manufacturer::orderBy('market_share_percentage', 'desc')
|
|
->limit(5)
|
|
->pluck('market_share_percentage', 'name')
|
|
->toArray(),
|
|
];
|
|
});
|
|
}
|
|
|
|
private function hasActiveFilters(): bool
|
|
{
|
|
return !empty($this->search) ||
|
|
!empty($this->specializations) ||
|
|
$this->totalRidesRange !== [0, 1000] ||
|
|
$this->industryPresenceRange !== [0, 100] ||
|
|
$this->foundedYearRange !== [1800, 2025] ||
|
|
$this->activeOnly ||
|
|
$this->innovationLeadersOnly;
|
|
}
|
|
|
|
private function generateCacheKey(): string
|
|
{
|
|
$filterHash = md5(serialize([
|
|
'search' => $this->search,
|
|
'sortBy' => $this->sortBy,
|
|
'sortDirection' => $this->sortDirection,
|
|
'specializations' => $this->specializations,
|
|
'totalRidesRange' => $this->totalRidesRange,
|
|
'industryPresenceRange' => $this->industryPresenceRange,
|
|
'foundedYearRange' => $this->foundedYearRange,
|
|
'activeOnly' => $this->activeOnly,
|
|
'innovationLeadersOnly' => $this->innovationLeadersOnly,
|
|
'perPage' => $this->perPage,
|
|
'page' => $this->getPage(),
|
|
]));
|
|
|
|
return "{$this->cacheKeyPrefix}_{$filterHash}";
|
|
}
|
|
|
|
private function initializeFilters()
|
|
{
|
|
// Initialize with sensible defaults for manufacturer filtering
|
|
if (empty($this->totalRidesRange)) {
|
|
$this->totalRidesRange = [0, 1000];
|
|
}
|
|
|
|
if (empty($this->industryPresenceRange)) {
|
|
$this->industryPresenceRange = [0, 100];
|
|
}
|
|
|
|
if (empty($this->foundedYearRange)) {
|
|
$this->foundedYearRange = [1800, 2025];
|
|
}
|
|
}
|
|
} |