diff --git a/frontend/src/components/admin/ConfirmDialog.jsx b/frontend/src/components/admin/ConfirmDialog.jsx new file mode 100644 index 0000000..4c67983 --- /dev/null +++ b/frontend/src/components/admin/ConfirmDialog.jsx @@ -0,0 +1,115 @@ +/** + * ConfirmDialog 컴포넌트 + * 삭제 등 위험한 작업의 확인을 위한 공통 다이얼로그 + * + * Props: + * - isOpen: 다이얼로그 표시 여부 + * - onClose: 닫기 콜백 + * - onConfirm: 확인 콜백 + * - title: 제목 (예: "앨범 삭제") + * - message: 메시지 내용 (ReactNode 가능) + * - confirmText: 확인 버튼 텍스트 (기본: "삭제") + * - cancelText: 취소 버튼 텍스트 (기본: "취소") + * - loading: 로딩 상태 + * - loadingText: 로딩 중 텍스트 (기본: "삭제 중...") + * - variant: 버튼 색상 (기본: "danger", "primary" 가능) + */ +import { motion, AnimatePresence } from 'framer-motion'; +import { AlertTriangle, Trash2 } from 'lucide-react'; + +function ConfirmDialog({ + isOpen, + onClose, + onConfirm, + title, + message, + confirmText = '삭제', + cancelText = '취소', + loading = false, + loadingText = '삭제 중...', + variant = 'danger', + icon: Icon = AlertTriangle +}) { + // 버튼 색상 설정 + const buttonColors = { + danger: 'bg-red-500 hover:bg-red-600', + primary: 'bg-primary hover:bg-primary-dark' + }; + + const iconBgColors = { + danger: 'bg-red-100', + primary: 'bg-primary/10' + }; + + const iconColors = { + danger: 'text-red-500', + primary: 'text-primary' + }; + + return ( + + {isOpen && ( + !loading && onClose()} + > + e.stopPropagation()} + > + {/* 헤더 */} +
+
+ +
+

{title}

+
+ + {/* 메시지 */} +
+ {message} +
+ + {/* 버튼 */} +
+ + +
+
+
+ )} +
+ ); +} + +export default ConfirmDialog; diff --git a/frontend/src/pages/pc/admin/AdminAlbums.jsx b/frontend/src/pages/pc/admin/AdminAlbums.jsx index ccf3904..b089cde 100644 --- a/frontend/src/pages/pc/admin/AdminAlbums.jsx +++ b/frontend/src/pages/pc/admin/AdminAlbums.jsx @@ -3,11 +3,12 @@ import { useNavigate, Link } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Plus, Search, Edit2, Trash2, Image, Music, - Home, ChevronRight, Calendar, AlertTriangle, X + Home, ChevronRight, Calendar, X } from 'lucide-react'; import Toast from '../../../components/Toast'; import Tooltip from '../../../components/Tooltip'; import AdminHeader from '../../../components/admin/AdminHeader'; +import ConfirmDialog from '../../../components/admin/ConfirmDialog'; import useToast from '../../../hooks/useToast'; import * as authApi from '../../../api/admin/auth'; import { getAlbums } from '../../../api/public/albums'; @@ -80,65 +81,20 @@ function AdminAlbums() { setToast(null)} /> {/* 삭제 확인 다이얼로그 */} - - {deleteDialog.show && ( - !deleting && setDeleteDialog({ show: false, album: null })} - > - e.stopPropagation()} - > -
-
- -
-

앨범 삭제

-
- -

- "{deleteDialog.album?.title}" 앨범을 삭제하시겠습니까? -
- 이 작업은 되돌릴 수 없으며, 모든 트랙과 커버 이미지가 함께 삭제됩니다. -

- -
- - -
-
-
- )} -
+ setDeleteDialog({ show: false, album: null })} + onConfirm={handleDelete} + title="앨범 삭제" + message={ + <> + "{deleteDialog.album?.title}" 앨범을 삭제하시겠습니까? +
+ 이 작업은 되돌릴 수 없으며, 모든 트랙과 커버 이미지가 함께 삭제됩니다. + + } + loading={deleting} + /> {/* 헤더 */} diff --git a/frontend/src/pages/pc/admin/AdminSchedule.jsx b/frontend/src/pages/pc/admin/AdminSchedule.jsx index 737a8d2..089b032 100644 --- a/frontend/src/pages/pc/admin/AdminSchedule.jsx +++ b/frontend/src/pages/pc/admin/AdminSchedule.jsx @@ -3,7 +3,7 @@ import { useNavigate, Link } from 'react-router-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Home, ChevronRight, Calendar, Plus, Edit2, Trash2, - ChevronLeft, Search, ChevronDown, AlertTriangle, Bot, Tag, ArrowLeft, ExternalLink, Clock, Link2 + ChevronLeft, Search, ChevronDown, Bot, Tag, ArrowLeft, ExternalLink, Clock, Link2 } from 'lucide-react'; import { useInfiniteQuery } from '@tanstack/react-query'; import { useInView } from 'react-intersection-observer'; @@ -11,6 +11,7 @@ import { useInView } from 'react-intersection-observer'; import Toast from '../../../components/Toast'; import Tooltip from '../../../components/Tooltip'; import AdminHeader from '../../../components/admin/AdminHeader'; +import ConfirmDialog from '../../../components/admin/ConfirmDialog'; import useScheduleStore from '../../../stores/useScheduleStore'; import useToast from '../../../hooks/useToast'; import { getTodayKST, formatDate } from '../../../utils/date'; @@ -567,75 +568,22 @@ function AdminSchedule() { setToast(null)} /> {/* 삭제 확인 다이얼로그 */} - - {deleteDialogOpen && ( - !deleting && setDeleteDialogOpen(false)} - > - e.stopPropagation()} - > -
-
- -
-

일정 삭제

-
- -

- 다음 일정을 삭제하시겠습니까? -

-

- {scheduleToDelete?.title} -

-

- 이 작업은 되돌릴 수 없습니다. -

- -
- - -
-
-
- )} -
+ setDeleteDialogOpen(false)} + onConfirm={handleDelete} + title="일정 삭제" + message={ + <> +

다음 일정을 삭제하시겠습니까?

+

+ {scheduleToDelete?.title} +

+

이 작업은 되돌릴 수 없습니다.

+ + } + loading={deleting} + /> {/* 헤더 */}