gps_system/app/Livewire/EventsAndAlerts.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

417 lines
14 KiB
PHP

<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\WithPagination;
use App\Models\Event;
use App\Models\Device;
use App\Models\Geofence;
use App\Models\NotificationPreference;
use App\Services\TraccarService;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
class EventsAndAlerts extends Component
{
use WithPagination;
public $search = '';
public $deviceFilter = 'all';
public $eventTypeFilter = 'all';
public $dateRange = '7'; // days
public $selectedEvent = null;
public $showNotificationSettings = false;
// Filter properties
public $filterType = '';
public $filterDevice = '';
public $filterDateFrom = '';
public $filterDateTo = '';
public $filterStatus = '';
public $filterAcknowledged = '';
// Notification settings
public $emailNotifications = true;
public $pushNotifications = true;
public $smsNotifications = false;
public $notificationTypes = [];
protected $traccarService;
public function boot(TraccarService $traccarService)
{
$this->traccarService = $traccarService;
}
public function mount()
{
$this->loadNotificationSettings();
}
public function loadNotificationSettings()
{
$user = Auth::user();
$preferences = NotificationPreference::where('user_id', $user->id)->first();
if ($preferences) {
$this->emailNotifications = $preferences->email_enabled;
$this->pushNotifications = $preferences->push_enabled;
$this->smsNotifications = $preferences->sms_enabled;
$this->notificationTypes = $preferences->event_types ?? [];
}
}
public function saveNotificationSettings()
{
try {
$user = Auth::user();
NotificationPreference::updateOrCreate(
['user_id' => $user->id],
[
'email_enabled' => $this->emailNotifications,
'push_enabled' => $this->pushNotifications,
'sms_enabled' => $this->smsNotifications,
'event_types' => $this->notificationTypes,
]
);
$this->showNotificationSettings = false;
session()->flash('success', 'Notification settings saved successfully!');
} catch (\Exception $e) {
session()->flash('error', 'Failed to save notification settings: ' . $e->getMessage());
}
}
public function viewEventDetails($eventId)
{
$this->selectedEvent = Event::with(['device', 'geofence'])->findOrFail($eventId);
}
public function closeEventDetails()
{
$this->selectedEvent = null;
}
public function markAsRead($eventId)
{
try {
$event = Event::findOrFail($eventId);
$event->update(['acknowledged' => true, 'acknowledged_at' => now()]);
session()->flash('success', 'Event marked as read');
} catch (\Exception $e) {
session()->flash('error', 'Failed to mark event as read: ' . $e->getMessage());
}
}
public function syncEvents()
{
try {
// Get events from Traccar
$traccarEvents = $this->traccarService->getEvents();
if ($traccarEvents) {
foreach ($traccarEvents as $traccarEvent) {
$device = Device::where('traccar_id', $traccarEvent['deviceId'])->first();
$geofence = null;
if (isset($traccarEvent['geofenceId'])) {
$geofence = Geofence::where('traccar_id', $traccarEvent['geofenceId'])->first();
}
if ($device) {
Event::updateOrCreate(
['traccar_id' => $traccarEvent['id']],
[
'device_id' => $device->id,
'geofence_id' => $geofence?->id,
'event_type' => $traccarEvent['type'],
'event_time' => Carbon::parse($traccarEvent['eventTime']),
'position_id' => null, // Would need to match position
'attributes' => $traccarEvent['attributes'] ?? null,
'acknowledged' => false,
]
);
}
}
}
session()->flash('success', 'Events synchronized successfully!');
} catch (\Exception $e) {
session()->flash('error', 'Failed to sync events: ' . $e->getMessage());
}
}
public function getEventIcon($eventType)
{
return match ($eventType) {
'deviceOnline' => 'signal',
'deviceOffline' => 'signal-slash',
'deviceOverspeed' => 'exclamation-triangle',
'deviceFuelDrop' => 'fire',
'geofenceEnter' => 'map-pin',
'geofenceExit' => 'map-pin',
'alarm' => 'bell',
'ignitionOn' => 'key',
'ignitionOff' => 'key',
'maintenance' => 'wrench',
'textMessage' => 'chat-bubble-left',
'driverChanged' => 'user',
default => 'information-circle'
};
}
public function getEventColor($eventType)
{
return match ($eventType) {
'deviceOnline' => 'text-green-600 dark:text-green-400',
'deviceOffline' => 'text-red-600 dark:text-red-400',
'deviceOverspeed' => 'text-orange-600 dark:text-orange-400',
'deviceFuelDrop' => 'text-red-600 dark:text-red-400',
'geofenceEnter' => 'text-blue-600 dark:text-blue-400',
'geofenceExit' => 'text-purple-600 dark:text-purple-400',
'alarm' => 'text-red-600 dark:text-red-400',
'ignitionOn' => 'text-green-600 dark:text-green-400',
'ignitionOff' => 'text-gray-600 dark:text-gray-400',
'maintenance' => 'text-yellow-600 dark:text-yellow-400',
'textMessage' => 'text-blue-600 dark:text-blue-400',
'driverChanged' => 'text-indigo-600 dark:text-indigo-400',
default => 'text-gray-600 dark:text-gray-400'
};
}
public function refreshEvents()
{
$this->resetPage();
session()->flash('success', 'Events refreshed!');
}
public function markAllAsRead()
{
try {
Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->where('acknowledged', false)
->update(['acknowledged' => true, 'acknowledged_at' => now()]);
session()->flash('success', 'All events marked as read');
} catch (\Exception $e) {
session()->flash('error', 'Failed to mark all events as read: ' . $e->getMessage());
}
}
public function acknowledgeEvent($eventId)
{
try {
$event = Event::findOrFail($eventId);
$event->update([
'acknowledged' => true,
'acknowledged_at' => now(),
'acknowledged_by' => Auth::id()
]);
session()->flash('success', 'Event acknowledged');
} catch (\Exception $e) {
session()->flash('error', 'Failed to acknowledge event: ' . $e->getMessage());
}
}
public function showEventDetails($eventId)
{
$this->selectedEvent = Event::with(['device', 'geofence', 'position'])->findOrFail($eventId);
}
public function showOnMap($latitude, $longitude)
{
// Emit event to show location on map
$this->dispatch('showLocationOnMap', ['lat' => $latitude, 'lng' => $longitude]);
session()->flash('info', "Location: {$latitude}, {$longitude}");
}
public function clearFilters()
{
$this->filterType = '';
$this->filterDevice = '';
$this->filterDateFrom = '';
$this->filterDateTo = '';
$this->filterStatus = '';
$this->filterAcknowledged = '';
$this->resetPage();
}
public function hasActiveFilters()
{
return !empty($this->filterType) ||
!empty($this->filterDevice) ||
!empty($this->filterDateFrom) ||
!empty($this->filterDateTo) ||
!empty($this->filterStatus) ||
!empty($this->filterAcknowledged);
}
// Computed properties for stats
public function getCriticalCountProperty()
{
$criticalTypes = ['alarm', 'deviceOffline', 'deviceOverspeed', 'panic', 'accident', 'deviceFuelDrop'];
return Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->whereIn('type', $criticalTypes)
->where('event_time', '>=', now()->subDays(30))
->count();
}
public function getWarningCountProperty()
{
$warningTypes = ['maintenance', 'batteryLow', 'deviceMoving', 'deviceStopped', 'geofenceExit', 'ignitionOff'];
return Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->whereIn('type', $warningTypes)
->where('event_time', '>=', now()->subDays(30))
->count();
}
public function getInfoCountProperty()
{
$infoTypes = ['deviceOnline', 'geofenceEnter', 'ignitionOn', 'driverChanged', 'textMessage'];
return Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->whereIn('type', $infoTypes)
->where('event_time', '>=', now()->subDays(30))
->count();
}
public function getTotalCountProperty()
{
return Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->where('event_time', '>=', now()->subDays(30))
->count();
}
public function getEventSeverity($eventType)
{
$criticalTypes = ['alarm', 'deviceOffline', 'deviceOverspeed', 'panic', 'accident', 'deviceFuelDrop'];
$warningTypes = ['maintenance', 'batteryLow', 'deviceMoving', 'deviceStopped', 'geofenceExit', 'ignitionOff'];
if (in_array($eventType, $criticalTypes)) {
return 'critical';
} elseif (in_array($eventType, $warningTypes)) {
return 'warning';
} else {
return 'info';
}
}
public function render()
{
// Build query with filters
$query = Event::with(['device', 'geofence', 'position'])
->whereHas('device', function($q) {
$q->where('user_id', Auth::id());
});
// Apply new filters
if ($this->filterType) {
$query->where('type', $this->filterType);
}
if ($this->filterDevice) {
$query->where('device_id', $this->filterDevice);
}
if ($this->filterDateFrom) {
$query->where('event_time', '>=', $this->filterDateFrom);
}
if ($this->filterDateTo) {
$query->where('event_time', '<=', $this->filterDateTo);
}
if ($this->filterStatus) {
if ($this->filterStatus === 'unread') {
$query->where('acknowledged', false);
} elseif ($this->filterStatus === 'read') {
$query->where('acknowledged', true);
}
}
if ($this->filterAcknowledged) {
if ($this->filterAcknowledged === 'yes') {
$query->where('acknowledged', true);
} elseif ($this->filterAcknowledged === 'no') {
$query->where('acknowledged', false);
}
}
// Apply legacy search filter
if ($this->search) {
$query->where(function($q) {
$q->whereHas('device', function($deviceQuery) {
$deviceQuery->where('name', 'like', '%' . $this->search . '%');
})->orWhere('type', 'like', '%' . $this->search . '%');
});
}
// Apply legacy filters for backward compatibility
if ($this->deviceFilter !== 'all') {
$query->where('device_id', $this->deviceFilter);
}
if ($this->eventTypeFilter !== 'all') {
$query->where('type', $this->eventTypeFilter);
}
if ($this->dateRange !== 'all') {
$query->where('event_time', '>=', now()->subDays((int)$this->dateRange));
}
$events = $query->orderBy('event_time', 'desc')->paginate(20);
$deviceQuery = 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')) {
$deviceQuery->orWhereHas('group.users', function($subQuery) {
$subQuery->where('user_id', Auth::id());
});
}
$devices = $deviceQuery->get();
$eventTypes = Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->distinct()
->pluck('type')
->sort();
$unreadCount = Event::whereHas('device', function($q) {
$q->where('user_id', Auth::id());
})
->where('acknowledged', false)
->count();
return view('livewire.events-and-alerts', [
'events' => $events,
'devices' => $devices,
'eventTypes' => $eventTypes,
'unreadCount' => $unreadCount
]);
}
}