import { useState, useEffect } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import { motion } from 'framer-motion';
import {
Disc3, Calendar, Users, LogOut,
Home, ChevronRight
} from 'lucide-react';
// 슬롯머신 스타일 롤링 숫자 컴포넌트 (아래에서 위로)
function AnimatedNumber({ value }) {
const digits = String(value).split('');
return (
{digits.map((digit, i) => (
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(n => (
{n}
))}
))}
);
}
function AdminDashboard() {
const navigate = useNavigate();
const [user, setUser] = useState(null);
const [stats, setStats] = useState({
albums: 0,
photos: 0,
schedules: 0,
members: 0
});
useEffect(() => {
// 로그인 상태 확인
const token = localStorage.getItem('adminToken');
const userData = localStorage.getItem('adminUser');
if (!token || !userData) {
navigate('/admin');
return;
}
setUser(JSON.parse(userData));
// 토큰 유효성 검증
fetch('/api/admin/verify', {
headers: { Authorization: `Bearer ${token}` }
})
.then(res => {
if (!res.ok) throw new Error('Invalid token');
return res.json();
})
.catch(() => {
localStorage.removeItem('adminToken');
localStorage.removeItem('adminUser');
navigate('/admin');
});
// 통계 데이터 가져오기
fetchStats();
}, [navigate]);
const fetchStats = async () => {
// 각 통계를 개별적으로 가져와서 하나가 실패해도 다른 것은 표시
try {
const membersRes = await fetch('/api/members');
if (membersRes.ok) {
const members = await membersRes.json();
setStats(prev => ({ ...prev, members: members.filter(m => !m.is_former).length }));
}
} catch (e) { console.error('멤버 통계 오류:', e); }
try {
const albumsRes = await fetch('/api/albums');
if (albumsRes.ok) {
const albums = await albumsRes.json();
setStats(prev => ({ ...prev, albums: albums.length }));
// 사진 수 계산
let totalPhotos = 0;
for (const album of albums) {
try {
const detailRes = await fetch(`/api/albums/${album.id}`);
if (detailRes.ok) {
const detail = await detailRes.json();
if (detail.conceptPhotos) {
Object.values(detail.conceptPhotos).forEach(photos => {
totalPhotos += photos.length;
});
}
if (detail.teasers) {
totalPhotos += detail.teasers.length;
}
}
} catch (e) { /* 개별 앨범 오류 무시 */ }
}
setStats(prev => ({ ...prev, photos: totalPhotos }));
}
} catch (e) { console.error('앨범 통계 오류:', e); }
try {
const schedulesRes = await fetch('/api/schedules');
if (schedulesRes.ok) {
const schedules = await schedulesRes.json();
setStats(prev => ({ ...prev, schedules: Array.isArray(schedules) ? schedules.length : 0 }));
}
} catch (e) { console.error('일정 통계 오류:', e); }
};
const handleLogout = () => {
localStorage.removeItem('adminToken');
localStorage.removeItem('adminUser');
navigate('/admin');
};
// 메뉴 아이템
const menuItems = [
{
icon: Users,
label: '멤버 관리',
description: '멤버 정보 및 프로필 관리',
path: '/admin/members',
color: 'bg-primary'
},
{
icon: Disc3,
label: '앨범 관리',
description: '앨범, 트랙, 사진 업로드 및 관리',
path: '/admin/albums',
color: 'bg-purple-500'
},
{
icon: Calendar,
label: '일정 관리',
description: '일정 추가 및 관리',
path: '/admin/schedule',
color: 'bg-blue-500'
},
];
return (
{/* 헤더 */}
{/* 메인 콘텐츠 */}
{/* 브레드크럼 */}
관리자 대시보드
{/* 타이틀 */}
관리자 대시보드
fromis_9 팬사이트를 관리하세요
{/* 메뉴 그리드 */}
{menuItems.map((item, index) => (
{item.label}
{item.description}
))}
{/* 빠른 통계 */}
);
}
export default AdminDashboard;