refactor: 어드민 페이지 인증 로직을 useAdminAuth 훅으로 통합
- 8개 어드민 페이지에서 중복된 인증 코드 제거 - localStorage 직접 접근 → useAdminAuth 훅 사용 - authApi.hasToken()/verifyToken() 호출 제거 - 일관된 인증 상태 관리 (5분 캐시, 자동 리다이렉트) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d44537d870
commit
6462949bc7
8 changed files with 78 additions and 145 deletions
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import Toast from '../../../components/Toast';
|
import Toast from '../../../components/Toast';
|
||||||
import CustomDatePicker from '../../../components/admin/CustomDatePicker';
|
import CustomDatePicker from '../../../components/admin/CustomDatePicker';
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import useToast from '../../../hooks/useToast';
|
import useToast from '../../../hooks/useToast';
|
||||||
|
|
||||||
// 커스텀 드롭다운 컴포넌트
|
// 커스텀 드롭다운 컴포넌트
|
||||||
|
|
@ -79,8 +80,8 @@ function AdminAlbumForm() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const isEditMode = !!id;
|
const isEditMode = !!id;
|
||||||
const coverInputRef = useRef(null);
|
const coverInputRef = useRef(null);
|
||||||
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [coverPreview, setCoverPreview] = useState(null);
|
const [coverPreview, setCoverPreview] = useState(null);
|
||||||
|
|
@ -101,18 +102,10 @@ function AdminAlbumForm() {
|
||||||
|
|
||||||
const [tracks, setTracks] = useState([]);
|
const [tracks, setTracks] = useState([]);
|
||||||
|
|
||||||
|
// 수정 모드일 때 앨범 데이터 로드
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('adminToken');
|
if (!isAuthenticated || !isEditMode) return;
|
||||||
const userData = localStorage.getItem('adminUser');
|
|
||||||
|
|
||||||
if (!token || !userData) {
|
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(JSON.parse(userData));
|
|
||||||
|
|
||||||
if (isEditMode) {
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
fetch(`/api/albums/${id}`)
|
fetch(`/api/albums/${id}`)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
|
|
@ -138,8 +131,7 @@ function AdminAlbumForm() {
|
||||||
console.error('앨범 로드 오류:', error);
|
console.error('앨범 로드 오류:', error);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}
|
}, [id, isEditMode, isAuthenticated]);
|
||||||
}, [id, isEditMode, navigate]);
|
|
||||||
|
|
||||||
const handleInputChange = (e) => {
|
const handleInputChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ import {
|
||||||
import Toast from '../../../components/Toast';
|
import Toast from '../../../components/Toast';
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
||||||
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import useToast from '../../../hooks/useToast';
|
import useToast from '../../../hooks/useToast';
|
||||||
import * as authApi from '../../../api/admin/auth';
|
|
||||||
import { getAlbum } from '../../../api/public/albums';
|
import { getAlbum } from '../../../api/public/albums';
|
||||||
import { getMembers } from '../../../api/public/members';
|
import { getMembers } from '../../../api/public/members';
|
||||||
import * as albumsApi from '../../../api/admin/albums';
|
import * as albumsApi from '../../../api/admin/albums';
|
||||||
|
|
@ -22,11 +22,11 @@ function AdminAlbumPhotos() {
|
||||||
const fileInputRef = useRef(null);
|
const fileInputRef = useRef(null);
|
||||||
const photoListRef = useRef(null); // 사진 목록 영역 ref
|
const photoListRef = useRef(null); // 사진 목록 영역 ref
|
||||||
|
|
||||||
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
const [album, setAlbum] = useState(null);
|
const [album, setAlbum] = useState(null);
|
||||||
const [photos, setPhotos] = useState([]);
|
const [photos, setPhotos] = useState([]);
|
||||||
const [teasers, setTeasers] = useState([]); // 티저 이미지
|
const [teasers, setTeasers] = useState([]); // 티저 이미지
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const { toast, setToast } = useToast();
|
const { toast, setToast } = useToast();
|
||||||
const [selectedPhotos, setSelectedPhotos] = useState([]);
|
const [selectedPhotos, setSelectedPhotos] = useState([]);
|
||||||
const [uploading, setUploading] = useState(false);
|
const [uploading, setUploading] = useState(false);
|
||||||
|
|
@ -143,15 +143,10 @@ function AdminAlbumPhotos() {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 로그인 확인
|
if (isAuthenticated) {
|
||||||
if (!authApi.hasToken()) {
|
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(authApi.getCurrentUser());
|
|
||||||
fetchAlbumData();
|
fetchAlbumData();
|
||||||
}, [navigate, albumId]);
|
}
|
||||||
|
}, [isAuthenticated, albumId]);
|
||||||
|
|
||||||
const fetchAlbumData = async () => {
|
const fetchAlbumData = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,32 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { useNavigate, Link } from 'react-router-dom';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import {
|
import { Plus, Search, Edit2, Trash2, Image, Music, Home, ChevronRight, Calendar } from 'lucide-react';
|
||||||
Plus, Search, Edit2, Trash2, Image, Music,
|
|
||||||
Home, ChevronRight, Calendar, X
|
|
||||||
} from 'lucide-react';
|
|
||||||
import Toast from '../../../components/Toast';
|
import Toast from '../../../components/Toast';
|
||||||
import Tooltip from '../../../components/Tooltip';
|
import Tooltip from '../../../components/Tooltip';
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
||||||
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import useToast from '../../../hooks/useToast';
|
import useToast from '../../../hooks/useToast';
|
||||||
import * as authApi from '../../../api/admin/auth';
|
|
||||||
import { getAlbums } from '../../../api/public/albums';
|
import { getAlbums } from '../../../api/public/albums';
|
||||||
import * as albumsApi from '../../../api/admin/albums';
|
import * as albumsApi from '../../../api/admin/albums';
|
||||||
|
|
||||||
|
|
||||||
function AdminAlbums() {
|
function AdminAlbums() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
|
const { toast, setToast } = useToast();
|
||||||
|
|
||||||
const [albums, setAlbums] = useState([]);
|
const [albums, setAlbums] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const { toast, setToast } = useToast();
|
|
||||||
const [deleteDialog, setDeleteDialog] = useState({ show: false, album: null });
|
const [deleteDialog, setDeleteDialog] = useState({ show: false, album: null });
|
||||||
const [deleting, setDeleting] = useState(false);
|
const [deleting, setDeleting] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 로그인 확인
|
if (isAuthenticated) {
|
||||||
if (!authApi.hasToken()) {
|
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(authApi.getCurrentUser());
|
|
||||||
fetchAlbums();
|
fetchAlbums();
|
||||||
}, [navigate]);
|
}
|
||||||
|
}, [isAuthenticated]);
|
||||||
|
|
||||||
const fetchAlbums = async () => {
|
const fetchAlbums = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import {
|
import { Disc3, Calendar, Users, Home, ChevronRight } from 'lucide-react';
|
||||||
Disc3, Calendar, Users,
|
|
||||||
Home, ChevronRight
|
|
||||||
} from 'lucide-react';
|
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
import * as authApi from '../../../api/admin/auth';
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import { getMembers } from '../../../api/public/members';
|
import { getMembers } from '../../../api/public/members';
|
||||||
import { getAlbums, getAlbum } from '../../../api/public/albums';
|
import { getAlbums, getAlbum } from '../../../api/public/albums';
|
||||||
import { getSchedules } from '../../../api/public/schedules';
|
import { getSchedules } from '../../../api/public/schedules';
|
||||||
|
|
@ -43,8 +40,7 @@ function AnimatedNumber({ value }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function AdminDashboard() {
|
function AdminDashboard() {
|
||||||
const navigate = useNavigate();
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const [stats, setStats] = useState({
|
const [stats, setStats] = useState({
|
||||||
albums: 0,
|
albums: 0,
|
||||||
photos: 0,
|
photos: 0,
|
||||||
|
|
@ -53,24 +49,10 @@ function AdminDashboard() {
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 로그인 상태 확인
|
if (isAuthenticated) {
|
||||||
if (!authApi.hasToken()) {
|
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(authApi.getCurrentUser());
|
|
||||||
|
|
||||||
// 토큰 유효성 검증
|
|
||||||
authApi.verifyToken()
|
|
||||||
.catch(() => {
|
|
||||||
authApi.logout();
|
|
||||||
navigate('/admin');
|
|
||||||
});
|
|
||||||
|
|
||||||
// 통계 데이터 가져오기
|
|
||||||
fetchStats();
|
fetchStats();
|
||||||
}, [navigate]);
|
}
|
||||||
|
}, [isAuthenticated]);
|
||||||
|
|
||||||
const fetchStats = async () => {
|
const fetchStats = async () => {
|
||||||
// 각 통계를 개별적으로 가져와서 하나가 실패해도 다른 것은 표시
|
// 각 통계를 개별적으로 가져와서 하나가 실패해도 다른 것은 표시
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import Tooltip from '../../../components/Tooltip';
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
||||||
import useScheduleStore from '../../../stores/useScheduleStore';
|
import useScheduleStore from '../../../stores/useScheduleStore';
|
||||||
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import useToast from '../../../hooks/useToast';
|
import useToast from '../../../hooks/useToast';
|
||||||
import { getTodayKST, formatDate } from '../../../utils/date';
|
import { getTodayKST, formatDate } from '../../../utils/date';
|
||||||
import * as schedulesApi from '../../../api/admin/schedules';
|
import * as schedulesApi from '../../../api/admin/schedules';
|
||||||
|
|
@ -151,9 +152,10 @@ function AdminSchedule() {
|
||||||
scrollPosition, setScrollPosition,
|
scrollPosition, setScrollPosition,
|
||||||
} = useScheduleStore();
|
} = useScheduleStore();
|
||||||
|
|
||||||
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
|
|
||||||
// 로컬 상태 (페이지 이동 시 유지할 필요 없는 것들)
|
// 로컬 상태 (페이지 이동 시 유지할 필요 없는 것들)
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const { toast, setToast } = useToast();
|
const { toast, setToast } = useToast();
|
||||||
const scrollContainerRef = useRef(null);
|
const scrollContainerRef = useRef(null);
|
||||||
const searchContainerRef = useRef(null); // 검색 컨테이너 (외부 클릭 감지용)
|
const searchContainerRef = useRef(null); // 검색 컨테이너 (외부 클릭 감지용)
|
||||||
|
|
@ -363,15 +365,7 @@ function AdminSchedule() {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('adminToken');
|
if (!isAuthenticated) return;
|
||||||
const userData = localStorage.getItem('adminUser');
|
|
||||||
|
|
||||||
if (!token || !userData) {
|
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(JSON.parse(userData));
|
|
||||||
|
|
||||||
// 카테고리 로드
|
// 카테고리 로드
|
||||||
fetchCategories();
|
fetchCategories();
|
||||||
|
|
@ -382,7 +376,7 @@ function AdminSchedule() {
|
||||||
setToast(JSON.parse(savedToast));
|
setToast(JSON.parse(savedToast));
|
||||||
sessionStorage.removeItem('scheduleToast');
|
sessionStorage.removeItem('scheduleToast');
|
||||||
}
|
}
|
||||||
}, [navigate]);
|
}, [isAuthenticated]);
|
||||||
|
|
||||||
|
|
||||||
// 월이 변경될 때마다 일정 로드
|
// 월이 변경될 때마다 일정 로드
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import Toast from '../../../components/Toast';
|
import Toast from '../../../components/Toast';
|
||||||
import Tooltip from '../../../components/Tooltip';
|
import Tooltip from '../../../components/Tooltip';
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import useToast from '../../../hooks/useToast';
|
import useToast from '../../../hooks/useToast';
|
||||||
import * as botsApi from '../../../api/admin/bots';
|
import * as botsApi from '../../../api/admin/bots';
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ const MeilisearchIcon = ({ size = 20 }) => (
|
||||||
|
|
||||||
function AdminScheduleBots() {
|
function AdminScheduleBots() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [user, setUser] = useState(null);
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
const { toast, setToast } = useToast();
|
const { toast, setToast } = useToast();
|
||||||
const [bots, setBots] = useState([]);
|
const [bots, setBots] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
@ -52,18 +53,11 @@ function AdminScheduleBots() {
|
||||||
const [quotaWarning, setQuotaWarning] = useState(null); // 할당량 경고 상태
|
const [quotaWarning, setQuotaWarning] = useState(null); // 할당량 경고 상태
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('adminToken');
|
if (isAuthenticated) {
|
||||||
const userData = localStorage.getItem('adminUser');
|
|
||||||
|
|
||||||
if (!token || !userData) {
|
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(JSON.parse(userData));
|
|
||||||
fetchBots();
|
fetchBots();
|
||||||
fetchQuotaWarning();
|
fetchQuotaWarning();
|
||||||
}, [navigate]);
|
}
|
||||||
|
}, [isAuthenticated]);
|
||||||
|
|
||||||
// 봇 목록 조회
|
// 봇 목록 조회
|
||||||
const fetchBots = async () => {
|
const fetchBots = async () => {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import { HexColorPicker } from 'react-colorful';
|
||||||
import Toast from '../../../components/Toast';
|
import Toast from '../../../components/Toast';
|
||||||
import AdminLayout from '../../../components/admin/AdminLayout';
|
import AdminLayout from '../../../components/admin/AdminLayout';
|
||||||
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
import ConfirmDialog from '../../../components/admin/ConfirmDialog';
|
||||||
|
import useAdminAuth from '../../../hooks/useAdminAuth';
|
||||||
import useToast from '../../../hooks/useToast';
|
import useToast from '../../../hooks/useToast';
|
||||||
import * as authApi from '../../../api/admin/auth';
|
|
||||||
import * as categoriesApi from '../../../api/admin/categories';
|
import * as categoriesApi from '../../../api/admin/categories';
|
||||||
|
|
||||||
// 기본 색상 (8개)
|
// 기본 색상 (8개)
|
||||||
|
|
@ -38,7 +38,7 @@ const getColorStyle = (colorValue) => {
|
||||||
|
|
||||||
function AdminScheduleCategory() {
|
function AdminScheduleCategory() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [user, setUser] = useState(null);
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
const [categories, setCategories] = useState([]);
|
const [categories, setCategories] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const { toast, setToast, showSuccess, showError } = useToast();
|
const { toast, setToast, showSuccess, showError } = useToast();
|
||||||
|
|
@ -55,24 +55,12 @@ function AdminScheduleCategory() {
|
||||||
// 카스텀 컴러 피커 팝업
|
// 카스텀 컴러 피커 팝업
|
||||||
const [colorPickerOpen, setColorPickerOpen] = useState(false);
|
const [colorPickerOpen, setColorPickerOpen] = useState(false);
|
||||||
|
|
||||||
// 사용자 인증 확인
|
// 카테고리 로드
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!authApi.hasToken()) {
|
if (isAuthenticated) {
|
||||||
navigate('/admin');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
authApi.verifyToken()
|
|
||||||
.then(data => {
|
|
||||||
if (data.valid) {
|
|
||||||
setUser(data.user);
|
|
||||||
fetchCategories();
|
fetchCategories();
|
||||||
} else {
|
|
||||||
navigate('/admin');
|
|
||||||
}
|
}
|
||||||
})
|
}, [isAuthenticated]);
|
||||||
.catch(() => navigate('/admin'));
|
|
||||||
}, [navigate]);
|
|
||||||
|
|
||||||
// 카테고리 목록 조회
|
// 카테고리 목록 조회
|
||||||
const fetchCategories = async () => {
|
const fetchCategories = async () => {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ import CustomDatePicker from "../../../components/admin/CustomDatePicker";
|
||||||
import CustomTimePicker from "../../../components/admin/CustomTimePicker";
|
import CustomTimePicker from "../../../components/admin/CustomTimePicker";
|
||||||
import AdminLayout from "../../../components/admin/AdminLayout";
|
import AdminLayout from "../../../components/admin/AdminLayout";
|
||||||
import ConfirmDialog from "../../../components/admin/ConfirmDialog";
|
import ConfirmDialog from "../../../components/admin/ConfirmDialog";
|
||||||
|
import useAdminAuth from "../../../hooks/useAdminAuth";
|
||||||
import useToast from "../../../hooks/useToast";
|
import useToast from "../../../hooks/useToast";
|
||||||
import * as authApi from "../../../api/admin/auth";
|
|
||||||
import * as categoriesApi from "../../../api/admin/categories";
|
import * as categoriesApi from "../../../api/admin/categories";
|
||||||
import * as schedulesApi from "../../../api/admin/schedules";
|
import * as schedulesApi from "../../../api/admin/schedules";
|
||||||
import { getMembers } from "../../../api/public/members";
|
import { getMembers } from "../../../api/public/members";
|
||||||
|
|
@ -38,8 +38,8 @@ function AdminScheduleForm() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const isEditMode = !!id;
|
const isEditMode = !!id;
|
||||||
|
const { user, isAuthenticated } = useAdminAuth();
|
||||||
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const { toast, setToast } = useToast();
|
const { toast, setToast } = useToast();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [members, setMembers] = useState([]);
|
const [members, setMembers] = useState([]);
|
||||||
|
|
@ -147,12 +147,8 @@ function AdminScheduleForm() {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!authApi.hasToken()) {
|
if (!isAuthenticated) return;
|
||||||
navigate("/admin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUser(authApi.getCurrentUser());
|
|
||||||
fetchMembers();
|
fetchMembers();
|
||||||
fetchCategories();
|
fetchCategories();
|
||||||
|
|
||||||
|
|
@ -160,7 +156,7 @@ function AdminScheduleForm() {
|
||||||
if (isEditMode && id) {
|
if (isEditMode && id) {
|
||||||
fetchSchedule();
|
fetchSchedule();
|
||||||
}
|
}
|
||||||
}, [navigate, isEditMode, id]);
|
}, [isAuthenticated, isEditMode, id]);
|
||||||
|
|
||||||
// 기존 일정 데이터 로드 (수정 모드)
|
// 기존 일정 데이터 로드 (수정 모드)
|
||||||
const fetchSchedule = async () => {
|
const fetchSchedule = async () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue