Initial commit
This commit is contained in:
134
client/src/contexts/SocketContext.jsx
Normal file
134
client/src/contexts/SocketContext.jsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { io } from 'socket.io-client';
|
||||
import { useAuth } from './AuthContext';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const SocketContext = createContext();
|
||||
|
||||
export const SocketProvider = ({ children }) => {
|
||||
const [socket, setSocket] = useState(null);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const [recentDetections, setRecentDetections] = useState([]);
|
||||
const [deviceStatus, setDeviceStatus] = useState({});
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
// Initialize socket connection
|
||||
const newSocket = io(process.env.NODE_ENV === 'production'
|
||||
? window.location.origin
|
||||
: 'http://localhost:3001'
|
||||
);
|
||||
|
||||
newSocket.on('connect', () => {
|
||||
console.log('Connected to server');
|
||||
setConnected(true);
|
||||
|
||||
// Join dashboard room for general updates
|
||||
newSocket.emit('join_dashboard');
|
||||
|
||||
toast.success('Connected to real-time updates');
|
||||
});
|
||||
|
||||
newSocket.on('disconnect', () => {
|
||||
console.log('Disconnected from server');
|
||||
setConnected(false);
|
||||
toast.error('Disconnected from server');
|
||||
});
|
||||
|
||||
newSocket.on('connect_error', (error) => {
|
||||
console.error('Connection error:', error);
|
||||
setConnected(false);
|
||||
toast.error('Failed to connect to server');
|
||||
});
|
||||
|
||||
// Listen for drone detections
|
||||
newSocket.on('drone_detection', (detection) => {
|
||||
console.log('New drone detection:', detection);
|
||||
|
||||
setRecentDetections(prev => [detection, ...prev.slice(0, 49)]); // Keep last 50
|
||||
|
||||
// Show toast notification
|
||||
toast.error(
|
||||
`Drone detected by ${detection.device.name || `Device ${detection.device_id}`}`,
|
||||
{
|
||||
duration: 5000,
|
||||
icon: '🚨',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Listen for device heartbeats
|
||||
newSocket.on('device_heartbeat', (heartbeat) => {
|
||||
console.log('Device heartbeat:', heartbeat);
|
||||
|
||||
setDeviceStatus(prev => ({
|
||||
...prev,
|
||||
[heartbeat.device_id]: {
|
||||
...heartbeat,
|
||||
last_seen: new Date()
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// Listen for device updates
|
||||
newSocket.on('device_updated', (device) => {
|
||||
console.log('Device updated:', device);
|
||||
toast.success(`Device ${device.name || device.id} updated`);
|
||||
});
|
||||
|
||||
setSocket(newSocket);
|
||||
|
||||
return () => {
|
||||
newSocket.disconnect();
|
||||
};
|
||||
} else {
|
||||
// Disconnect if not authenticated
|
||||
if (socket) {
|
||||
socket.disconnect();
|
||||
setSocket(null);
|
||||
setConnected(false);
|
||||
}
|
||||
}
|
||||
}, [isAuthenticated]);
|
||||
|
||||
const joinDeviceRoom = (deviceId) => {
|
||||
if (socket) {
|
||||
socket.emit('join_device_room', deviceId);
|
||||
}
|
||||
};
|
||||
|
||||
const leaveDeviceRoom = (deviceId) => {
|
||||
if (socket) {
|
||||
socket.emit('leave_device_room', deviceId);
|
||||
}
|
||||
};
|
||||
|
||||
const clearRecentDetections = () => {
|
||||
setRecentDetections([]);
|
||||
};
|
||||
|
||||
const value = {
|
||||
socket,
|
||||
connected,
|
||||
recentDetections,
|
||||
deviceStatus,
|
||||
joinDeviceRoom,
|
||||
leaveDeviceRoom,
|
||||
clearRecentDetections
|
||||
};
|
||||
|
||||
return (
|
||||
<SocketContext.Provider value={value}>
|
||||
{children}
|
||||
</SocketContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useSocket = () => {
|
||||
const context = useContext(SocketContext);
|
||||
if (!context) {
|
||||
throw new Error('useSocket must be used within a SocketProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
Reference in New Issue
Block a user