diff --git a/frontend/src/api/admin/albums.js b/frontend/src/api/admin/albums.js index 9235682..d1913c4 100644 --- a/frontend/src/api/admin/albums.js +++ b/frontend/src/api/admin/albums.js @@ -48,3 +48,15 @@ export async function deleteAlbumPhoto(albumId, photoId) { method: "DELETE", }); } + +// 앨범 티저 목록 조회 +export async function getAlbumTeasers(albumId) { + return fetchAdminApi(`/api/admin/albums/${albumId}/teasers`); +} + +// 앨범 티저 삭제 +export async function deleteAlbumTeaser(albumId, teaserId) { + return fetchAdminApi(`/api/admin/albums/${albumId}/teasers/${teaserId}`, { + method: "DELETE", + }); +} diff --git a/frontend/src/pages/pc/admin/AdminAlbumPhotos.jsx b/frontend/src/pages/pc/admin/AdminAlbumPhotos.jsx index bbcfa7e..577d4f2 100644 --- a/frontend/src/pages/pc/admin/AdminAlbumPhotos.jsx +++ b/frontend/src/pages/pc/admin/AdminAlbumPhotos.jsx @@ -8,6 +8,10 @@ import { Tag, FolderOpen, Save } from 'lucide-react'; import Toast from '../../../components/Toast'; +import * as authApi from '../../../api/admin/auth'; +import { getAlbum } from '../../../api/public/albums'; +import { getMembers } from '../../../api/public/members'; +import * as albumsApi from '../../../api/admin/albums'; function AdminAlbumPhotos() { const { albumId } = useParams(); @@ -145,67 +149,47 @@ function AdminAlbumPhotos() { useEffect(() => { // 로그인 확인 - const token = localStorage.getItem('adminToken'); - const userData = localStorage.getItem('adminUser'); - - if (!token || !userData) { + if (!authApi.hasToken()) { navigate('/admin'); return; } - setUser(JSON.parse(userData)); + setUser(authApi.getCurrentUser()); fetchAlbumData(); }, [navigate, albumId]); const fetchAlbumData = async () => { try { - const token = localStorage.getItem('adminToken'); - // 앨범 정보 로드 - const albumRes = await fetch(`/api/albums/${albumId}`); - if (!albumRes.ok) throw new Error('앨범을 찾을 수 없습니다'); - const albumData = await albumRes.json(); + const albumData = await getAlbum(albumId); setAlbum(albumData); // 멤버 목록 로드 - const membersRes = await fetch('/api/members'); - if (membersRes.ok) { - const membersData = await membersRes.json(); + try { + const membersData = await getMembers(); setMembers(membersData); - } + } catch (e) { /* 무시 */ } // 기존 컨셉 포토 목록 로드 - const photosRes = await fetch(`/api/admin/albums/${albumId}/photos`, { - headers: { 'Authorization': `Bearer ${token}` } - }); let photosData = []; - if (photosRes.ok) { - photosData = await photosRes.json(); + try { + photosData = await albumsApi.getAlbumPhotos(albumId); setPhotos(photosData); - } + } catch (e) { /* 무시 */ } // 티저 이미지 목록 로드 - const teasersRes = await fetch(`/api/admin/albums/${albumId}/teasers`, { - headers: { 'Authorization': `Bearer ${token}` } - }); let teasersData = []; - if (teasersRes.ok) { - teasersData = await teasersRes.json(); + try { + teasersData = await albumsApi.getAlbumTeasers(albumId); setTeasers(teasersData); - } + } catch (e) { /* 무시 */ } - // 시작 번호 자동 설정 (현재 선택된 타입의 마지막 + 1) - // 컨셉 포토는 컨셉 포토끼리, 티저는 티저끼리 번호 계산 + // 시작 번호 자동 설정 const maxPhotoOrder = photosData.length > 0 ? Math.max(...photosData.map(p => p.sort_order || 0)) : 0; - const maxTeaserOrder = teasersData.length > 0 - ? Math.max(...teasersData.map(t => t.sort_order || 0)) - : 0; - // 기본값은 컨셉 포토 기준 setStartNumber(maxPhotoOrder + 1); - setLoading(false); } catch (error) { console.error('앨범 로드 오류:', error); @@ -230,8 +214,7 @@ function AdminAlbumPhotos() { }, [photoType, photos, teasers]); const handleLogout = () => { - localStorage.removeItem('adminToken'); - localStorage.removeItem('adminUser'); + authApi.logout(); navigate('/admin'); }; @@ -504,7 +487,6 @@ function AdminAlbumPhotos() { // 삭제 처리 (기존 사진/티저) const handleDelete = async () => { setDeleting(true); - const token = localStorage.getItem('adminToken'); try { // 사진 ID와 티저 ID 분리 @@ -515,24 +497,12 @@ function AdminAlbumPhotos() { // 사진 삭제 for (const photoId of photoIds) { - const res = await fetch(`/api/admin/albums/${albumId}/photos/${photoId}`, { - method: 'DELETE', - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) { - throw new Error('사진 삭제 실패'); - } + await albumsApi.deleteAlbumPhoto(albumId, photoId); } // 티저 삭제 for (const teaserId of teaserIds) { - const res = await fetch(`/api/admin/albums/${albumId}/teasers/${teaserId}`, { - method: 'DELETE', - headers: { 'Authorization': `Bearer ${token}` } - }); - if (!res.ok) { - throw new Error('티저 삭제 실패'); - } + await albumsApi.deleteAlbumTeaser(albumId, teaserId); } // UI 상태 업데이트 diff --git a/frontend/src/pages/pc/admin/AdminMemberEdit.jsx b/frontend/src/pages/pc/admin/AdminMemberEdit.jsx index a3bf200..f26e3d1 100644 --- a/frontend/src/pages/pc/admin/AdminMemberEdit.jsx +++ b/frontend/src/pages/pc/admin/AdminMemberEdit.jsx @@ -6,6 +6,8 @@ import { 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 }) { @@ -272,28 +274,18 @@ function AdminMemberEdit() { useEffect(() => { // 로그인 확인 - const token = localStorage.getItem('adminToken'); - const userData = localStorage.getItem('adminUser'); - - if (!token || !userData) { + if (!authApi.hasToken()) { navigate('/admin'); return; } - setUser(JSON.parse(userData)); + setUser(authApi.getCurrentUser()); 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(); + const data = await membersApi.getMember(encodeURIComponent(name)); setFormData({ name: data.name || '', birth_date: data.birth_date ? data.birth_date.split('T')[0] : '', @@ -311,8 +303,7 @@ function AdminMemberEdit() { }; const handleLogout = () => { - localStorage.removeItem('adminToken'); - localStorage.removeItem('adminUser'); + authApi.logout(); navigate('/admin'); }; @@ -331,7 +322,6 @@ function AdminMemberEdit() { setSaving(true); try { - const token = localStorage.getItem('adminToken'); const formDataToSend = new FormData(); formDataToSend.append('name', formData.name); @@ -344,14 +334,7 @@ function AdminMemberEdit() { 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('수정 실패'); - + await membersApi.updateMember(encodeURIComponent(name), formDataToSend); setToast({ message: '멤버 정보가 수정되었습니다.', type: 'success' }); setTimeout(() => navigate('/admin/members'), 1000); } catch (error) { diff --git a/frontend/src/pages/pc/admin/AdminScheduleForm.jsx b/frontend/src/pages/pc/admin/AdminScheduleForm.jsx index 28f8264..b541fb0 100644 --- a/frontend/src/pages/pc/admin/AdminScheduleForm.jsx +++ b/frontend/src/pages/pc/admin/AdminScheduleForm.jsx @@ -26,6 +26,10 @@ import { } from "lucide-react"; import Toast from "../../../components/Toast"; import Lightbox from "../../../components/common/Lightbox"; +import * as authApi from "../../../api/admin/auth"; +import * as categoriesApi from "../../../api/admin/categories"; +import * as schedulesApi from "../../../api/admin/schedules"; +import { getMembers } from "../../../api/public/members"; // 커스텀 데이트픽커 컴포넌트 (AdminMemberEdit.jsx에서 가져옴) function CustomDatePicker({ value, onChange, placeholder = "날짜 선택" }) { const [isOpen, setIsOpen] = useState(false); @@ -840,8 +844,7 @@ function AdminScheduleForm() { // 카테고리 로드 const fetchCategories = async () => { try { - const res = await fetch("/api/admin/schedule-categories"); - const data = await res.json(); + const data = await categoriesApi.getCategories(); setCategories(data); // 첫 번째 카테고리를 기본값으로 설정 if (data.length > 0 && !formData.category) { @@ -861,15 +864,12 @@ function AdminScheduleForm() { }, [toast]); useEffect(() => { - const token = localStorage.getItem("adminToken"); - const userData = localStorage.getItem("adminUser"); - - if (!token || !userData) { + if (!authApi.hasToken()) { navigate("/admin"); return; } - setUser(JSON.parse(userData)); + setUser(authApi.getCurrentUser()); fetchMembers(); fetchCategories(); @@ -883,18 +883,7 @@ function AdminScheduleForm() { const fetchSchedule = async () => { setLoading(true); try { - const token = localStorage.getItem("adminToken"); - const res = await fetch(`/api/admin/schedules/${id}`, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - - if (!res.ok) { - throw new Error("일정을 찾을 수 없습니다."); - } - - const data = await res.json(); + const data = await schedulesApi.getSchedule(id); // 폼 데이터 설정 setFormData({ @@ -957,8 +946,7 @@ function AdminScheduleForm() { const fetchMembers = async () => { try { - const res = await fetch("/api/members"); - const data = await res.json(); + const data = await getMembers(); setMembers(data.filter((m) => !m.is_former)); } catch (error) { console.error("멤버 로드 오류:", error); @@ -966,8 +954,7 @@ function AdminScheduleForm() { }; const handleLogout = () => { - localStorage.removeItem("adminToken"); - localStorage.removeItem("adminUser"); + authApi.logout(); navigate("/admin"); };