diff --git a/backend/src/index.js b/backend/src/index.js index 416bb9c..1bd7ad1 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -83,6 +83,10 @@ app.put('/api/plates/:id/approve', authenticateToken, isAdmin, async (req, res) where: { id: parseInt(id) }, data: { status } }); + + // Notify Users via WebSocket + io.emit('plate_status_updated', plate); + res.json(plate); } catch (err) { res.status(500).json({ error: err.message }); @@ -219,6 +223,10 @@ app.post('/api/people/bulk-approve', authenticateToken, isAdmin, async (req, res where: { addedById: parseInt(userId), status: 'PENDING' }, data: { status: 'APPROVED' } }); + + // Notify Users via WebSocket + io.emit('people_updated', { userId }); + res.json({ message: 'Bulk approval successful' }); } catch (err) { res.status(500).json({ error: err.message }); diff --git a/frontend/src/pages/AdminDashboard.jsx b/frontend/src/pages/AdminDashboard.jsx index 34e36f5..35d5f3b 100644 --- a/frontend/src/pages/AdminDashboard.jsx +++ b/frontend/src/pages/AdminDashboard.jsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import axios from 'axios'; import io from 'socket.io-client'; -import { Users, CheckCircle, XCircle, Shield, Trash2, Camera, Clock, Calendar } from 'lucide-react'; +import { Users, CheckCircle, XCircle, Shield, Trash2, Camera, Clock, Calendar, AlertCircle } from 'lucide-react'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; const socket = io(API_URL); @@ -20,6 +20,8 @@ function AdminDashboard({ token }) { // Visitor State const [activePeople, setActivePeople] = useState([]); + const [searchRut, setSearchRut] = useState(''); + const [searchResult, setSearchResult] = useState(null); // null | { found: true, data: ... } | { found: false } useEffect(() => { fetchData(); @@ -77,6 +79,18 @@ function AdminDashboard({ token }) { } }; + const handleSearchRut = (e) => { + e.preventDefault(); + const normalizedRut = searchRut.replace(/\./g, '').toUpperCase(); + const found = activePeople.find(p => p.rut.toUpperCase() === normalizedRut); + + if (found) { + setSearchResult({ found: true, data: found }); + } else { + setSearchResult({ found: false }); + } + }; + const handleCreateUser = async (e) => { e.preventDefault(); try { @@ -181,6 +195,63 @@ function AdminDashboard({ token }) { + {/* Visitor Lookup Banner */} +
+ Authorized by: @{searchResult.data.addedBy?.username || 'Unknown'} +
+This RUT is not listed in the visitor registry.
+