mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 15:31:10 -05:00
167 lines
4.8 KiB
PHP
167 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Location;
|
|
|
|
use Livewire\Component;
|
|
use App\Services\GeocodeService;
|
|
use App\Exceptions\GeocodingException;
|
|
use App\Exceptions\ValidationException;
|
|
|
|
class LocationSelectorComponent extends Component
|
|
{
|
|
// Search State
|
|
public string $searchQuery = '';
|
|
public array $searchResults = [];
|
|
public bool $isSearching = false;
|
|
public ?string $validationError = null;
|
|
|
|
// Location State
|
|
public ?float $latitude = null;
|
|
public ?float $longitude = null;
|
|
public ?string $formattedAddress = null;
|
|
public bool $isValidLocation = false;
|
|
|
|
// UI State
|
|
public bool $showSearchResults = false;
|
|
public bool $isLoadingLocation = false;
|
|
public string $mode = 'search'; // search|coordinates|current
|
|
|
|
// Component Configuration
|
|
protected $geocodeService;
|
|
|
|
protected $listeners = [
|
|
'mapLocationSelected' => 'handleMapLocation',
|
|
'clearLocation' => 'clearSelection',
|
|
];
|
|
|
|
public function mount(GeocodeService $geocodeService)
|
|
{
|
|
$this->geocodeService = $geocodeService;
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.location.location-selector');
|
|
}
|
|
|
|
public function updatedSearchQuery()
|
|
{
|
|
if (strlen($this->searchQuery) < 3) {
|
|
$this->searchResults = [];
|
|
$this->showSearchResults = false;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$this->isSearching = true;
|
|
$this->searchResults = $this->geocodeService->geocode($this->searchQuery);
|
|
$this->showSearchResults = true;
|
|
$this->validationError = null;
|
|
} catch (GeocodingException $e) {
|
|
$this->validationError = $e->getMessage();
|
|
} finally {
|
|
$this->isSearching = false;
|
|
}
|
|
}
|
|
|
|
public function selectLocation(array $location)
|
|
{
|
|
try {
|
|
if (!isset($location['lat'], $location['lon'])) {
|
|
throw new ValidationException('Invalid location data');
|
|
}
|
|
|
|
$this->setCoordinates($location['lat'], $location['lon']);
|
|
$this->formattedAddress = $location['display_name'] ?? null;
|
|
$this->showSearchResults = false;
|
|
$this->searchQuery = '';
|
|
$this->isValidLocation = true;
|
|
$this->validationError = null;
|
|
|
|
$this->dispatch('locationSelected', [
|
|
'latitude' => $this->latitude,
|
|
'longitude' => $this->longitude,
|
|
'address' => $this->formattedAddress,
|
|
]);
|
|
} catch (ValidationException $e) {
|
|
$this->validationError = $e->getMessage();
|
|
$this->isValidLocation = false;
|
|
}
|
|
}
|
|
|
|
public function setCoordinates(float $lat, float $lon)
|
|
{
|
|
try {
|
|
if (!$this->geocodeService->validateCoordinates($lat, $lon)) {
|
|
throw new ValidationException('Invalid coordinates');
|
|
}
|
|
|
|
$this->latitude = $lat;
|
|
$this->longitude = $lon;
|
|
$this->isValidLocation = true;
|
|
$this->validationError = null;
|
|
|
|
$this->dispatch('coordinatesChanged', [
|
|
'latitude' => $this->latitude,
|
|
'longitude' => $this->longitude,
|
|
]);
|
|
} catch (ValidationException $e) {
|
|
$this->validationError = $e->getMessage();
|
|
$this->isValidLocation = false;
|
|
}
|
|
}
|
|
|
|
public function handleMapLocation($lat, $lon)
|
|
{
|
|
$this->setCoordinates($lat, $lon);
|
|
|
|
try {
|
|
$address = $this->geocodeService->reverseGeocode($lat, $lon);
|
|
$this->formattedAddress = $address['display_name'] ?? null;
|
|
} catch (GeocodingException $e) {
|
|
$this->validationError = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
public function detectCurrentLocation()
|
|
{
|
|
$this->mode = 'current';
|
|
$this->isLoadingLocation = true;
|
|
$this->dispatch('requestCurrentLocation');
|
|
}
|
|
|
|
public function clearSelection()
|
|
{
|
|
$this->reset([
|
|
'latitude',
|
|
'longitude',
|
|
'formattedAddress',
|
|
'isValidLocation',
|
|
'searchQuery',
|
|
'searchResults',
|
|
'showSearchResults',
|
|
'validationError',
|
|
]);
|
|
$this->mode = 'search';
|
|
}
|
|
|
|
public function switchMode(string $mode)
|
|
{
|
|
if (!in_array($mode, ['search', 'coordinates', 'current'])) {
|
|
return;
|
|
}
|
|
|
|
$this->mode = $mode;
|
|
$this->clearSelection();
|
|
$this->dispatch('modeChanged', ['mode' => $mode]);
|
|
}
|
|
|
|
protected function rules()
|
|
{
|
|
return [
|
|
'latitude' => 'required|numeric|between:-90,90',
|
|
'longitude' => 'required|numeric|between:-180,180',
|
|
'searchQuery' => 'nullable|string|min:3|max:200',
|
|
];
|
|
}
|
|
} |