import { useState, useEffect, useRef } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { LogOut, Home, ChevronRight, Calendar, Plus, Edit2, Trash2, ChevronLeft, Search, ChevronDown } from 'lucide-react'; import Toast from '../../../components/Toast'; function AdminSchedule() { const navigate = useNavigate(); const [loading, setLoading] = useState(false); const [user, setUser] = useState(null); const [toast, setToast] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [selectedCategory, setSelectedCategory] = useState('all'); const [selectedDate, setSelectedDate] = useState(null); const [currentDate, setCurrentDate] = useState(new Date()); const [slideDirection, setSlideDirection] = useState(0); // 년월 선택 관련 (Schedule.jsx와 동일한 패턴) const [showYearMonthPicker, setShowYearMonthPicker] = useState(false); const [viewMode, setViewMode] = useState('yearMonth'); // 'yearMonth' | 'months' const pickerRef = useRef(null); // 달력 관련 const year = currentDate.getFullYear(); const month = currentDate.getMonth(); const firstDay = new Date(year, month, 1).getDay(); const daysInMonth = new Date(year, month + 1, 0).getDate(); const days = ['일', '월', '화', '수', '목', '금', '토']; const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']; // 년도 범위 (현재 년도 기준 10년 단위 - Schedule.jsx와 동일) const startYear = Math.floor(year / 10) * 10 - 1; const yearRange = Array.from({ length: 12 }, (_, i) => startYear + i); // 현재 년도/월 확인 함수 const isCurrentYear = (y) => new Date().getFullYear() === y; const isCurrentMonth = (m) => { const today = new Date(); return today.getFullYear() === year && today.getMonth() === m; }; const getDaysInMonth = (y, m) => new Date(y, m + 1, 0).getDate(); // 카테고리 목록 const categories = [ { id: 'all', name: '전체', color: 'gray' }, { id: 'broadcast', name: '방송', color: 'blue' }, { id: 'event', name: '이벤트', color: 'green' }, { id: 'release', name: '발매', color: 'purple' }, { id: 'concert', name: '콘서트', color: 'red' }, { id: 'fansign', name: '팬사인회', color: 'pink' }, ]; // 더미 일정 데이터 (UI용) const dummySchedules = [ { id: 1, title: 'SBS 인기가요 출연', date: '2026-01-05', time: '15:30', category: 'broadcast', description: '컴백 무대' }, { id: 2, title: '유튜브 라이브', date: '2026-01-05', time: '19:00', category: 'broadcast', description: '팬들과 소통 시간' }, { id: 3, title: '팬미팅', date: '2026-01-10', time: '18:00', category: 'event', description: '서울 올림픽홀' }, { id: 4, title: '신곡 발매', date: '2026-01-15', time: '18:00', category: 'release', description: '미니앨범 8집' }, { id: 5, title: '콘서트 투어', date: '2026-01-20', time: '19:00', category: 'concert', description: '부산 벡스코' }, { id: 6, title: '온라인 팬사인회', date: '2026-01-25', time: '17:00', category: 'fansign', description: '위버스 진행' }, ]; // 카테고리별 색상 const getCategoryColor = (categoryId) => { const colors = { broadcast: 'bg-blue-100 text-blue-700', event: 'bg-green-100 text-green-700', release: 'bg-purple-100 text-purple-700', concert: 'bg-red-100 text-red-700', fansign: 'bg-pink-100 text-pink-700', }; return colors[categoryId] || 'bg-gray-100 text-gray-700'; }; // 카테고리별 도트 색상 const getCategoryDotColor = (categoryId) => { const colors = { broadcast: 'bg-blue-500', event: 'bg-green-500', release: 'bg-purple-500', concert: 'bg-red-500', fansign: 'bg-pink-500', }; return colors[categoryId] || 'bg-gray-500'; }; // 해당 날짜에 일정이 있는지 확인 const hasSchedule = (day) => { const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; return dummySchedules.some(s => s.date === dateStr); }; // Toast 자동 숨김 useEffect(() => { if (toast) { const timer = setTimeout(() => setToast(null), 3000); return () => clearTimeout(timer); } }, [toast]); useEffect(() => { const token = localStorage.getItem('adminToken'); const userData = localStorage.getItem('adminUser'); if (!token || !userData) { navigate('/admin'); return; } setUser(JSON.parse(userData)); }, [navigate]); // 외부 클릭 시 피커 닫기 useEffect(() => { const handleClickOutside = (event) => { if (pickerRef.current && !pickerRef.current.contains(event.target)) { setShowYearMonthPicker(false); setViewMode('yearMonth'); } }; if (showYearMonthPicker) { document.addEventListener('mousedown', handleClickOutside); } return () => document.removeEventListener('mousedown', handleClickOutside); }, [showYearMonthPicker]); const handleLogout = () => { localStorage.removeItem('adminToken'); localStorage.removeItem('adminUser'); navigate('/admin'); }; // 월 이동 const prevMonth = () => { setSlideDirection(-1); setCurrentDate(new Date(year, month - 1, 1)); }; const nextMonth = () => { setSlideDirection(1); setCurrentDate(new Date(year, month + 1, 1)); }; // 년도 범위 이동 const prevYearRange = () => setCurrentDate(new Date(year - 10, month, 1)); const nextYearRange = () => setCurrentDate(new Date(year + 10, month, 1)); // 년도 선택 시 월 선택 모드로 전환 const selectYear = (newYear) => { setCurrentDate(new Date(newYear, month, 1)); setViewMode('months'); }; // 월 선택 시 적용 후 닫기 const selectMonth = (newMonth) => { setCurrentDate(new Date(year, newMonth, 1)); setShowYearMonthPicker(false); setViewMode('yearMonth'); }; // 날짜 선택 const selectDate = (day) => { const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; setSelectedDate(selectedDate === dateStr ? null : dateStr); }; // 필터링된 일정 const filteredSchedules = dummySchedules.filter(schedule => { const matchesSearch = schedule.title.toLowerCase().includes(searchTerm.toLowerCase()); const matchesCategory = selectedCategory === 'all' || schedule.category === selectedCategory; return matchesSearch && matchesCategory; }); return (
setToast(null)} /> {/* 헤더 */}
fromis_9 Admin
안녕하세요, {user?.username}
{/* 메인 콘텐츠 */}
{/* 브레드크럼 */}
일정 관리
{/* 타이틀 + 추가 버튼 */}

일정 관리

fromis_9의 일정을 관리합니다

{/* 왼쪽: 달력 + 카테고리 필터 */}
{/* 달력 (Schedule.jsx와 동일한 패턴) */}
{/* 달력 헤더 */}
{/* 년/월 선택 팝업 (Schedule.jsx와 동일한 스타일) */} {showYearMonthPicker && ( {/* 헤더 - 년도 범위 이동 */}
{viewMode === 'yearMonth' ? `${yearRange[0]} - ${yearRange[yearRange.length - 1]}` : `${year}년`}
{viewMode === 'yearMonth' && ( {/* 년도 선택 */}
년도
{yearRange.map((y) => ( ))}
{/* 월 선택 */}
{monthNames.map((m, i) => ( ))}
)} {viewMode === 'months' && ( {/* 월 선택 */}
월 선택
{monthNames.map((m, i) => ( ))}
)}
)}
{/* 요일 헤더 + 날짜 그리드 */} {/* 요일 헤더 */}
{days.map((day, i) => (
{day}
))}
{/* 날짜 그리드 */}
{/* 전달 날짜 */} {Array.from({ length: firstDay }).map((_, i) => { const prevMonthDays = getDaysInMonth(year, month - 1); const day = prevMonthDays - firstDay + i + 1; return (
{day}
); })} {/* 현재 달 날짜 */} {Array.from({ length: daysInMonth }).map((_, i) => { const day = i + 1; const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; const isSelected = selectedDate === dateStr; const hasEvent = hasSchedule(day); const dayOfWeek = (firstDay + i) % 7; const isToday = new Date().toDateString() === new Date(year, month, day).toDateString(); return ( ); })} {/* 다음달 날짜 */} {(() => { const totalCells = firstDay + daysInMonth; const remainder = totalCells % 7; const nextDays = remainder === 0 ? 0 : 7 - remainder; return Array.from({ length: nextDays }).map((_, i) => (
{i + 1}
)); })()}
{/* 범례 */}
일정 있음
{/* 카테고리 필터 */}

카테고리

{categories.map(category => ( ))}
{/* 오른쪽: 일정 목록 */}
{/* 검색 */}
setSearchTerm(e.target.value)} className="w-full pl-12 pr-4 py-3 bg-gray-50 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary focus:bg-white transition-all" />
{/* 일정 목록 */}

{selectedCategory === 'all' ? '전체 일정' : categories.find(c => c.id === selectedCategory)?.name}

{filteredSchedules.length}개의 일정
{loading ? (
) : filteredSchedules.length === 0 ? (

등록된 일정이 없습니다

) : (
{filteredSchedules.map((schedule, index) => (
{/* 날짜 */}
{new Date(schedule.date).getDate()}
{new Date(schedule.date).toLocaleDateString('ko-KR', { weekday: 'short' })}
{/* 내용 */}
{categories.find(c => c.id === schedule.category)?.name} {schedule.time}

{schedule.title}

{schedule.description}

{/* 액션 버튼 */}
))}
)}
); } export default AdminSchedule;