관리자 페이지
서버 관리 및 설정
로그 파일
{file.name}
{file.size}
{player.name}
{/* 액션 버튼 */}/** * 관리자 페이지 * - 탭 UI: 콘솔 / 플레이어 / 설정 */ import { useEffect, useState, useRef } from 'react'; import { useNavigate, useLocation, Link } from 'react-router-dom'; import { useAuth } from '../contexts/AuthContext'; import { Shield, ArrowLeft, Loader2, Terminal, Users, Settings, Send, Ban, UserX, Crown, Sun, Moon, Cloud, CloudRain, CloudLightning, ChevronDown, FileText, Download, Trash2, Check } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; // 더미 로그 데이터 const DUMMY_LOGS = [ { time: '15:01:23', type: 'info', message: '[Server] Starting minecraft server version 1.21.1' }, { time: '15:01:24', type: 'info', message: '[Server] Loading properties' }, { time: '15:01:25', type: 'info', message: '[Server] Preparing level "world"' }, { time: '15:01:28', type: 'info', message: '[Server] Done (3.245s)! For help, type "help"' }, { time: '15:05:12', type: 'info', message: '[Server] 비머[/127.0.0.1:54321] logged in' }, { time: '15:05:15', type: 'info', message: '[Server] 비머 joined the game' }, { time: '15:10:30', type: 'warning', message: '[Server] Can\'t keep up! Is the server overloaded?' }, { time: '15:15:00', type: 'info', message: '[Server] 비머부캐 joined the game' }, ]; // 더미 로그 파일 데이터 const DUMMY_LOG_FILES = [ { name: '2024-12-22.log', size: '2.4 MB', date: '2024-12-22' }, { name: '2024-12-21.log', size: '1.8 MB', date: '2024-12-21' }, { name: '2024-12-20.log', size: '3.1 MB', date: '2024-12-20' }, ]; // 더미 플레이어 데이터 const DUMMY_PLAYERS = [ { uuid: '1234-5678-9012-3456', name: '비머', isOnline: true, isOp: true }, { uuid: '2345-6789-0123-4567', name: '비머부캐', isOnline: true, isOp: false }, { uuid: '3456-7890-1234-5678', name: 'Steve', isOnline: false, isOp: false }, { uuid: '4567-8901-2345-6789', name: 'Alex', isOnline: false, isOp: false }, ]; // 더미 게임규칙 데이터 const DUMMY_GAMERULES = [ { name: 'keepInventory', value: false, label: '인벤토리 유지' }, { name: 'doDaylightCycle', value: true, label: '낮/밤 주기' }, { name: 'doMobSpawning', value: true, label: '몹 스폰' }, { name: 'doFireTick', value: true, label: '불 번짐' }, { name: 'mobGriefing', value: true, label: '몹 그리핑' }, { name: 'pvp', value: true, label: 'PvP' }, ]; export default function Admin({ isMobile = false }) { const { isLoggedIn, isAdmin, user, loading } = useAuth(); const navigate = useNavigate(); const location = useLocation(); const [toast, setToast] = useState(null); // 탭 상태 const [activeTab, setActiveTab] = useState('console'); // 콘솔 관련 상태 const [logs, setLogs] = useState(DUMMY_LOGS); const [command, setCommand] = useState(''); const [logFiles] = useState(DUMMY_LOG_FILES); const logEndRef = useRef(null); // 플레이어 관련 상태 const [players, setPlayers] = useState(DUMMY_PLAYERS); const [playerFilter, setPlayerFilter] = useState('all'); // all, online, offline, banned const [selectedPlayer, setSelectedPlayer] = useState(null); const [showPlayerDialog, setShowPlayerDialog] = useState(false); const [dialogAction, setDialogAction] = useState(null); // kick, ban, op const [actionReason, setActionReason] = useState(''); // 설정 관련 상태 const [gamerules, setGamerules] = useState(DUMMY_GAMERULES); const [difficulty, setDifficulty] = useState('normal'); const [timeOfDay, setTimeOfDay] = useState('day'); const [weather, setWeather] = useState('clear'); // 권한 확인 useEffect(() => { if (!loading) { if (!isLoggedIn) { navigate('/login', { state: { from: location.pathname } }); } else if (!isAdmin) { setToast('관리자 권한이 필요합니다.'); setTimeout(() => navigate('/'), 1500); } } }, [isLoggedIn, isAdmin, loading, navigate, location.pathname]); // 토스트 자동 숨기기 useEffect(() => { if (toast) { const timer = setTimeout(() => setToast(null), 3000); return () => clearTimeout(timer); } }, [toast]); // 로그 스크롤 useEffect(() => { logEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [logs]); // 명령어 실행 (더미) const handleCommand = () => { if (!command.trim()) return; const newLogs = [ { time: new Date().toLocaleTimeString('ko-KR', { hour12: false }), type: 'command', message: `> ${command}` }, { time: new Date().toLocaleTimeString('ko-KR', { hour12: false }), type: 'info', message: `[Server] 명령어 실행됨: ${command}` } ]; setLogs(prev => [...prev, ...newLogs]); setCommand(''); setToast('명령어가 실행되었습니다.'); }; // 플레이어 액션 핸들러 const handlePlayerAction = () => { if (!selectedPlayer || !dialogAction) return; let message = ''; switch (dialogAction) { case 'kick': message = `${selectedPlayer.name}님을 추방했습니다.`; break; case 'ban': message = `${selectedPlayer.name}님을 차단했습니다.`; break; case 'op': const isOp = players.find(p => p.uuid === selectedPlayer.uuid)?.isOp; setPlayers(prev => prev.map(p => p.uuid === selectedPlayer.uuid ? { ...p, isOp: !isOp } : p )); message = isOp ? `${selectedPlayer.name}님의 OP를 해제했습니다.` : `${selectedPlayer.name}님에게 OP를 부여했습니다.`; break; } setShowPlayerDialog(false); setSelectedPlayer(null); setDialogAction(null); setActionReason(''); setToast(message); }; // 게임규칙 토글 const toggleGamerule = (name) => { setGamerules(prev => prev.map(rule => rule.name === name ? { ...rule, value: !rule.value } : rule )); setToast('게임규칙이 변경되었습니다.'); }; // 로그 색상 const getLogColor = (type) => { switch (type) { case 'error': return 'text-red-400'; case 'warning': return 'text-yellow-400'; case 'command': return 'text-mc-green'; default: return 'text-zinc-300'; } }; // 필터된 플레이어 const filteredPlayers = players.filter(p => { if (playerFilter === 'online') return p.isOnline; if (playerFilter === 'offline') return !p.isOnline; return true; }); if (loading) { return (
서버 관리 및 설정
{file.name}
{file.size}
{player.name}
{/* 액션 버튼 */}{selectedPlayer.name}
{selectedPlayer.uuid}