import { useState, useEffect, useRef } from 'react'; import { useNavigate, useParams, Link } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Save, Upload, LogOut, Home, ChevronRight, ChevronLeft, ChevronDown, User, Instagram, Calendar, Briefcase } from 'lucide-react'; import Toast from '../../../components/Toast'; // 커스텀 데이트픽커 컴포넌트 function CustomDatePicker({ value, onChange }) { const [isOpen, setIsOpen] = useState(false); const [viewMode, setViewMode] = useState('days'); const [viewDate, setViewDate] = useState(() => { if (value) return new Date(value); return new Date(); }); const ref = useRef(null); useEffect(() => { const handleClickOutside = (e) => { if (ref.current && !ref.current.contains(e.target)) { setIsOpen(false); setViewMode('days'); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const year = viewDate.getFullYear(); const month = viewDate.getMonth(); const firstDay = new Date(year, month, 1).getDay(); const daysInMonth = new Date(year, month + 1, 0).getDate(); const days = []; for (let i = 0; i < firstDay; i++) { days.push(null); } for (let i = 1; i <= daysInMonth; i++) { days.push(i); } const startYear = Math.floor(year / 10) * 10 - 1; const years = Array.from({ length: 12 }, (_, i) => startYear + i); const prevMonth = () => setViewDate(new Date(year, month - 1, 1)); const nextMonth = () => setViewDate(new Date(year, month + 1, 1)); const prevYearRange = () => setViewDate(new Date(year - 10, month, 1)); const nextYearRange = () => setViewDate(new Date(year + 10, month, 1)); const selectDate = (day) => { const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; onChange(dateStr); setIsOpen(false); setViewMode('days'); }; const selectYear = (y) => { setViewDate(new Date(y, month, 1)); setViewMode('months'); }; const selectMonth = (m) => { setViewDate(new Date(year, m, 1)); setViewMode('days'); }; const formatDisplayDate = (dateStr) => { if (!dateStr) return ''; const [y, m, d] = dateStr.split('-'); return `${y}년 ${parseInt(m)}월 ${parseInt(d)}일`; }; const isSelected = (day) => { if (!value || !day) return false; const [y, m, d] = value.split('-'); return parseInt(y) === year && parseInt(m) === month + 1 && parseInt(d) === day; }; const isToday = (day) => { if (!day) return false; const today = new Date(); return today.getFullYear() === year && today.getMonth() === month && today.getDate() === day; }; const isCurrentYear = (y) => new Date().getFullYear() === y; const isCurrentMonth = (m) => { const today = new Date(); return today.getFullYear() === year && today.getMonth() === m; }; const months = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']; return (
{isOpen && (
{viewMode === 'years' && (
년도
{years.map((y) => ( ))}
{months.map((m, i) => ( ))}
)} {viewMode === 'months' && (
월 선택
{months.map((m, i) => ( ))}
)} {viewMode === 'days' && (
{['일', '월', '화', '수', '목', '금', '토'].map((d, i) => (
{d}
))}
{days.map((day, i) => ( ))}
)}
)}
); } function AdminMemberEdit() { const navigate = useNavigate(); const { name } = useParams(); const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [toast, setToast] = useState(null); const [imagePreview, setImagePreview] = useState(null); const [imageFile, setImageFile] = useState(null); const [formData, setFormData] = useState({ name: '', birth_date: '', position: '', instagram: '', is_former: false }); // 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)); fetchMember(); }, [navigate, name]); const fetchMember = async () => { try { const token = localStorage.getItem('adminToken'); const res = await fetch(`/api/admin/members/${encodeURIComponent(name)}`, { headers: { Authorization: `Bearer ${token}` } }); if (!res.ok) throw new Error('멤버 조회 실패'); const data = await res.json(); setFormData({ name: data.name || '', birth_date: data.birth_date ? data.birth_date.split('T')[0] : '', position: data.position || '', instagram: data.instagram || '', is_former: !!data.is_former }); setImagePreview(data.image_url); setLoading(false); } catch (error) { console.error('멤버 로드 오류:', error); setToast({ message: '멤버 정보를 불러올 수 없습니다.', type: 'error' }); setLoading(false); } }; const handleLogout = () => { localStorage.removeItem('adminToken'); localStorage.removeItem('adminUser'); navigate('/admin'); }; const handleImageChange = (e) => { const file = e.target.files[0]; if (file) { setImageFile(file); const reader = new FileReader(); reader.onloadend = () => setImagePreview(reader.result); reader.readAsDataURL(file); } }; const handleSubmit = async (e) => { e.preventDefault(); setSaving(true); try { const token = localStorage.getItem('adminToken'); const formDataToSend = new FormData(); formDataToSend.append('name', formData.name); formDataToSend.append('birth_date', formData.birth_date); formDataToSend.append('position', formData.position); formDataToSend.append('instagram', formData.instagram); formDataToSend.append('is_former', formData.is_former); if (imageFile) { formDataToSend.append('image', imageFile); } const res = await fetch(`/api/admin/members/${encodeURIComponent(name)}`, { method: 'PUT', headers: { Authorization: `Bearer ${token}` }, body: formDataToSend }); if (!res.ok) throw new Error('수정 실패'); setToast({ message: '멤버 정보가 수정되었습니다.', type: 'success' }); setTimeout(() => navigate('/admin/members'), 1000); } catch (error) { console.error('수정 오류:', error); setToast({ message: '수정 중 오류가 발생했습니다.', type: 'error' }); } finally { setSaving(false); } }; return (
{/* Toast */} setToast(null)} /> {/* 헤더 */}
fromis_9 Admin
안녕하세요, {user?.username}
{/* 메인 콘텐츠 */}
{/* 브레드크럼 */}
멤버 관리 멤버 수정
{/* 타이틀 */}

멤버 수정

멤버 정보를 수정합니다

{loading ? (
) : (
{/* 이미지 업로드 영역 */}
document.getElementById('imageInput').click()} > {imagePreview ? ( <> 프로필 미리보기
변경
) : (
클릭하여 업로드
)}
{/* 입력 폼 영역 */}
{/* 이름 */}
setFormData({ ...formData, name: e.target.value })} required className="w-full px-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="멤버 이름" />
{/* 생년월일 */}
setFormData({ ...formData, birth_date: date })} />
{/* 포지션 */}
setFormData({ ...formData, position: e.target.value })} className="w-full px-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="메인보컬, 리드댄서 등" />
{/* 인스타그램 */}
setFormData({ ...formData, instagram: e.target.value })} className="w-full px-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="@username" />
{/* 활동 상태 */}
{/* 버튼 영역 */}
)}
); } export default AdminMemberEdit;