mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 05:51:09 -05:00
feat: implement autocomplete functionality for park search with keyboard navigation
This commit is contained in:
87
app/Livewire/AutocompleteComponent.php
Normal file
87
app/Livewire/AutocompleteComponent.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use App\Models\Park;
|
||||
use App\Models\Ride;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Livewire\Component;
|
||||
|
||||
class AutocompleteComponent extends Component
|
||||
{
|
||||
public string $query = '';
|
||||
public string $type = 'park';
|
||||
public array $suggestions = [];
|
||||
public ?string $selectedId = null;
|
||||
|
||||
protected $queryString = [
|
||||
'query' => ['except' => ''],
|
||||
'type' => ['except' => 'park']
|
||||
];
|
||||
|
||||
public function mount(string $type = 'park'): void
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view('livewire.autocomplete', [
|
||||
'suggestions' => $this->suggestions
|
||||
]);
|
||||
}
|
||||
|
||||
public function updatedQuery(): void
|
||||
{
|
||||
if (strlen($this->query) < 2) {
|
||||
$this->suggestions = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$this->suggestions = match ($this->type) {
|
||||
'park' => $this->getParkSuggestions(),
|
||||
'ride' => $this->getRideSuggestions(),
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
protected function getParkSuggestions(): array
|
||||
{
|
||||
return Park::query()
|
||||
->select(['id', 'name', 'slug'])
|
||||
->where('name', 'like', "%{$this->query}%")
|
||||
->orderBy('name')
|
||||
->limit(5)
|
||||
->get()
|
||||
->map(fn($park) => [
|
||||
'id' => $park->id,
|
||||
'text' => $park->name,
|
||||
'url' => route('parks.show', $park->slug)
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
protected function getRideSuggestions(): array
|
||||
{
|
||||
return Ride::query()
|
||||
->select(['id', 'name', 'slug', 'park_id'])
|
||||
->with('park:id,name')
|
||||
->where('name', 'like', "%{$this->query}%")
|
||||
->orderBy('name')
|
||||
->limit(5)
|
||||
->get()
|
||||
->map(fn($ride) => [
|
||||
'id' => $ride->id,
|
||||
'text' => "{$ride->name} at {$ride->park->name}",
|
||||
'url' => route('rides.show', $ride->slug)
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function selectSuggestion(string $id): void
|
||||
{
|
||||
$this->selectedId = $id;
|
||||
$this->dispatch('suggestion-selected', id: $id);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace App\Livewire;
|
||||
use App\Models\Park;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
@@ -49,6 +50,17 @@ class SearchComponent extends Component
|
||||
$this->filtersApplied = $this->hasActiveFilters();
|
||||
}
|
||||
|
||||
#[On('suggestion-selected')]
|
||||
public function handleSuggestionSelected($id, $text): void
|
||||
{
|
||||
$park = Park::find($id);
|
||||
if ($park) {
|
||||
$this->search = $text;
|
||||
$this->filtersApplied = $this->hasActiveFilters();
|
||||
redirect()->route('parks.show', $park);
|
||||
}
|
||||
}
|
||||
|
||||
public function updatedLocation(): void
|
||||
{
|
||||
$this->resetPage();
|
||||
|
||||
Reference in New Issue
Block a user