feat: 관리자 페이지 추가 (공지사항, 다운로드, 유저 관리)

- /admin 라우트 추가 (admin 권한 전용)
- 공지사항 CRUD, 다운로드 정보 수정, 유저 권한/삭제 관리
- AuthContext에 role 추가 및 localStorage 저장
- 홈 헤더에 admin 링크 표시 (admin만 노출)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 14:52:28 +09:00
parent 9fa665c9c0
commit 1359c38222
11 changed files with 619 additions and 6 deletions

View File

@@ -0,0 +1,49 @@
import { useState, useEffect } from 'react';
import { getUsers, updateUserRole, deleteUser } from '../../api/users';
import { useAuth } from '../../context/AuthContext';
import './AdminCommon.css';
export default function UserAdmin() {
const [users, setUsers] = useState([]);
const { user: me } = useAuth();
const load = () => getUsers().then(setUsers);
useEffect(() => { load(); }, []);
const handleRoleToggle = async (u) => {
const newRole = u.role === 'admin' ? 'user' : 'admin';
if (!confirm(`${u.username}의 권한을 ${newRole}로 변경하시겠습니까?`)) return;
await updateUserRole(u.id, newRole);
load();
};
const handleDelete = async (u) => {
if (!confirm(`${u.username} 계정을 삭제하시겠습니까?`)) return;
await deleteUser(u.id);
load();
};
return (
<div className="admin-section">
<h2 className="admin-section-title">유저 관리</h2>
<ul className="admin-list">
{users.map((u) => (
<li key={u.id} className="admin-list-item">
<div className="admin-list-info">
<span className="admin-list-title">{u.username}</span>
<span className={`admin-role-badge ${u.role}`}>{u.role}</span>
</div>
{u.username !== me?.username && (
<div className="admin-list-actions">
<button className="btn-admin-edit" onClick={() => handleRoleToggle(u)}>
{u.role === 'admin' ? '일반으로' : '관리자로'}
</button>
<button className="btn-admin-delete" onClick={() => handleDelete(u)}>삭제</button>
</div>
)}
</li>
))}
</ul>
</div>
);
}