From f1515cdd723cf41aad3b329ad94eef7a866b8250 Mon Sep 17 00:00:00 2001 From: wallace Date: Wed, 19 Nov 2025 11:56:13 +0900 Subject: [PATCH] =?UTF-8?q?admin=20=ED=8E=98=EC=9D=B4=EC=A7=80=EB=93=A4=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=BB=A4=EC=84=9C=20=EB=B3=80=EA=B2=BD1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/admin/certificates/page.tsx | 10 +- .../admin/courses/CourseRegistrationModal.tsx | 10 +- src/app/admin/courses/page.tsx | 12 +- src/app/admin/id/page.tsx | 24 +- src/app/admin/lessons/page.tsx | 518 ++++++++++++++---- src/app/admin/logs/page.tsx | 10 +- src/app/admin/notices/page.tsx | 10 +- src/app/admin/questions/page.tsx | 10 +- src/app/admin/resources/page.tsx | 10 +- src/app/svgs/backarrow.tsx | 41 ++ 10 files changed, 491 insertions(+), 164 deletions(-) create mode 100644 src/app/svgs/backarrow.tsx diff --git a/src/app/admin/certificates/page.tsx b/src/app/admin/certificates/page.tsx index 1c0f92f..92408f2 100644 --- a/src/app/admin/certificates/page.tsx +++ b/src/app/admin/certificates/page.tsx @@ -65,7 +65,7 @@ export default function AdminCertificatesPage() { type="button" onClick={() => setCurrentPage(1)} aria-label="맨 앞 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === 1} >
@@ -79,7 +79,7 @@ export default function AdminCertificatesPage() { type="button" onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} aria-label="이전 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === 1} > @@ -95,7 +95,7 @@ export default function AdminCertificatesPage() { onClick={() => setCurrentPage(n)} aria-current={active ? 'page' : undefined} className={[ - 'flex items-center justify-center rounded-[1000px] size-[32px]', + 'flex items-center justify-center rounded-[1000px] size-[32px] cursor-pointer', active ? 'bg-[#ecf0ff]' : 'bg-white', ].join(' ')} > @@ -109,7 +109,7 @@ export default function AdminCertificatesPage() { type="button" onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} aria-label="다음 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === totalPages} > @@ -120,7 +120,7 @@ export default function AdminCertificatesPage() { type="button" onClick={() => setCurrentPage(totalPages)} aria-label="맨 뒤 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === totalPages} >
diff --git a/src/app/admin/courses/CourseRegistrationModal.tsx b/src/app/admin/courses/CourseRegistrationModal.tsx index cf05938..4a92e69 100644 --- a/src/app/admin/courses/CourseRegistrationModal.tsx +++ b/src/app/admin/courses/CourseRegistrationModal.tsx @@ -193,7 +193,7 @@ export default function CourseRegistrationModal({ open, onClose, onSave, onDelet @@ -309,14 +309,14 @@ export default function CourseRegistrationModal({ open, onClose, onSave, onDelet diff --git a/src/app/admin/courses/page.tsx b/src/app/admin/courses/page.tsx index 32e0449..982cbad 100644 --- a/src/app/admin/courses/page.tsx +++ b/src/app/admin/courses/page.tsx @@ -107,7 +107,7 @@ export default function AdminCoursesPage() { @@ -201,7 +201,7 @@ export default function AdminCoursesPage() { type="button" onClick={() => setCurrentPage(1)} aria-label="맨 앞 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === 1} >
@@ -215,7 +215,7 @@ export default function AdminCoursesPage() { type="button" onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} aria-label="이전 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === 1} > @@ -231,7 +231,7 @@ export default function AdminCoursesPage() { onClick={() => setCurrentPage(n)} aria-current={active ? 'page' : undefined} className={[ - 'flex items-center justify-center rounded-[1000px] size-[32px]', + 'flex items-center justify-center rounded-[1000px] size-[32px] cursor-pointer', active ? 'bg-[#ecf0ff]' : 'bg-white', ].join(' ')} > @@ -245,7 +245,7 @@ export default function AdminCoursesPage() { type="button" onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} aria-label="다음 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === totalPages} > @@ -256,7 +256,7 @@ export default function AdminCoursesPage() { type="button" onClick={() => setCurrentPage(totalPages)} aria-label="맨 뒤 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === totalPages} >
diff --git a/src/app/admin/id/page.tsx b/src/app/admin/id/page.tsx index 0f90742..174ef16 100644 --- a/src/app/admin/id/page.tsx +++ b/src/app/admin/id/page.tsx @@ -186,7 +186,7 @@ export default function AdminIdPage() { type="button" onClick={() => setActiveTab(tab.id)} className={[ - "pb-4 px-1 text-[16px] font-medium leading-[1.5] transition-colors relative", + "pb-4 px-1 text-[16px] font-medium leading-[1.5] transition-colors relative cursor-pointer", activeTab === tab.id ? "text-[#1f2b91] font-semibold" : "text-[#6c7682]", @@ -269,7 +269,7 @@ export default function AdminIdPage() { type="button" onClick={() => changeUserRole(user.id, role)} className={[ - "w-full px-4 py-2 text-left text-[14px] leading-[1.5] hover:bg-gray-50 transition-colors", + "w-full px-4 py-2 text-left text-[14px] leading-[1.5] hover:bg-gray-50 transition-colors cursor-pointer", user.role === role ? "text-[#1f2b91] font-semibold bg-[#ecf0ff]" : "text-[#1b2027]", @@ -303,7 +303,7 @@ export default function AdminIdPage() { @@ -331,7 +331,7 @@ export default function AdminIdPage() { type="button" onClick={() => setCurrentPage(1)} aria-label="맨 앞 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === 1} >
@@ -345,7 +345,7 @@ export default function AdminIdPage() { type="button" onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} aria-label="이전 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === 1} > @@ -361,7 +361,7 @@ export default function AdminIdPage() { onClick={() => setCurrentPage(n)} aria-current={active ? 'page' : undefined} className={[ - 'flex items-center justify-center rounded-[1000px] size-[32px]', + 'flex items-center justify-center rounded-[1000px] size-[32px] cursor-pointer', active ? 'bg-[#ecf0ff]' : 'bg-white', ].join(' ')} > @@ -375,7 +375,7 @@ export default function AdminIdPage() { type="button" onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} aria-label="다음 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === totalPages} > @@ -386,7 +386,7 @@ export default function AdminIdPage() { type="button" onClick={() => setCurrentPage(totalPages)} aria-label="맨 뒤 페이지" - className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40" + className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40 cursor-pointer disabled:cursor-not-allowed" disabled={currentPage === totalPages} >
@@ -426,14 +426,14 @@ export default function AdminIdPage() { @@ -465,14 +465,14 @@ export default function AdminIdPage() { diff --git a/src/app/admin/lessons/page.tsx b/src/app/admin/lessons/page.tsx index eb68c65..d55b7da 100644 --- a/src/app/admin/lessons/page.tsx +++ b/src/app/admin/lessons/page.tsx @@ -1,13 +1,25 @@ 'use client'; -import { useState, useMemo } from "react"; +import { useState, useMemo, useRef, useEffect } from "react"; import AdminSidebar from "@/app/components/AdminSidebar"; import ChevronDownSvg from "@/app/svgs/chevrondownsvg"; +import DropdownIcon from "@/app/svgs/dropdownicon"; +import BackArrowSvg from "@/app/svgs/backarrow"; export default function AdminLessonsPage() { // TODO: 나중에 실제 데이터로 교체 const items: any[] = []; const [currentPage, setCurrentPage] = useState(1); + const [isRegistrationMode, setIsRegistrationMode] = useState(false); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const dropdownRef = useRef(null); + + // 등록 폼 상태 + const [selectedCourse, setSelectedCourse] = useState(""); + const [lessonName, setLessonName] = useState(""); + const [learningGoal, setLearningGoal] = useState(""); + const [courseVideoCount, setCourseVideoCount] = useState(0); + const [vrContentCount, setVrContentCount] = useState(0); const totalCount = useMemo(() => items.length, [items]); @@ -19,6 +31,47 @@ export default function AdminLessonsPage() { return items.slice(startIndex, endIndex); }, [items, currentPage]); + // TODO: 나중에 실제 데이터로 교체 + const courseOptions = [ + { id: "1", name: "교육과정 1" }, + { id: "2", name: "교육과정 2" }, + { id: "3", name: "교육과정 3" }, + ]; + + // 외부 클릭 시 드롭다운 닫기 + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + setIsDropdownOpen(false); + } + }; + + if (isDropdownOpen) { + document.addEventListener("mousedown", handleClickOutside); + } + + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [isDropdownOpen]); + + const handleBackClick = () => { + setIsRegistrationMode(false); + // 폼 초기화 + setSelectedCourse(""); + setLessonName(""); + setLearningGoal(""); + setCourseVideoCount(0); + setVrContentCount(0); + }; + + const handleRegisterClick = () => { + setIsRegistrationMode(true); + }; + return (
{/* 메인 레이아웃 */} @@ -31,126 +84,359 @@ export default function AdminLessonsPage() { {/* 메인 콘텐츠 */}
- {/* 제목 영역 */} -
-

- 강좌 관리 -

-
- - {/* 헤더 영역 (제목과 콘텐츠 사이) */} -
-

- 총 {totalCount}건 -

- -
- - {/* 콘텐츠 영역 */} -
- {items.length === 0 ? ( -
-

- 등록된 강좌가 없습니다. -
- 강좌를 등록해주세요. -

+ {isRegistrationMode ? ( + /* 등록 모드 */ +
+ {/* 헤더 */} +
+
+ +

+ 강좌 등록 +

+
- ) : ( - <> - {/* TODO: 테이블 또는 리스트를 여기에 추가 */} - - {/* 페이지네이션 - 10개 초과일 때만 표시 */} - {items.length > ITEMS_PER_PAGE && (() => { - // 페이지 번호를 10단위로 표시 - const pageGroup = Math.floor((currentPage - 1) / 10); - const startPage = pageGroup * 10 + 1; - const endPage = Math.min(startPage + 9, totalPages); - const visiblePages = Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i); - return ( -
-
- {/* First (맨 앞으로) */} - + {isDropdownOpen && ( +
+ {courseOptions.map((course, index) => ( + + ))} +
+ )} +
+
+ + {/* 강좌명 */} +
+ + setLessonName(e.target.value)} + placeholder="강좌명을 입력해 주세요." + className="h-[40px] px-[12px] py-[8px] border border-[#dee1e6] rounded-[8px] bg-white text-[16px] font-normal leading-[1.5] text-[#1b2027] placeholder:text-[#b1b8c0] focus:outline-none focus:ring-2 focus:ring-[#1f2b91] focus:border-transparent" + /> +
+ + {/* 학습 목표 */} +
+ +
+