Primera version de frontend

This commit is contained in:
2025-07-28 11:00:25 -06:00
parent 748e37cbcc
commit 0dac802736
78 changed files with 18757 additions and 0 deletions

73
src/hooks/usePolling.js Normal file
View File

@@ -0,0 +1,73 @@
import { useState, useEffect, useRef } from 'react';
export function usePolling(fetchFunction, interval = 30000, dependencies = []) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const intervalRef = useRef(null);
const isActiveRef = useRef(true);
const fetchData = async (showLoading = false) => {
if (showLoading) setLoading(true);
setError(null);
try {
const result = await fetchFunction();
if (isActiveRef.current) {
setData(result);
setLoading(false);
}
} catch (err) {
if (isActiveRef.current) {
setError(err);
setLoading(false);
}
}
};
const startPolling = () => {
if (intervalRef.current) return; // Ya está corriendo
fetchData(true); // Fetch inicial
intervalRef.current = setInterval(() => {
if (isActiveRef.current) {
fetchData(false); // Fetch sin loading para no molestar al usuario
}
}, interval);
};
const stopPolling = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
};
const refetch = () => {
fetchData(true);
};
useEffect(() => {
isActiveRef.current = true;
startPolling();
// Parar polling cuando el componente se desmonta o la pestaña no está visible
const handleVisibilityChange = () => {
if (document.hidden) {
stopPolling();
} else {
startPolling();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
isActiveRef.current = false;
stopPolling();
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, dependencies);
return { data, loading, error, refetch, startPolling, stopPolling };
}

49
src/hooks/useWebSocket.js Normal file
View File

@@ -0,0 +1,49 @@
import { useEffect, useState, useRef } from 'react';
import { io } from 'socket.io-client';
export function useWebSocket(url, events = {}) {
const [isConnected, setIsConnected] = useState(false);
const socketRef = useRef(null);
useEffect(() => {
// Conectar WebSocket
socketRef.current = io(url, {
transports: ['websocket'],
auth: {
token: localStorage.getItem('access')
}
});
const socket = socketRef.current;
socket.on('connect', () => {
console.log('WebSocket conectado');
setIsConnected(true);
});
socket.on('disconnect', () => {
console.log('WebSocket desconectado');
setIsConnected(false);
});
// Registrar eventos personalizados
Object.entries(events).forEach(([eventName, handler]) => {
socket.on(eventName, handler);
});
return () => {
Object.keys(events).forEach(eventName => {
socket.off(eventName);
});
socket.disconnect();
};
}, [url]);
const emit = (eventName, data) => {
if (socketRef.current && isConnected) {
socketRef.current.emit(eventName, data);
}
};
return { isConnected, emit };
}