import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import api from '../services/api'; import { format } from 'date-fns'; import { PlusIcon, PencilIcon, TrashIcon, ServerIcon, MapPinIcon, SignalIcon, BoltIcon } from '@heroicons/react/24/outline'; const Devices = () => { const navigate = useNavigate(); const [devices, setDevices] = useState([]); const [loading, setLoading] = useState(true); const [showAddModal, setShowAddModal] = useState(false); const [editingDevice, setEditingDevice] = useState(null); const [filter, setFilter] = useState('all'); // 'all', 'approved', 'pending' const [showDetailsModal, setShowDetailsModal] = useState(false); const [selectedDevice, setSelectedDevice] = useState(null); useEffect(() => { fetchDevices(); }, []); const fetchDevices = async () => { try { const response = await api.get('/devices?include_stats=true'); setDevices(response.data.data); } catch (error) { console.error('Error fetching devices:', error); } finally { setLoading(false); } }; const handleAddDevice = () => { setEditingDevice(null); setShowAddModal(true); }; const handleEditDevice = (device) => { setEditingDevice(device); setShowAddModal(true); }; const handleApproveDevice = async (deviceId) => { try { await api.post(`/devices/${deviceId}/approve`, { approved: true }); fetchDevices(); } catch (error) { console.error('Error approving device:', error); if (error.response?.status === 401 || error.response?.status === 403) { alert('Your session has expired. Please log in again.'); return; } alert('Error approving device: ' + (error.response?.data?.message || error.message)); } }; const handleRejectDevice = async (deviceId) => { if (window.confirm('Are you sure you want to reject this device?')) { try { await api.post(`/devices/${deviceId}/approve`, { approved: false }); fetchDevices(); } catch (error) { console.error('Error rejecting device:', error); if (error.response?.status === 401 || error.response?.status === 403) { alert('Your session has expired. Please log in again.'); return; } alert('Error rejecting device: ' + (error.response?.data?.message || error.message)); } } }; const handleViewDetails = (device) => { setSelectedDevice(device); setShowDetailsModal(true); }; const handleViewOnMap = (device) => { if (device.geo_lat && device.geo_lon) { // Navigate to map with device information navigate('/map', { state: { focusDevice: { id: device.id, name: device.name || `Device ${device.id}`, lat: device.geo_lat, lon: device.geo_lon, status: device.stats?.status || 'unknown' } } }); } else { alert('Device location coordinates are not available'); } }; const handleDeleteDevice = async (deviceId) => { if (window.confirm('Are you sure you want to deactivate this device?')) { try { await api.delete(`/devices/${deviceId}`); fetchDevices(); } catch (error) { console.error('Error deleting device:', error); } } }; const getStatusColor = (status) => { switch (status) { case 'online': return 'bg-green-100 text-green-800'; case 'offline': return 'bg-red-100 text-red-800'; default: return 'bg-gray-100 text-gray-800'; } }; const getSignalStrength = (lastHeartbeat) => { if (!lastHeartbeat) return 'Unknown'; const timeSince = (new Date() - new Date(lastHeartbeat)) / 1000 / 60; // minutes if (timeSince < 5) return 'Strong'; if (timeSince < 15) return 'Good'; if (timeSince < 60) return 'Weak'; return 'Lost'; }; const filteredDevices = devices.filter(device => { if (filter === 'approved') return device.is_approved; if (filter === 'pending') return !device.is_approved; return true; // 'all' }); const pendingCount = devices.filter(device => !device.is_approved).length; if (loading) { return (
Manage your drone detection devices {pendingCount > 0 && ( {pendingCount} pending approval )}
{filter === 'pending' ? 'No devices are currently pending approval.' : filter === 'approved' ? 'No devices have been approved yet.' : 'No devices match the current filter.' }
Get started by adding your first drone detection device.