feat: implement search functionality with real-time filtering and pagination

This commit is contained in:
pacnpal
2025-02-25 22:14:13 -05:00
parent 5d2908127b
commit a57e5deb3f
5 changed files with 498 additions and 11 deletions

View File

@@ -0,0 +1,136 @@
<?php
namespace App\Livewire;
use App\Models\Park;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Component;
use Livewire\WithPagination;
class SearchComponent extends Component
{
use WithPagination;
// Filter properties
public string $search = '';
public string $location = '';
public ?float $minRating = null;
public ?float $maxRating = null;
public ?int $minRides = null;
public ?int $minCoasters = null;
public bool $filtersApplied = false;
// Querystring parameters
protected $queryString = [
'search' => ['except' => ''],
'location' => ['except' => ''],
'minRating' => ['except' => ''],
'maxRating' => ['except' => ''],
'minRides' => ['except' => ''],
'minCoasters' => ['except' => '']
];
public function mount(): void
{
$this->filtersApplied = $this->hasActiveFilters();
}
public function render(): View
{
return view('livewire.search', [
'results' => $this->getFilteredParks()
]);
}
public function updatedSearch(): void
{
$this->resetPage();
$this->filtersApplied = $this->hasActiveFilters();
}
public function updatedLocation(): void
{
$this->resetPage();
$this->filtersApplied = $this->hasActiveFilters();
}
public function updatedMinRating(): void
{
$this->resetPage();
$this->filtersApplied = $this->hasActiveFilters();
}
public function updatedMaxRating(): void
{
$this->resetPage();
$this->filtersApplied = $this->hasActiveFilters();
}
public function updatedMinRides(): void
{
$this->resetPage();
$this->filtersApplied = $this->hasActiveFilters();
}
public function updatedMinCoasters(): void
{
$this->resetPage();
$this->filtersApplied = $this->hasActiveFilters();
}
public function clearFilters(): void
{
$this->reset([
'search',
'location',
'minRating',
'maxRating',
'minRides',
'minCoasters'
]);
$this->filtersApplied = false;
$this->resetPage();
}
protected function getFilteredParks()
{
return Park::query()
->select('parks.*')
->with(['location', 'photos'])
->when($this->search, function (Builder $query) {
$query->where(function (Builder $query) {
$query->where('name', 'like', "%{$this->search}%")
->orWhere('description', 'like', "%{$this->search}%");
});
})
->when($this->location, function (Builder $query) {
$query->whereHas('location', function (Builder $query) {
$query->where('address_text', 'like', "%{$this->location}%");
});
})
->when($this->minRating, function (Builder $query) {
$query->where('average_rating', '>=', $this->minRating);
})
->when($this->maxRating, function (Builder $query) {
$query->where('average_rating', '<=', $this->maxRating);
})
->when($this->minRides, function (Builder $query) {
$query->where('ride_count', '>=', $this->minRides);
})
->when($this->minCoasters, function (Builder $query) {
$query->where('coaster_count', '>=', $this->minCoasters);
})
->paginate(10);
}
protected function hasActiveFilters(): bool
{
return !empty($this->search)
|| !empty($this->location)
|| !empty($this->minRating)
|| !empty($this->maxRating)
|| !empty($this->minRides)
|| !empty($this->minCoasters);
}
}