From b91de06e29aa74c7d16db0bb48e70331886baba1 Mon Sep 17 00:00:00 2001 From: raven Date: Sun, 28 Dec 2025 19:27:51 -0300 Subject: [PATCH] Correccion de dashboar usuarios y admins --- backend/src/index.js | 8 +- frontend/src/pages/AdminDashboard.jsx | 124 +++++++++++++++++++++++++- frontend/src/pages/UserDashboard.jsx | 34 +------ 3 files changed, 128 insertions(+), 38 deletions(-) diff --git a/backend/src/index.js b/backend/src/index.js index 991c85f..e32061f 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -31,11 +31,11 @@ app.use('/api/auth', authRoutes); // Plates CRUD app.get('/api/plates', authenticateToken, async (req, res) => { try { - // Users see their own plates? Or all? - // Requirement: "usuarios al agregar nuevas patentes, deberan ser permitidas por el administrador" - // Let's users see all but maybe status distinguishes them. - // For now, let's return all. + // Filter based on role + const where = req.user.role === 'ADMIN' ? {} : { addedById: req.user.id }; + const plates = await prisma.plate.findMany({ + where, include: { addedBy: { select: { username: true } } } }); res.json(plates); diff --git a/frontend/src/pages/AdminDashboard.jsx b/frontend/src/pages/AdminDashboard.jsx index da5527c..4a3fd32 100644 --- a/frontend/src/pages/AdminDashboard.jsx +++ b/frontend/src/pages/AdminDashboard.jsx @@ -1,28 +1,64 @@ import { useState, useEffect } from 'react'; import axios from 'axios'; -import { Users, CheckCircle, XCircle, Shield, Trash2 } from 'lucide-react'; +import io from 'socket.io-client'; +import { Users, CheckCircle, XCircle, Shield, Trash2, Camera, Clock, Calendar } from 'lucide-react'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; +const socket = io(API_URL); function AdminDashboard({ token }) { const [users, setUsers] = useState([]); const [plates, setPlates] = useState([]); const [newUser, setNewUser] = useState({ username: '', password: '', role: 'USER' }); - const [activeTab, setActiveTab] = useState('plates'); // 'plates' | 'users' + const [activeTab, setActiveTab] = useState('monitor'); // 'monitor' | 'plates' | 'users' + + // Monitor State + const [detections, setDetections] = useState([]); + const [historyLogs, setHistoryLogs] = useState([]); + const [viewMode, setViewMode] = useState('live'); // 'live' | 'history' + const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]); useEffect(() => { fetchData(); + + // Live detection listener + socket.on('new_detection', (data) => { + setDetections(prev => [data, ...prev].slice(0, 10)); + }); + + return () => socket.off('new_detection'); }, [token]); + useEffect(() => { + if (viewMode === 'history' && activeTab === 'monitor') { + fetchHistory(selectedDate); + } + }, [viewMode, selectedDate, activeTab]); + const fetchData = async () => { try { const authHeader = { headers: { Authorization: `Bearer ${token}` } }; - const [usersRes, platesRes] = await Promise.all([ + const [usersRes, platesRes, recentRes] = await Promise.all([ axios.get(`${API_URL}/api/auth`, authHeader).catch(err => ({ data: [] })), - axios.get(`${API_URL}/api/plates`, authHeader) + axios.get(`${API_URL}/api/plates`, authHeader), + axios.get(`${API_URL}/api/recent`, authHeader) ]); setUsers(usersRes.data); setPlates(platesRes.data); + setDetections(recentRes.data.map(log => ({ + plate: log.plateNumber, + status: log.accessStatus, + timestamp: log.timestamp + }))); + } catch (err) { + console.error(err); + } + }; + + const fetchHistory = async (date) => { + try { + const res = await axios.get(`${API_URL}/api/history?date=${date}`); + setHistoryLogs(res.data); } catch (err) { console.error(err); } @@ -65,6 +101,15 @@ function AdminDashboard({ token }) { } }; + const StatusBadge = ({ status }) => ( + + {status} + + ); + return (
@@ -74,6 +119,12 @@ function AdminDashboard({ token }) { Admin Portal
+
+ {activeTab === 'monitor' && ( +
+
+

+ Live Monitor +

+
+ + +
+
+ + {viewMode === 'live' ? ( +
+
+ e.target.style.display = 'none'} + /> +
LIVE
+
+
+

Recent Detections

+
+ {detections.map((d, i) => ( +
+ {d.plate} +
+ {new Date(d.timestamp).toLocaleTimeString()} + +
+
+ ))} +
+
+
+ ) : ( +
+
+ setSelectedDate(e.target.value)} + className="bg-slate-900 border border-slate-600 rounded px-4 py-2" + /> +
+
+ {historyLogs.map(log => ( +
+
+ {log.plateNumber} + {new Date(log.timestamp).toLocaleString()} +
+ +
+ ))} + {historyLogs.length === 0 &&

No logs found for this date.

} +
+
+ )} +
+ )} + {activeTab === 'plates' && (

Pending Approvals

@@ -128,6 +243,7 @@ function AdminDashboard({ token }) {
{plate.number}
{plate.owner}
+
Added by: {plate.addedBy?.username || 'System'}
{plate.status} diff --git a/frontend/src/pages/UserDashboard.jsx b/frontend/src/pages/UserDashboard.jsx index c3868a6..200916c 100644 --- a/frontend/src/pages/UserDashboard.jsx +++ b/frontend/src/pages/UserDashboard.jsx @@ -58,8 +58,8 @@ function UserDashboard({ token, username }) {
- {/* Left: Register & My Plates */} -
+ {/* Register & My Plates (Full Width) */} +

Welcome, {username} @@ -72,8 +72,8 @@ function UserDashboard({ token, username }) { My Registered Plates

-
- {plates.length === 0 &&

No plates registered.

} +
+ {plates.length === 0 &&

No plates registered.

} {plates.map(plate => (
@@ -126,32 +126,6 @@ function UserDashboard({ token, username }) {
- {/* Right: Live Feed Preview */} -
-
-

Live Gate Feed

-
- e.target.style.display = 'none'} - /> -
-
- -
-

Recent Activity

-
- {detections.map((d, i) => ( -
- {d.plate} - {d.status} -
- ))} -
-
-
-
);