feat: implementar dashboard de administración - #32
Conversation
…ion mismatch - Sidebar: nodo admin debajo de team, visible solo para isAdmin - TerminalWindow: recibe session prop desde layout - layout.tsx: pasa session a TerminalWindow - Corrige hydration mismatch usando session estable del servidor - Backend de usuarios ya listo en /api/admin/users
…hydration mismatch)
…ers, Announcements, Game Configuration)
- src/components/UsersView.tsx: tabla con alias, name, isAdmin, isTeamLeader, team, counts - Edicion inline (PATCH): name, isAdmin, isTeamLeader - Eliminacion (DELETE) con confirmacion - Mensajes toast de confirmacion - Integrado en AdminDashboard tab Users
…checkboxes mas grandes - No se puede editar ni eliminar tu propio usuario - Selector de equipo (teamId) en modo edicion - Checkboxes de admin/team leader mas grandes (18px) - currentUserId pasado desde AdminDashboard
- /api/admin/teams/route.ts: GET lista equipos con member count - /api/admin/teams/[id]/route.ts: PATCH edita nombre, DELETE elimina equipo - DELETE: remueve teamId de miembros (no borra usuarios) - Protegido con session.user.isAdmin
- src/components/TeamsView.tsx: tabla con name, code, score, member count, created - Edicion inline (PATCH): solo nombre del equipo - Eliminacion (DELETE): remueve teamId de miembros, no borra usuarios - Tab Teams integrado en AdminDashboard
- /api/admin/export/route.ts: GET exporta users, teams, challenges, announcements, gameConfig - POST importa con transaction (all-or-nothing) - Protegido con session.user.isAdmin - Formato JSON
- Export All: descarga JSON con todos los datos - Import: file input que envia JSON al backend - Botones en esquina superior derecha, al lado de Admin Panel - Mensajes toast de confirmacion
- /api/admin/rules/route.ts: GET/POST usando SiteConfig (key: rules_text) - RulesView.tsx: textarea para editar reglas con Markdown - Tab Rules integrado en AdminDashboard - Protegido con session.user.isAdmin
- /api/rules/route.ts: GET publico que lee SiteConfig (rules_text) - Conecta con RulesView del usuario (dashboard) - Solo admins editan via /api/admin/rules - Usuarios ven reglas via /api/rules
- /api/admin/rules y /api/rules ahora usan key 'rules' - No borra reglas preexistentes del seed - Reglas visibles en admin para editar y en dashboard para usuarios
- /api/rules usaba 'rules_text' en lugar de 'rules' (key del seed) - Ahora las reglas aparecen correctamente en el dashboard para usuarios - RulesView del usuario usa fetch con cache: no-store (sin cache)
- /api/admin/announcements: GET lista anuncios - /api/admin/announcements/[id]: DELETE elimina anuncio - AdminDashboard: listado de anuncios con titulo, contenido, fecha/hora y boton delete - Carga inicial de anuncios en useEffect - Estilo CRT mantenido
- GameTimer.tsx: cronometro que muestra tiempo restante (antes/inicio/despues/infinito) - /api/game: endpoint publico para gameConfig (sin requerir admin) - Game Configuration: valores por defecto (hoy+1h, +24h), END auto-recalculado - localStorage: guarda ultima configuracion para futuras ediciones - Mensajes de ayuda en espanol sobre reglas de tiempo - TerminalOutput: integra GameTimer al inicio del dashboard
- /api/admin/submissions: GET lista submissions con user, team, challenge - SubmissionsView.tsx: tabla con Time, Team, User, Challenge, Flag, Correct - Tab Submissions en AdminDashboard - Seed: submissions de ejemplo (1 correcto, 1 incorrecto)
- /api/admin/logs: GET lista activity logs - LogsView.tsx: tabla con Type, Description, Team, Time - Tab Logs en AdminDashboard - Colores de tabs morados (#8a2be2) - Teams: color aleatorio al crear (8 colores cyberpunk) - Seed: logs de ejemplo - Lint warning corregido
- LoadingSpinner: logo 200px, temblor Watch Dogs 2 (40ms), particulas alrededor - Reemplaza Loading... en UsersView, TeamsView, SubmissionsView, LogsView - Imagen ~/Descargas/imagen-invertida.png en /public/ - Estilo CRT mantenido
- AdminDashboard: LoadingSpinner en challenges y announcements tabs - RulesView: LoadingSpinner en lugar de texto - LoadingSpinner1: partículas cercanas a la imagen - LoadingSpinner2: partículas cercanas + animacion abrir/cerrar boca - Imagenes reemplazadas con versiones editadas
- LoadingSpinner3: GIF con efecto glitch, sin temblor - LoadingSpinner4: GIF con recorte de bordes (clipPath inset 10%) - LoadingSpinner: randomiza entre 4 spinners (25% cada uno) - public/loading-gif.gif y loading-gif-2.gif agregados
…abs en AdminDashboard Los cards de 'Game Configuration' y 'New Announcement' estaban renderizados tanto en la seccion de superior (fuera de los tabs) como dentro de sus tabs correspondientes, causando duplicacion visual. Se eliminan las versiones duplicadas que estaban fuera de los tabs, manteniendo solo las versiones dentro de cada tab. Resuelve el merge conflict de feature/dashboard-vistas-gestion con origin/dev.
Stevenjoelrs
left a comment
There was a problem hiding this comment.
Problemas adicionales con la estructura:
- RulesView.tsx duplicado (raíz y views/)
- Admin views sueltos en raíz mezclados con todo
- Spinners ocupan 5 archivos en la raíz
- Terminal-related podrían agruparse
te recomendaria reorganizarlo y que termine asi:
src/components/
├── admin/
│ ├── AdminDashboard.tsx
│ ├── UsersView.tsx
│ ├── TeamsView.tsx
│ ├── SubmissionsView.tsx
│ ├── LogsView.tsx
│ ├── RulesView.tsx
│ └── GameTimer.tsx
│
├── terminal/
│ ├── TerminalWindow.tsx
│ ├── TerminalInput.tsx
│ ├── TerminalOutput.tsx
│ └── CRTSettings.tsx
│
├── ui/
│ ├── LoadingSpinner.tsx
│ ├── LoadingSpinner1.tsx
│ ├── LoadingSpinner2.tsx
│ ├── LoadingSpinner3.tsx
│ └── LoadingSpinner4.tsx
│
├── views/
│ ├── CategoryView.tsx
│ ├── RulesView.tsx
│ ├── ScoreboardView.tsx
│ └── TeamView.tsx
│
├── Background3D.tsx
├── ChallengeView.tsx
├── Providers.tsx
├── Sidebar.tsx
├── StatusBar.tsx
| } | ||
|
|
||
| if (gameConfig) { | ||
| // Delete existing game config |
There was a problem hiding this comment.
antes de importar debería de haber una confirmación, mas que nada por seguridad
| updatedAt: true, | ||
| }, | ||
| }), | ||
| prisma.user.findMany({ |
There was a problem hiding this comment.
no se estan exportando los usuarios con el dato de la contraseña, al momento de importar estos usuarios se rompen
|
|
||
| // PATCH /api/admin/users/[id] - Update user properties (admin, team leader status, name) | ||
| // Admin-only endpoint to modify user information | ||
| export async function PATCH( |
There was a problem hiding this comment.
este patch esta ignorando el teamId, el frontend lo envía pero como aquí no esta eso no se actualiza cuando se cambia de equipo desde el dashboard de admin
| } | ||
|
|
||
| // Validate name length if provided | ||
| if (name && name.length > 48) { |
There was a problem hiding this comment.
en lo que uses como acá mejor usa name !== undefined && { name } como sí hacen otras rutas
There was a problem hiding this comment.
tus toggle/delete muestran el toast de éxito sin antes verificar si el resultado fue exitoso
There was a problem hiding this comment.
estas mezclando inline styles + CSS classes, colores hardcodeados en vez de variables de CSS
There was a problem hiding this comment.
tienes un eslint-disable innecesario — loadLogs ya tiene useCallback([])
There was a problem hiding this comment.
Flash del primer spinner antes del useEffect inicializalo en null
There was a problem hiding this comment.
estas importando PrismaClient directo en vez de usar el singleton de @/lib/prisma
There was a problem hiding this comment.
Solo permite editar nombre — no soporta icon, color, code, te recomendaría agregar eso mas
| @@ -36,12 +52,54 @@ export default function AdminDashboard() { | |||
| const [creating, setCreating] = useState(false); | |||
|
|
|||
| // Game config | |||

Cambios
Relacionado con #1