Fix jwt-token

This commit is contained in:
2025-08-18 10:28:08 +02:00
parent 7b0e9ca6ae
commit 24be56ad0c

View File

@@ -421,7 +421,21 @@ const MapView = () => {
opacity: opacity * 0.8,
dashArray: dashPattern
}}
eventHandlers={{
click: () => {
console.log('MapView: Ring clicked for drone:', detection);
}
}}
>
<Popup>
<DroneDetectionPopup
detection={detection}
age={age}
droneTypes={droneTypes}
droneDetectionHistory={droneDetectionHistory}
/>
</Popup>
</Circle>
{/* Drone ID label for multiple drones */}
{totalDrones > 1 && age < 5 && ( // Show labels for recent detections with multiple drones
@@ -451,7 +465,12 @@ const MapView = () => {
opacity={opacity * 0.9}
>
<Popup>
<DroneDetectionPopup detection={detection} age={age} droneTypes={droneTypes} />
<DroneDetectionPopup
detection={detection}
age={age}
droneTypes={droneTypes}
droneDetectionHistory={droneDetectionHistory}
/>
</Popup>
</Marker>
)}
@@ -464,7 +483,12 @@ const MapView = () => {
opacity={opacity * 0.7}
>
<Popup>
<DroneDetectionPopup detection={detection} age={age} droneTypes={droneTypes} />
<DroneDetectionPopup
detection={detection}
age={age}
droneTypes={droneTypes}
droneDetectionHistory={droneDetectionHistory}
/>
</Popup>
</Marker>
)}
@@ -607,12 +631,45 @@ const DevicePopup = ({ device, status, detections }) => (
</div>
);
const DroneDetectionPopup = ({ detection, age, droneTypes }) => (
<div className="p-2 min-w-[250px]">
<div className="flex items-center justify-between mb-2">
const DroneDetectionPopup = ({ detection, age, droneTypes, droneDetectionHistory }) => {
// Get all detections for this specific drone from history
const droneHistory = droneDetectionHistory.filter(d =>
d.drone_id === detection.drone_id && d.device_id === detection.device_id
).slice(0, 10); // Last 10 detections for this drone
// Calculate movement trend from history
const calculateMovementTrend = () => {
if (droneHistory.length < 2) return null;
const sortedHistory = [...droneHistory].sort((a, b) =>
new Date(a.device_timestamp) - new Date(b.device_timestamp)
);
const first = sortedHistory[0];
const latest = sortedHistory[sortedHistory.length - 1];
const rssiChange = latest.rssi - first.rssi;
return {
change: rssiChange,
trend: rssiChange > 2 ? 'APPROACHING' :
rssiChange < -2 ? 'RETREATING' : 'STABLE',
duration: (new Date(latest.device_timestamp) - new Date(first.device_timestamp)) / 1000 / 60, // minutes
detectionCount: droneHistory.length
};
};
const movementTrend = calculateMovementTrend();
const firstDetection = droneHistory.length > 0 ?
droneHistory.reduce((earliest, current) =>
new Date(current.device_timestamp) < new Date(earliest.device_timestamp) ? current : earliest
) : detection;
return (
<div className="p-3 min-w-[300px] max-w-[400px]">
<div className="flex items-center justify-between mb-3">
<h4 className="font-semibold text-red-700 flex items-center space-x-1">
<span>🚨</span>
<span>Drone Detection</span>
<span>Drone Detection Details</span>
</h4>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${
age < 1 ? 'bg-red-100 text-red-800' :
@@ -623,11 +680,13 @@ const DroneDetectionPopup = ({ detection, age, droneTypes }) => (
</span>
</div>
<div className="space-y-2 text-sm">
<div className="space-y-3 text-sm">
{/* Basic Information */}
<div className="bg-gray-50 rounded-lg p-2">
<div className="grid grid-cols-2 gap-2">
<div>
<span className="font-medium text-gray-700">Drone ID:</span>
<div className="text-gray-900">{detection.drone_id}</div>
<div className="text-gray-900 font-mono">{detection.drone_id}</div>
</div>
<div>
<span className="font-medium text-gray-700">Type:</span>
@@ -635,7 +694,7 @@ const DroneDetectionPopup = ({ detection, age, droneTypes }) => (
</div>
</div>
<div className="grid grid-cols-2 gap-2">
<div className="grid grid-cols-2 gap-2 mt-2">
<div>
<span className="font-medium text-gray-700">RSSI:</span>
<div className={`font-mono ${
@@ -651,22 +710,109 @@ const DroneDetectionPopup = ({ detection, age, droneTypes }) => (
<div className="text-gray-900">{detection.freq}MHz</div>
</div>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<span className="font-medium text-gray-700">Confidence:</span>
<div className="text-gray-900">{(detection.confidence_level * 100).toFixed(0)}%</div>
</div>
<div>
<span className="font-medium text-gray-700">Duration:</span>
<div className="text-gray-900">{(detection.signal_duration / 1000).toFixed(1)}s</div>
{/* Detection Timeline */}
<div className="border-t border-gray-200 pt-2">
<span className="font-medium text-gray-700 block mb-2">Detection Timeline:</span>
<div className="text-xs space-y-1">
<div className="flex justify-between">
<span className="text-gray-600">First detected:</span>
<span className="font-mono text-gray-900">
{format(new Date(firstDetection.device_timestamp), 'MMM dd, HH:mm:ss')}
</span>
</div>
<div className="flex justify-between">
<span className="text-gray-600">Latest detection:</span>
<span className="font-mono text-gray-900">
{format(new Date(detection.device_timestamp), 'MMM dd, HH:mm:ss')}
</span>
</div>
{droneHistory.length > 1 && (
<div className="flex justify-between">
<span className="text-gray-600">Total detections:</span>
<span className="font-medium text-gray-900">{droneHistory.length}</span>
</div>
)}
</div>
</div>
{/* Movement Analysis */}
{movementTrend && (
<div className="border-t border-gray-200 pt-2">
<span className="font-medium text-gray-700 block mb-2">Movement Analysis:</span>
<div className="text-xs space-y-2">
<div className={`px-2 py-1 rounded ${
movementTrend.trend === 'APPROACHING' ? 'bg-red-100 text-red-800' :
movementTrend.trend === 'RETREATING' ? 'bg-green-100 text-green-800' :
'bg-yellow-100 text-yellow-800'
}`}>
<div className="font-medium">
{movementTrend.trend === 'APPROACHING' ? '⚠️ APPROACHING' :
movementTrend.trend === 'RETREATING' ? '✅ RETREATING' :
'➡️ STABLE POSITION'}
</div>
<div className="mt-1">
RSSI change: {movementTrend.change > 0 ? '+' : ''}{movementTrend.change.toFixed(1)}dB
over {movementTrend.duration.toFixed(1)} minutes
</div>
</div>
{/* Signal Strength History Graph (simplified) */}
<div className="bg-gray-50 rounded p-2">
<div className="text-gray-600 mb-1">Signal Strength Trend:</div>
<div className="flex items-end space-x-1 h-8">
{droneHistory.slice(0, 8).reverse().map((hist, idx) => {
const height = Math.max(10, Math.min(32, (hist.rssi + 100) / 2)); // Scale -100 to 0 dBm to 10-32px
return (
<div
key={idx}
className={`w-2 rounded-t ${
hist.rssi > -50 ? 'bg-red-400' :
hist.rssi > -70 ? 'bg-orange-400' :
'bg-green-400'
}`}
style={{ height: `${height}px` }}
title={`${hist.rssi}dBm at ${format(new Date(hist.device_timestamp), 'HH:mm:ss')}`}
/>
);
})}
</div>
<div className="text-xs text-gray-500 mt-1">Last 8 detections (oldest to newest)</div>
</div>
</div>
</div>
)}
{/* Current Detection Details */}
<div className="border-t border-gray-200 pt-2">
<span className="font-medium text-gray-700 block mb-2">Current Detection:</span>
<div className="grid grid-cols-2 gap-2 text-xs">
<div>
<span className="text-gray-600">Confidence:</span>
<div className="text-gray-900">{(detection.confidence_level * 100).toFixed(0)}%</div>
</div>
<div>
<span className="text-gray-600">Duration:</span>
<div className="text-gray-900">{(detection.signal_duration / 1000).toFixed(1)}s</div>
</div>
<div>
<span className="text-gray-600">Detector:</span>
<div className="text-gray-900">Device {detection.device_id}</div>
</div>
<div>
<span className="text-gray-600">Location:</span>
<div className="text-gray-900 font-mono">
{detection.geo_lat?.toFixed(4)}, {detection.geo_lon?.toFixed(4)}
</div>
</div>
</div>
</div>
{/* Legacy movement analysis from detection */}
{detection.movement_analysis && (
<div className="pt-2 border-t border-gray-200">
<span className="font-medium text-gray-700 block mb-1">Movement Analysis:</span>
<div className="border-t border-gray-200 pt-2">
<span className="font-medium text-gray-700 block mb-1">Real-time Analysis:</span>
<div className="text-xs space-y-1">
<div className={`px-2 py-1 rounded ${
detection.movement_analysis.alertLevel >= 3 ? 'bg-red-100 text-red-800' :
@@ -679,7 +825,7 @@ const DroneDetectionPopup = ({ detection, age, droneTypes }) => (
{detection.movement_analysis.rssiTrend && (
<div className="flex items-center space-x-2 mt-1">
<span className="text-gray-600">Trend:</span>
<span className="text-gray-600">Instant trend:</span>
<span className={`font-medium ${
detection.movement_analysis.rssiTrend.trend === 'STRENGTHENING' ? 'text-red-600' :
detection.movement_analysis.rssiTrend.trend === 'WEAKENING' ? 'text-green-600' :
@@ -694,34 +840,13 @@ const DroneDetectionPopup = ({ detection, age, droneTypes }) => (
</span>
</div>
)}
{detection.movement_analysis.proximityLevel && (
<div className="flex items-center space-x-2">
<span className="text-gray-600">Proximity:</span>
<span className={`px-1 py-0.5 rounded text-xs font-medium ${
detection.movement_analysis.proximityLevel === 'VERY_CLOSE' ? 'bg-red-100 text-red-700' :
detection.movement_analysis.proximityLevel === 'CLOSE' ? 'bg-orange-100 text-orange-700' :
detection.movement_analysis.proximityLevel === 'MEDIUM' ? 'bg-yellow-100 text-yellow-700' :
'bg-green-100 text-green-700'
}`}>
{detection.movement_analysis.proximityLevel.replace('_', ' ')}
</span>
</div>
)}
</div>
</div>
)}
<div className="pt-2 border-t border-gray-200">
<div className="text-xs text-gray-500">
<div>Detected by: Device {detection.device_id}</div>
<div>Location: {detection.geo_lat?.toFixed(4)}, {detection.geo_lon?.toFixed(4)}</div>
<div>Time: {format(new Date(detection.device_timestamp), 'MMM dd, HH:mm:ss')}</div>
</div>
</div>
</div>
</div>
);
);
};
const DeviceListItem = ({ device, status, detections, onClick }) => (
<div