diff --git a/Admin.tsx b/Admin.tsx index c6a1f30..f7338a0 100644 --- a/Admin.tsx +++ b/Admin.tsx @@ -1,15 +1,17 @@ - import React, { useState, useEffect, useRef, useMemo } from 'react'; -import { X, Edit3, Trash2, Shield, ShieldCheck, ShieldAlert, Skull, Newspaper, Download, Upload, Database, Save, History, Plus, Globe, User, ShieldX, UserMinus, UserCheck, Medal, CheckCircle2 } from 'lucide-react'; +import { X, Edit3, Trash2, Shield, ShieldCheck, ShieldAlert, Skull, Newspaper, Download, Upload, Database, Save, History, Plus, Globe, User, ShieldX, UserMinus, UserCheck, Medal, CheckCircle2, Settings, Flag, Wrench, LayoutGrid, RefreshCw } from 'lucide-react'; import { useCTF } from './CTFContext'; import { Challenge, Team, BlogPost, Difficulty, ChallengeFile } from './types'; import { Button, Countdown, CategoryIcon } from './UIComponents'; import { CATEGORIES, DIFFICULTIES } from './constants'; import { calculateChallengeValue, getFirstBloodBonusFactor } from './services/scoring'; +type AdminTab = 'GENERAL' | 'CHALLENGES' | 'BLOG' | 'PLAYERS' | 'TOOLS'; + export const Admin: React.FC = () => { const { state, toggleCtf, resetScores, upsertChallenge, deleteChallenge, deleteAllChallenges, updateTeam, deleteTeam, deleteSolve, createBlogPost, updateBlogPost, deleteBlogPost, updateConfig, exportChallenges, importChallenges, backupDatabase, restoreDatabase, refreshState } = useCTF(); + const [activeTab, setActiveTab] = useState('GENERAL'); const [editingChallenge, setEditingChallenge] = useState | null>(null); const [editingTeam, setEditingTeam] = useState & { newPassword?: string } | null>(null); const [editingBlogPost, setEditingBlogPost] = useState | null>(null); @@ -105,222 +107,338 @@ export const Admin: React.FC = () => { await updateTeam(team.id, { ...team, isDisabled: !team.isDisabled }); }; + const menuItems: { id: AdminTab; label: string; icon: React.ReactNode }[] = [ + { id: 'GENERAL', label: 'General', icon: }, + { id: 'CHALLENGES', label: 'Challenges', icon: }, + { id: 'BLOG', label: 'Blog', icon: }, + { id: 'PLAYERS', label: 'Players', icon: }, + { id: 'TOOLS', label: 'Tools', icon: }, + ]; + return ( -
-
-
- {isBeforeStart && ( -
- +
+
+ {/* Sidebar */} +
-
-
-
-

GENERAL_CONFIG

-
-
-
- - setLocalConf({...localConf, conferenceName: e.target.value})} /> -
-
-
- - { const val = fromUTCDisplay(e.target.value); if (val) setLocalConf({...localConf, eventStartTime: val}); }} /> + {menuItems.map((item) => ( + + ))} + +
+
+ {isBeforeStart && ( +
+
-
- - { const val = fromUTCDisplay(e.target.value); if (val) setLocalConf({...localConf, eventEndTime: val}); }} /> -
-
-
- - setLocalConf({...localConf, dockerIp: e.target.value})} /> -
-
- -