mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-21 18:11:09 -05:00
Implement LocationDisplayComponent and LocationMapComponent for interactive map features; add event handling and state management
This commit is contained in:
167
app/Livewire/Location/LocationSelectorComponent.php
Normal file
167
app/Livewire/Location/LocationSelectorComponent.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?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',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user