gps_system/app/Livewire/GeofenceManagement.php
sackey 6b878bb0a0
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
Initial commit
2025-09-12 16:19:56 +00:00

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
]);
}
}