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';
import * as authApi from '../../../api/admin/auth';
import * as membersApi from '../../../api/admin/members';
// 커스텀 데이트픽커 컴포넌트
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(() => {
// 로그인 확인
if (!authApi.hasToken()) {
navigate('/admin');
return;
}
setUser(authApi.getCurrentUser());
fetchMember();
}, [navigate, name]);
const fetchMember = async () => {
try {
const data = await membersApi.getMember(encodeURIComponent(name));
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 = () => {
authApi.logout();
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 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);
}
await membersApi.updateMember(encodeURIComponent(name), formDataToSend);
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)} />
{/* 헤더 */}
{/* 메인 콘텐츠 */}
{/* 브레드크럼 */}
멤버 관리
멤버 수정
{/* 타이틀 */}
{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;