switch lesson creation to sub_module_lessons flow

Create lessons via question-set + sub-module-lesson attachment instead of video-only handling, and update new-level creation to reuse existing CEFR levels when present.

Made-with: Cursor
This commit is contained in:
Yared Yemane 2026-04-14 06:39:39 -07:00
parent 06a0daedfe
commit 6df388fb98
2 changed files with 73 additions and 18 deletions

View File

@ -349,6 +349,33 @@ export const createPractice = (data: CreatePracticeRequest) =>
.then(() => res) .then(() => res)
}) })
export const createLesson = (data: {
sub_module_id: number
title: string
description?: string
intro_video_url?: string
}) =>
http
.post<CreateQuestionSetResponse>("/question-sets", {
title: data.title,
set_type: "QUIZ",
owner_type: "SUB_MODULE",
owner_id: data.sub_module_id,
...(data.description?.trim() ? { description: data.description.trim() } : {}),
...(data.intro_video_url?.trim() ? { intro_video_url: data.intro_video_url.trim() } : {}),
})
.then((res) => {
const questionSetID = res.data?.data?.id
if (!questionSetID) return res
return http
.post("/course-management/sub-module-lessons", {
sub_module_id: data.sub_module_id,
question_set_id: questionSetID,
intro_video_url: data.intro_video_url,
})
.then(() => res)
})
export const updatePractice = (practiceId: number, data: UpdatePracticeRequest) => export const updatePractice = (practiceId: number, data: UpdatePracticeRequest) =>
http.put(`/course-management/practices/${practiceId}`, data) http.put(`/course-management/practices/${practiceId}`, data)

View File

@ -31,6 +31,7 @@ import { SpinnerIcon } from "../../components/ui/spinner-icon"
import { import {
addQuestionToSet, addQuestionToSet,
createPractice, createPractice,
createLesson,
createQuestion, createQuestion,
createCourse, createCourse,
createCourseCategory, createCourseCategory,
@ -565,6 +566,26 @@ export function HumanLanguagePage() {
} }
} }
const handleCreateLesson = async (subModuleId: number, currentLessonsCount: number) => {
const key = `lesson-${subModuleId}`
setCreatingKey(key)
try {
const next = (currentLessonsCount || 0) + 1
await createLesson({
sub_module_id: subModuleId,
title: `Lesson ${next}`,
description: `Auto-created lesson ${next}`,
})
toast.success("Lesson created")
await loadHierarchy(false)
} catch (error) {
console.error("Failed to create lesson:", error)
toast.error("Failed to create lesson")
} finally {
setCreatingKey(null)
}
}
const requestRemove = (payload: PendingRemove) => { const requestRemove = (payload: PendingRemove) => {
if (payload.ids.length === 0) return if (payload.ids.length === 0) return
setPendingRemove(payload) setPendingRemove(payload)
@ -608,12 +629,17 @@ export function HumanLanguagePage() {
const key = `next-level-${courseId}-${next}` const key = `next-level-${courseId}-${next}`
setCreatingKey(key) setCreatingKey(key)
try { try {
const existingLevel = course.levels.find((l) => l.level.toUpperCase() === next)
if (existingLevel?.level_id) {
await createModuleInLevel(existingLevel.level_id, "Module-1", `${next} Module-1`, 1)
} else {
await createHumanLanguageLesson({ await createHumanLanguageLesson({
course_id: courseId, course_id: courseId,
cefr_level: next, cefr_level: next,
title: "Module-1", title: "Module-1",
description: `${next} Module-1`, description: `${next} Module-1`,
}) })
}
toast.success(`${next} created with Module-1`) toast.success(`${next} created with Module-1`)
await loadHierarchy() await loadHierarchy()
} catch (error) { } catch (error) {
@ -1611,20 +1637,22 @@ export function HumanLanguagePage() {
<Plus className="h-3.5 w-3.5" /> <Plus className="h-3.5 w-3.5" />
New practice New practice
</Button> </Button>
) : panelTab === "lessons" && categoryId ? ( ) : panelTab === "lessons" ? (
<Link
to={`/content/human-language/${categoryId}/${course.course_id}/sub-module/${subModule.id}`}
>
<Button <Button
type="button" type="button"
size="sm" size="sm"
variant="outline" variant="outline"
className="h-8 border-grayScale-200 bg-white px-2 text-[11px] hover:border-brand-200 hover:bg-brand-50/40" className="h-8 border-grayScale-200 bg-white px-2 text-[11px] hover:border-brand-200 hover:bg-brand-50/40"
onClick={() => handleCreateLesson(subModule.id, lessonRows.length)}
disabled={creatingKey === `lesson-${subModule.id}`}
> >
{creatingKey === `lesson-${subModule.id}` ? (
<Loader2 className="h-3.5 w-3.5 animate-spin" />
) : (
<Plus className="h-3.5 w-3.5" /> <Plus className="h-3.5 w-3.5" />
)}
New lesson New lesson
</Button> </Button>
</Link>
) : null} ) : null}
</div> </div>
</div> </div>