256 lines
8.7 KiB
PHP
256 lines
8.7 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
use App\Models\Geofence;
|
|
use App\Models\Device;
|
|
use App\Services\TraccarService;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class GeofenceManagement extends Component
|
|
{
|
|
use WithPagination;
|
|
|
|
public $search = '';
|
|
public $showModal = false;
|
|
public $editingGeofence = null;
|
|
public $selectedGeofence = null;
|
|
|
|
// Form fields
|
|
public $geofenceName = '';
|
|
public $geofenceDescription = '';
|
|
public $geofenceType = 'entry';
|
|
public $geofenceActive = true;
|
|
public $selectedDevicesForGeofence = [];
|
|
public $tempCoordinates = null;
|
|
|
|
// Map settings
|
|
public $mapCenter = ['lat' => 40.7128, 'lng' => -74.0060];
|
|
public $zoomLevel = 13;
|
|
|
|
protected $traccarService;
|
|
|
|
public function boot(TraccarService $traccarService)
|
|
{
|
|
$this->traccarService = $traccarService;
|
|
}
|
|
|
|
protected $rules = [
|
|
'geofenceName' => 'required|string|max:255',
|
|
'geofenceDescription' => 'nullable|string|max:1000',
|
|
'geofenceType' => 'required|string|in:entry,exit,both,zone',
|
|
'selectedDevicesForGeofence' => 'array',
|
|
'selectedDevicesForGeofence.*' => 'exists:devices,id',
|
|
];
|
|
|
|
public function mount()
|
|
{
|
|
// Set default map center based on user's devices
|
|
$userDevices = Device::where('user_id', Auth::id())->get();
|
|
if ($userDevices->isNotEmpty()) {
|
|
$avgLat = $userDevices->avg('last_position_lat') ?: 40.7128;
|
|
$avgLng = $userDevices->avg('last_position_lng') ?: -74.0060;
|
|
$this->mapCenter = ['lat' => $avgLat, 'lng' => $avgLng];
|
|
}
|
|
}
|
|
|
|
public function showGeofenceModal()
|
|
{
|
|
$this->resetForm();
|
|
$this->showModal = true;
|
|
}
|
|
|
|
public function closeModal()
|
|
{
|
|
$this->showModal = false;
|
|
$this->resetForm();
|
|
$this->dispatch('clearDrawnShape');
|
|
}
|
|
|
|
public function selectGeofence($geofenceId)
|
|
{
|
|
$this->selectedGeofence = $geofenceId;
|
|
}
|
|
|
|
public function editGeofence($geofenceId)
|
|
{
|
|
$geofence = Geofence::findOrFail($geofenceId);
|
|
|
|
$this->editingGeofence = $geofence;
|
|
$this->geofenceName = $geofence->name;
|
|
$this->geofenceDescription = $geofence->description;
|
|
$this->geofenceType = $geofence->type ?? 'entry';
|
|
$this->geofenceActive = $geofence->is_active;
|
|
$this->selectedDevicesForGeofence = $geofence->devices->pluck('id')->toArray();
|
|
|
|
$this->showModal = true;
|
|
}
|
|
|
|
public function saveGeofence()
|
|
{
|
|
$this->validate();
|
|
|
|
if (!$this->tempCoordinates && !$this->editingGeofence) {
|
|
session()->flash('error', 'Please draw a geofence area on the map first.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$geofenceData = [
|
|
'name' => $this->geofenceName,
|
|
'description' => $this->geofenceDescription,
|
|
'type' => $this->geofenceType,
|
|
'is_active' => $this->geofenceActive,
|
|
'coordinates' => $this->tempCoordinates ? json_encode($this->tempCoordinates) : null,
|
|
];
|
|
|
|
if ($this->editingGeofence) {
|
|
// Update existing geofence
|
|
$this->editingGeofence->update($geofenceData);
|
|
$geofence = $this->editingGeofence;
|
|
|
|
// Update in Traccar if it has traccar_id
|
|
if ($geofence->traccar_id) {
|
|
$traccarData = [
|
|
'id' => $geofence->traccar_id,
|
|
'name' => $this->geofenceName,
|
|
'description' => $this->geofenceDescription,
|
|
'area' => $this->tempCoordinates ? $this->convertCoordinatesToTraccarFormat($this->tempCoordinates) : $geofence->area,
|
|
];
|
|
$this->traccarService->updateGeofence($geofence->traccar_id, $traccarData);
|
|
}
|
|
} else {
|
|
// Create new geofence
|
|
$geofenceData['user_id'] = Auth::id();
|
|
|
|
// Create in Traccar first
|
|
$traccarData = [
|
|
'name' => $this->geofenceName,
|
|
'description' => $this->geofenceDescription,
|
|
'area' => $this->convertCoordinatesToTraccarFormat($this->tempCoordinates),
|
|
];
|
|
|
|
$traccarGeofence = $this->traccarService->createGeofence($traccarData);
|
|
|
|
if ($traccarGeofence && isset($traccarGeofence['id'])) {
|
|
$geofenceData['traccar_id'] = $traccarGeofence['id'];
|
|
}
|
|
|
|
$geofence = Geofence::create($geofenceData);
|
|
}
|
|
|
|
// Sync device associations
|
|
$geofence->devices()->sync($this->selectedDevicesForGeofence);
|
|
|
|
// Sync device-geofence associations in Traccar
|
|
foreach ($this->selectedDevicesForGeofence as $deviceId) {
|
|
$device = Device::find($deviceId);
|
|
if ($device && $device->traccar_id && $geofence->traccar_id) {
|
|
$this->traccarService->linkGeofenceToDevice($geofence->traccar_id, $device->traccar_id);
|
|
}
|
|
}
|
|
|
|
$this->closeModal();
|
|
$this->dispatch('geofencesUpdated');
|
|
session()->flash('success', $this->editingGeofence ? 'Geofence updated successfully!' : 'Geofence created successfully!');
|
|
|
|
} catch (\Exception $e) {
|
|
session()->flash('error', 'Failed to save geofence: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
private function convertCoordinatesToTraccarFormat($coordinates)
|
|
{
|
|
if (!$coordinates) return '';
|
|
|
|
if ($coordinates['type'] === 'circle') {
|
|
// For circles, create a polygon approximation
|
|
$center = $coordinates['center'];
|
|
$radius = $coordinates['radius'];
|
|
$points = [];
|
|
|
|
for ($i = 0; $i < 16; $i++) {
|
|
$angle = ($i * 360 / 16) * (M_PI / 180);
|
|
$lat = $center[0] + ($radius / 111000) * cos($angle);
|
|
$lng = $center[1] + ($radius / (111000 * cos($center[0] * M_PI / 180))) * sin($angle);
|
|
$points[] = "$lat $lng";
|
|
}
|
|
|
|
return "POLYGON((" . implode(', ', $points) . "))";
|
|
} else {
|
|
// For polygons
|
|
$points = array_map(function($coord) {
|
|
return $coord[0] . ' ' . $coord[1];
|
|
}, $coordinates['coordinates']);
|
|
|
|
return "POLYGON((" . implode(', ', $points) . "))";
|
|
}
|
|
}
|
|
|
|
public function deleteGeofence($geofenceId)
|
|
{
|
|
try {
|
|
$geofence = Geofence::findOrFail($geofenceId);
|
|
|
|
// Delete from Traccar if it exists
|
|
if ($geofence->traccar_id) {
|
|
$this->traccarService->deleteGeofence($geofence->traccar_id);
|
|
}
|
|
|
|
$geofence->delete();
|
|
$this->dispatch('geofencesUpdated');
|
|
session()->flash('success', 'Geofence deleted successfully!');
|
|
|
|
} catch (\Exception $e) {
|
|
session()->flash('error', 'Failed to delete geofence: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function refreshGeofences()
|
|
{
|
|
$this->dispatch('geofencesUpdated');
|
|
session()->flash('success', 'Geofences refreshed!');
|
|
}
|
|
|
|
private function resetForm()
|
|
{
|
|
$this->editingGeofence = null;
|
|
$this->geofenceName = '';
|
|
$this->geofenceDescription = '';
|
|
$this->geofenceType = 'entry';
|
|
$this->geofenceActive = true;
|
|
$this->selectedDevicesForGeofence = [];
|
|
$this->tempCoordinates = null;
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
$geofences = Geofence::where('user_id', Auth::id())
|
|
->when($this->search, function($query) {
|
|
$query->where('name', 'like', '%' . $this->search . '%')
|
|
->orWhere('description', 'like', '%' . $this->search . '%');
|
|
})
|
|
->with('devices')
|
|
->orderBy('created_at', 'desc')
|
|
->get();
|
|
|
|
$query = Device::where('user_id', Auth::id());
|
|
|
|
// Check if device groups have users relationship (safely handle missing relationship)
|
|
if (method_exists(\App\Models\DeviceGroup::class, 'users')) {
|
|
$query->orWhereHas('group.users', function($subQuery) {
|
|
$subQuery->where('user_id', Auth::id());
|
|
});
|
|
}
|
|
|
|
$devices = $query->get();
|
|
|
|
return view('livewire.geofence-management', [
|
|
'geofences' => $geofences,
|
|
'devices' => $devices
|
|
]);
|
|
}
|
|
}
|