From 3ef3990f1dc50ffcb6104e3a150aac551c24bacd Mon Sep 17 00:00:00 2001 From: wallace Date: Mon, 1 Dec 2025 11:31:09 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B5=90=EC=9C=A1=EA=B3=BC=EC=A0=95=EC=A0=95?= =?UTF-8?q?=20=EC=83=81=EC=84=B8=EB=B3=B4=EA=B8=B0=20=EC=88=98=EC=A0=951?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/course-list/[id]/page.tsx | 317 ++++++++++++++++-------------- src/app/menu/layout.tsx | 2 +- src/app/page.tsx | 2 +- 3 files changed, 169 insertions(+), 152 deletions(-) diff --git a/src/app/course-list/[id]/page.tsx b/src/app/course-list/[id]/page.tsx index fd898ab..f70918b 100644 --- a/src/app/course-list/[id]/page.tsx +++ b/src/app/course-list/[id]/page.tsx @@ -33,6 +33,7 @@ export default function CourseDetailPage() { const params = useParams(); const router = useRouter(); const [course, setCourse] = useState(null); + const [lectures, setLectures] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -43,58 +44,37 @@ export default function CourseDetailPage() { try { setLoading(true); setError(null); - + let data: any = null; - - // 먼저 getLecture 시도 + const subjectId = String(params.id); + + // getSubjects로 과목 정보 가져오기 try { - const response = await apiService.getLecture(params.id as string); - data = response.data; - } catch (lectureErr) { - console.warn('getLecture 실패, getSubjects로 재시도:', lectureErr); - - // getLecture 실패 시 getSubjects로 폴백 - try { - const subjectsResponse = await apiService.getSubjects(); - let subjectsData: any[] = []; - - if (Array.isArray(subjectsResponse.data)) { - subjectsData = subjectsResponse.data; - } else if (subjectsResponse.data && typeof subjectsResponse.data === 'object') { - subjectsData = subjectsResponse.data.items || - subjectsResponse.data.courses || - subjectsResponse.data.data || - subjectsResponse.data.list || - subjectsResponse.data.subjects || - subjectsResponse.data.subjectList || - []; - } - - // ID로 과목 찾기 - data = subjectsData.find((s: any) => String(s.id || s.subjectId) === String(params.id)); - - if (!data) { - // getLectures로도 시도 - try { - const lecturesResponse = await apiService.getLectures(); - const lectures = Array.isArray(lecturesResponse.data) - ? lecturesResponse.data - : lecturesResponse.data?.items || lecturesResponse.data?.lectures || lecturesResponse.data?.data || []; - - data = lectures.find((l: any) => String(l.id || l.lectureId) === String(params.id)); - } catch (lecturesErr) { - console.error('getLectures 실패:', lecturesErr); - } - } - } catch (subjectsErr) { - console.error('getSubjects 실패:', subjectsErr); + const subjectsResponse = await apiService.getSubjects(); + let subjectsData: any[] = []; + + if (Array.isArray(subjectsResponse.data)) { + subjectsData = subjectsResponse.data; + } else if (subjectsResponse.data && typeof subjectsResponse.data === 'object') { + subjectsData = subjectsResponse.data.items || + subjectsResponse.data.courses || + subjectsResponse.data.data || + subjectsResponse.data.list || + subjectsResponse.data.subjects || + subjectsResponse.data.subjectList || + []; } + + // ID로 과목 찾기 + data = subjectsData.find((s: any) => String(s.id || s.subjectId) === subjectId); + } catch (subjectsErr) { + console.error('getSubjects 실패:', subjectsErr); } - + if (!data) { throw new Error('강좌를 찾을 수 없습니다.'); } - + // 썸네일 이미지 가져오기 let thumbnail = '/imgs/talk.png'; if (data.imageKey) { @@ -107,43 +87,60 @@ export default function CourseDetailPage() { console.error('이미지 다운로드 실패:', imgErr); } } - - // 강좌의 차시(lessons) 정보 가져오기 - let lessons: any[] = []; - if (data.lessons && Array.isArray(data.lessons)) { - lessons = data.lessons; - } else if (data.lectureId) { - // lectureId가 있으면 해당 강좌의 차시 정보 가져오기 시도 - try { - const lectureResponse = await apiService.getLecture(data.lectureId); - if (lectureResponse.data?.lessons) { - lessons = lectureResponse.data.lessons; - } - } catch (err) { - console.warn('차시 정보 가져오기 실패:', err); - } - } - - // API 응답 데이터를 CourseDetail 타입으로 변환 - const courseDetail: CourseDetail = { - id: String(data.id || params.id), - status: data.status || "수강 예정", - title: data.title || data.lectureName || data.subjectName || '', - goal: data.objective || data.goal || '', - method: data.method || '', - summary: data.summary || `VOD · 총 ${lessons.length || 0}강`, - submitSummary: data.submitSummary || '', - thumbnail: thumbnail, - lessons: lessons.map((lesson: any, index: number) => ({ - id: String(lesson.id || lesson.lessonId || index + 1), - title: `${index + 1}. ${lesson.title || lesson.lessonName || ''}`, - duration: lesson.duration || '00:00', - state: lesson.isCompleted ? "제출완료" : "제출대기", - action: lesson.isCompleted ? "복습하기" : (index === 0 ? "수강하기" : "이어서 수강하기"), - })), - }; - setCourse(courseDetail); + // getLectures로 모든 lecture 가져오기 + let allLectures: any[] = []; + try { + const lecturesResponse = await apiService.getLectures(); + if (Array.isArray(lecturesResponse.data)) { + allLectures = lecturesResponse.data; + } else if (lecturesResponse.data && typeof lecturesResponse.data === 'object') { + allLectures = lecturesResponse.data.items || + lecturesResponse.data.lectures || + lecturesResponse.data.data || + lecturesResponse.data.list || + []; + } + + // subjectId로 필터링 + const filteredLectures = allLectures.filter((lecture: any) => + String(lecture.subjectId || lecture.subject_id) === subjectId + ); + + setLectures(filteredLectures); + + // API 응답 데이터를 CourseDetail 타입으로 변환 + const courseDetail: CourseDetail = { + id: String(data.id || params.id), + status: data.status || "수강 예정", + title: data.title || data.lectureName || data.subjectName || '', + goal: data.objective || data.goal || '', + method: data.method || '', + summary: data.summary || `VOD · 총 ${filteredLectures.length || 0}강`, + submitSummary: data.submitSummary || '', + thumbnail: thumbnail, + lessons: [], + }; + + setCourse(courseDetail); + } catch (lecturesErr) { + console.error('getLectures 실패:', lecturesErr); + + // API 응답 데이터를 CourseDetail 타입으로 변환 (lecture 없이) + const courseDetail: CourseDetail = { + id: String(data.id || params.id), + status: data.status || "수강 예정", + title: data.title || data.lectureName || data.subjectName || '', + goal: data.objective || data.goal || '', + method: data.method || '', + summary: data.summary || `VOD · 총 0강`, + submitSummary: data.submitSummary || '', + thumbnail: thumbnail, + lessons: [], + }; + + setCourse(courseDetail); + } } catch (err) { console.error('강좌 조회 실패:', err); setError(err instanceof Error ? err.message : '강좌를 불러오는데 실패했습니다.'); @@ -229,9 +226,9 @@ export default function CourseDetailPage() {
{/* 이미지 컨테이너 */}
- {course.title}
- {/* 차시 리스트 */} + {/* Lecture 리스트 */}
- {course.lessons.map((l) => { - const isSubmitted = l.state === "제출완료"; - const submitBtnBorder = isSubmitted - ? "border-transparent" - : (l.action === "이어서 수강하기" || l.action === "수강하기" ? "border-[#b1b8c0]" : "border-[#8c95a1]"); - const submitBtnText = isSubmitted ? "text-[#384fbf]" : (l.action === "이어서 수강하기" || l.action === "수강하기" ? "text-[#b1b8c0]" : "text-[#4c5561]"); - const rightBtnStyle = - l.action === "이어서 수강하기" || l.action === "수강하기" - ? "bg-[#ecf0ff] text-[#384fbf]" - : "bg-[#f1f3f5] text-[#4c5561]"; - - return ( -
-
-
- {/* 차시 정보 */} -
-
-

{l.title}

-
-

{l.duration}

+ {lectures.length > 0 ? ( + lectures.map((lecture: any, index: number) => { + const isSubmitted = false; // TODO: 진행률 API에서 가져와야 함 + const action = isSubmitted ? "복습하기" : (index === 0 ? "수강하기" : "이어서 수강하기"); + const submitBtnBorder = isSubmitted + ? "border-transparent" + : (action === "이어서 수강하기" || action === "수강하기" ? "border-[#b1b8c0]" : "border-[#8c95a1]"); + const submitBtnText = isSubmitted ? "text-[#384fbf]" : (action === "이어서 수강하기" || action === "수강하기" ? "text-[#b1b8c0]" : "text-[#4c5561]"); + const rightBtnStyle = + action === "이어서 수강하기" || action === "수강하기" + ? "bg-[#ecf0ff] text-[#384fbf]" + : "bg-[#f1f3f5] text-[#4c5561]"; + + return ( +
+
+
+ {/* Lecture 정보 */} +
+
+

+ {index + 1}. {lecture.title || lecture.lectureName || ''} +

+
+

+ {lecture.duration || '00:00'} +

+
-
- {/* 버튼 영역 */} -
-
- {/* 학습 제출 버튼 */} -
- ) : ( + ) : ( +

학습 제출 하기

+ )} + + + {/* 수강/복습 버튼 */} + - - {/* 수강/복습 버튼 */} - + action === "이어서 수강하기" || action === "수강하기" ? "text-[#384fbf]" : "text-[#4c5561]", + ].join(" ")}>{action}

+ +
-
- ); - })} + ); + }) + ) : ( +
+

등록된 강의가 없습니다.

+
+ )}
diff --git a/src/app/menu/layout.tsx b/src/app/menu/layout.tsx index 41cb205..0402f73 100644 --- a/src/app/menu/layout.tsx +++ b/src/app/menu/layout.tsx @@ -4,7 +4,7 @@ import MenuSidebar from "./MenuSidebar"; export default function MenuLayout({ children }: { children: ReactNode }) { return (
-