diff --git a/src/api/courses.api.ts b/src/api/courses.api.ts index f94ccb6..23f1e7f 100644 --- a/src/api/courses.api.ts +++ b/src/api/courses.api.ts @@ -768,6 +768,7 @@ export const getHumanLanguageHierarchy = () => id: subModuleId, title: row.sub_module_title ?? "", videos: [], + lessons: [], practices: [], }) } @@ -789,6 +790,71 @@ export const getHumanLanguageHierarchy = () => }), })) + const subModuleIds = subCategories.flatMap((sub) => + sub.courses.flatMap((course) => + course.levels.flatMap((levelNode) => levelNode.modules.flatMap((moduleNode) => moduleNode.sub_modules.map((sm) => sm.id))), + ), + ) + + type QuestionSetListItem = { + id: number + title?: string + set_type?: string + status?: string + intro_video_url?: string | null + question_count?: number + created_at?: string + } + + const questionSetsBySubModule = new Map() + await Promise.all( + subModuleIds.map(async (subModuleID) => { + try { + const questionSetRes = await http.get("/question-sets/by-owner", { + params: { owner_type: "SUB_MODULE", owner_id: subModuleID }, + }) + const payload = questionSetRes.data?.data + const sets = Array.isArray(payload) + ? payload + : Array.isArray((payload as { question_sets?: QuestionSetListItem[] } | undefined)?.question_sets) + ? ((payload as { question_sets: QuestionSetListItem[] }).question_sets ?? []) + : [] + questionSetsBySubModule.set(subModuleID, sets as QuestionSetListItem[]) + } catch { + questionSetsBySubModule.set(subModuleID, []) + } + }), + ) + + subCategories.forEach((sub) => { + sub.courses.forEach((course) => { + course.levels.forEach((levelNode) => { + levelNode.modules.forEach((moduleNode) => { + moduleNode.sub_modules.forEach((subModuleNode) => { + const sets = questionSetsBySubModule.get(subModuleNode.id) ?? [] + const lessons = sets + .filter((set) => String(set.set_type ?? "").toUpperCase() === "QUIZ") + .sort((a, b) => { + const ad = Date.parse(String(a.created_at ?? "")) || 0 + const bd = Date.parse(String(b.created_at ?? "")) || 0 + return ad - bd + }) + .map((set, idx) => ({ + id: Number(set.id), + question_set_id: Number(set.id), + title: set.title?.trim() || `Lesson ${idx + 1}`, + status: set.status ?? "DRAFT", + question_count: Number(set.question_count ?? 0), + display_order: idx + 1, + intro_video_url: set.intro_video_url ?? null, + })) + subModuleNode.lessons = lessons + }) + }) + }) + }) + }) + return { ...res, data: { diff --git a/src/pages/content-management/HumanLanguagePage.tsx b/src/pages/content-management/HumanLanguagePage.tsx index edb7994..3bc747f 100644 --- a/src/pages/content-management/HumanLanguagePage.tsx +++ b/src/pages/content-management/HumanLanguagePage.tsx @@ -57,7 +57,6 @@ import type { HumanLanguageCourseTree, HumanLanguageSubCategoryTree, LearningPathPractice, - LearningPathVideo, QuestionDetail, QuestionSetQuestion, } from "../../types/course.types" @@ -1506,9 +1505,26 @@ export function HumanLanguagePage() { const smKey = `${course.course_id}-${subModule.id}` const panelTab = subModulePanelTab[smKey] ?? "lessons" const cardSel = getSubModuleSelection(smKey) - const lessonRows: LearningPathVideo[] = [...subModule.videos].sort( - (a, b) => a.display_order - b.display_order, - ) + const lessonRows = [ + ...(subModule.lessons ?? []).map((lesson) => ({ + id: lesson.id, + title: lesson.title, + display_order: lesson.display_order, + status: lesson.status, + question_count: lesson.question_count, + intro_video_url: lesson.intro_video_url ?? "", + })), + ...((subModule.lessons?.length ?? 0) === 0 + ? subModule.videos.map((video) => ({ + id: video.id, + title: video.title, + display_order: video.display_order, + status: "PUBLISHED", + question_count: 0, + intro_video_url: video.video_url ?? "", + })) + : []), + ].sort((a, b) => a.display_order - b.display_order) const practiceRows: LearningPathPractice[] = [...subModule.practices].sort( (a, b) => (a.display_order ?? 0) - (b.display_order ?? 0), ) @@ -1643,9 +1659,8 @@ export function HumanLanguagePage() { {panelTab === "lessons" ? ( lessonRows.length === 0 ? (
- No lesson videos yet. Use{" "} - Open editor to add - videos. + No lessons yet. Use{" "} + New lesson to create one.
) : (
@@ -1672,10 +1687,14 @@ export function HumanLanguagePage() {

{v.title}

-

- Lesson {idx + 1} · {formatDurationSeconds(v.duration ?? 0)} · Order{" "} - {v.display_order} -

+
+ + {(v.status ?? "DRAFT").replace(/_/g, " ").toLowerCase()} + + + Lesson {idx + 1} · {v.question_count} Q · Order {v.display_order} + +
@@ -1685,7 +1704,7 @@ export function HumanLanguagePage() { {selectedLesson ? (

- Lesson content + Lesson detail

{selectedLesson.title} @@ -1698,34 +1717,34 @@ export function HumanLanguagePage() {

-
Duration
+
Questions
- {formatDurationSeconds(selectedLesson.duration ?? 0)} + {selectedLesson.question_count}
-
Video
+
Intro video
- {selectedLesson.video_url ? ( + {selectedLesson.intro_video_url ? ( - {selectedLesson.video_url} + {selectedLesson.intro_video_url} ) : ( - No video URL set — use Open editor to add one. + No intro video URL set for this lesson. )} - {selectedLesson.video_url + {selectedLesson.intro_video_url ? renderMediaPreview( - selectedLesson.video_url, + selectedLesson.intro_video_url, "video", "mt-3", - "Video preview", + "Intro video preview", ) : null}
diff --git a/src/types/course.types.ts b/src/types/course.types.ts index 5b6c62d..25aafcc 100644 --- a/src/types/course.types.ts +++ b/src/types/course.types.ts @@ -719,6 +719,15 @@ export interface HumanLanguageSubModule { id: number title: string videos: LearningPathVideo[] + lessons?: { + id: number + question_set_id: number + title: string + status: string + question_count: number + display_order: number + intro_video_url?: string | null + }[] practices: LearningPathPractice[] }