Fix jwt-token
This commit is contained in:
@@ -12,8 +12,112 @@ export const SocketProvider = ({ children }) => {
|
||||
const [deviceStatus, setDeviceStatus] = useState({});
|
||||
const [movementAlerts, setMovementAlerts] = useState([]);
|
||||
const [droneTracking, setDroneTracking] = useState(new Map());
|
||||
const [notificationsEnabled, setNotificationsEnabled] = useState(
|
||||
localStorage.getItem('notificationsEnabled') !== 'false' // Default to enabled
|
||||
);
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
// Mobile notification management
|
||||
const [notificationCooldown, setNotificationCooldown] = useState(new Map());
|
||||
const [pendingNotifications, setPendingNotifications] = useState([]);
|
||||
|
||||
// Check if device is mobile
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
// Mobile-friendly notification handler
|
||||
const handleMobileNotification = (alertData) => {
|
||||
// Skip if notifications are disabled
|
||||
if (!notificationsEnabled) return;
|
||||
|
||||
const now = Date.now();
|
||||
const cooldownKey = `${alertData.droneId}-${alertData.analysis.alertLevel}`;
|
||||
const lastNotification = notificationCooldown.get(cooldownKey) || 0;
|
||||
|
||||
// Rate limiting based on device type and alert level
|
||||
const cooldownPeriod = isMobile
|
||||
? (alertData.analysis.alertLevel >= 3 ? 5000 : 15000) // 5s for critical, 15s for others on mobile
|
||||
: (alertData.analysis.alertLevel >= 3 ? 2000 : 8000); // 2s for critical, 8s for others on desktop
|
||||
|
||||
if (now - lastNotification < cooldownPeriod) {
|
||||
// Store pending notification for potential grouping
|
||||
setPendingNotifications(prev => [...prev, alertData]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update cooldown
|
||||
setNotificationCooldown(prev => new Map(prev).set(cooldownKey, now));
|
||||
|
||||
// Show notification with mobile-optimized settings
|
||||
const alertIcon = alertData.analysis.alertLevel >= 3 ? '🚨' :
|
||||
alertData.analysis.alertLevel >= 2 ? '⚠️' : '📍';
|
||||
|
||||
const toastOptions = {
|
||||
duration: isMobile
|
||||
? (alertData.analysis.alertLevel >= 3 ? 4000 : 2500) // Shorter durations on mobile
|
||||
: (alertData.analysis.alertLevel >= 2 ? 6000 : 4000),
|
||||
icon: alertIcon,
|
||||
style: {
|
||||
background: alertData.analysis.alertLevel >= 3 ? '#fee2e2' :
|
||||
alertData.analysis.alertLevel >= 2 ? '#fef3c7' : '#e0f2fe',
|
||||
fontSize: isMobile ? '13px' : '14px',
|
||||
padding: isMobile ? '0.75rem' : '1rem',
|
||||
maxWidth: isMobile ? '85vw' : '400px',
|
||||
}
|
||||
};
|
||||
|
||||
// Create condensed message for mobile
|
||||
const message = isMobile
|
||||
? `${alertIcon} Drone ${alertData.droneId}: ${getShortDescription(alertData.analysis)}`
|
||||
: alertData.analysis.description;
|
||||
|
||||
if (alertData.analysis.alertLevel >= 3) {
|
||||
toast.error(message, toastOptions);
|
||||
} else if (alertData.analysis.alertLevel >= 2) {
|
||||
toast.error(message, toastOptions);
|
||||
} else {
|
||||
toast(message, toastOptions);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to create short descriptions for mobile
|
||||
const getShortDescription = (analysis) => {
|
||||
if (analysis.alertLevel >= 3) return 'Critical proximity';
|
||||
if (analysis.alertLevel >= 2) return 'Approaching';
|
||||
return analysis.movement === 'approaching' ? 'Detected' : 'Movement';
|
||||
};
|
||||
|
||||
// Handle grouped notifications for mobile
|
||||
useEffect(() => {
|
||||
if (pendingNotifications.length > 0 && isMobile) {
|
||||
const timer = setTimeout(() => {
|
||||
const criticalCount = pendingNotifications.filter(n => n.analysis.alertLevel >= 3).length;
|
||||
const warningCount = pendingNotifications.filter(n => n.analysis.alertLevel === 2).length;
|
||||
const infoCount = pendingNotifications.filter(n => n.analysis.alertLevel < 2).length;
|
||||
|
||||
if (criticalCount > 0) {
|
||||
toast.error(`🚨 ${criticalCount} critical alert${criticalCount > 1 ? 's' : ''}`, {
|
||||
duration: 5000,
|
||||
style: { background: '#fee2e2', fontSize: '13px' }
|
||||
});
|
||||
} else if (warningCount > 0) {
|
||||
toast.error(`⚠️ ${warningCount} warning${warningCount > 1 ? 's' : ''}`, {
|
||||
duration: 3000,
|
||||
style: { background: '#fef3c7', fontSize: '13px' }
|
||||
});
|
||||
} else if (infoCount > 0) {
|
||||
toast(`📍 ${infoCount} detection${infoCount > 1 ? 's' : ''}`, {
|
||||
duration: 2000,
|
||||
style: { background: '#e0f2fe', fontSize: '13px' }
|
||||
});
|
||||
}
|
||||
|
||||
setPendingNotifications([]);
|
||||
}, 3000); // Group notifications for 3 seconds
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [pendingNotifications, isMobile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
// Initialize socket connection
|
||||
@@ -83,26 +187,8 @@ export const SocketProvider = ({ children }) => {
|
||||
|
||||
setMovementAlerts(prev => [alertData, ...prev.slice(0, 19)]); // Keep last 20 alerts
|
||||
|
||||
// Show priority-based notifications
|
||||
const alertIcon = alertData.analysis.alertLevel >= 3 ? '🚨' :
|
||||
alertData.analysis.alertLevel >= 2 ? '⚠️' : '📍';
|
||||
|
||||
const toastOptions = {
|
||||
duration: alertData.analysis.alertLevel >= 2 ? 10000 : 6000,
|
||||
icon: alertIcon,
|
||||
style: {
|
||||
background: alertData.analysis.alertLevel >= 3 ? '#fee2e2' :
|
||||
alertData.analysis.alertLevel >= 2 ? '#fef3c7' : '#e0f2fe'
|
||||
}
|
||||
};
|
||||
|
||||
if (alertData.analysis.alertLevel >= 3) {
|
||||
toast.error(alertData.analysis.description, toastOptions);
|
||||
} else if (alertData.analysis.alertLevel >= 2) {
|
||||
toast.error(alertData.analysis.description, toastOptions);
|
||||
} else {
|
||||
toast(alertData.analysis.description, toastOptions);
|
||||
}
|
||||
// Mobile-friendly notification management
|
||||
handleMobileNotification(alertData);
|
||||
});
|
||||
|
||||
// Listen for device heartbeats
|
||||
@@ -164,6 +250,18 @@ export const SocketProvider = ({ children }) => {
|
||||
return droneTracking.get(trackingKey);
|
||||
};
|
||||
|
||||
// Toggle notifications function
|
||||
const toggleNotifications = () => {
|
||||
const newValue = !notificationsEnabled;
|
||||
setNotificationsEnabled(newValue);
|
||||
localStorage.setItem('notificationsEnabled', newValue.toString());
|
||||
|
||||
toast.success(
|
||||
newValue ? 'Notifications enabled' : 'Notifications disabled',
|
||||
{ duration: 2000 }
|
||||
);
|
||||
};
|
||||
|
||||
const value = {
|
||||
socket,
|
||||
connected,
|
||||
@@ -171,6 +269,8 @@ export const SocketProvider = ({ children }) => {
|
||||
deviceStatus,
|
||||
movementAlerts,
|
||||
droneTracking,
|
||||
notificationsEnabled,
|
||||
toggleNotifications,
|
||||
joinDeviceRoom,
|
||||
leaveDeviceRoom,
|
||||
clearRecentDetections,
|
||||
|
||||
Reference in New Issue
Block a user