diff --git a/client/src/App.jsx b/client/src/App.jsx index 9e1ed51..78afa4c 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -2,6 +2,7 @@ import { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom'; import CreateEvent from './components/CreateEvent'; import EventPoll from './components/EventPoll'; import AnalyticsDashboard from './components/AnalyticsDashboard'; +import AdminDashboard from './components/AdminDashboard'; function Layout() { return ( @@ -27,6 +28,7 @@ function App() { } /> } /> } /> + } /> diff --git a/client/src/components/AdminDashboard.jsx b/client/src/components/AdminDashboard.jsx new file mode 100644 index 0000000..c2322d1 --- /dev/null +++ b/client/src/components/AdminDashboard.jsx @@ -0,0 +1,148 @@ +import { useState } from 'react'; +import { motion } from 'framer-motion'; +import { format, parseISO } from 'date-fns'; + +export default function AdminDashboard() { + const [password, setPassword] = useState(''); + const [events, setEvents] = useState(null); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(false); + + const handleLogin = async (e) => { + e.preventDefault(); + setLoading(true); + setError(''); + + try { + const res = await fetch('/api/admin/events', { + headers: { 'x-admin-password': password }, + }); + + if (res.status === 401) { + setError('Invalid password'); + setEvents(null); + } else if (res.ok) { + const data = await res.json(); + setEvents(data.events); + } else { + setError('Failed to load events'); + } + } catch (err) { + setError('Network error'); + } finally { + setLoading(false); + } + }; + + if (!events) { + return ( + +
+

Admin Login

+
+
+ + setPassword(e.target.value)} + placeholder="Enter admin password" + className="w-full px-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent outline-none transition-all text-slate-800" + required + /> +
+ {error && ( +

{error}

+ )} + +
+
+
+ ); + } + + const origin = typeof window !== 'undefined' ? window.location.origin : ''; + + return ( + +
+
+

All Events

+ +
+ + {events.length === 0 ? ( +

No events yet.

+ ) : ( +
+ + + + + + + + + + {events.map((event) => ( + + + + + + ))} + +
EventDatesLinks
+
{event.name}
+ {event.description && ( +
{event.description}
+ )} +
+ {format(parseISO(event.start_date), 'MMM d')} - {format(parseISO(event.end_date), 'MMM d, yyyy')} + + +
+
+ )} +
+
+ ); +} diff --git a/server/routes.js b/server/routes.js index f5d19c0..218d044 100644 --- a/server/routes.js +++ b/server/routes.js @@ -108,4 +108,22 @@ router.get('/events/:id/analytics', (req, res) => { } }); +// Admin: Get All Events (password protected) +router.get('/admin/events', (req, res) => { + const password = req.headers['x-admin-password']; + const adminPassword = process.env.ADMIN_PASSWORD || '123456'; + + if (password !== adminPassword) { + return res.status(401).json({ error: 'Unauthorized' }); + } + + try { + const events = db.prepare('SELECT id, name, description, start_date, end_date, created_at FROM events ORDER BY created_at DESC').all(); + res.json({ events }); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Failed to retrieve events' }); + } +}); + module.exports = router;