From bfbdf0fc19392b43ff15527a2d7fb5b09673f58a Mon Sep 17 00:00:00 2001 From: Yared Yemane Date: Tue, 14 Apr 2026 05:45:35 -0700 Subject: [PATCH] add sub-category and course delete controls in human language page Wire delete actions and confirmation dialogs for selected sub-categories and courses, backed by the new sub-category delete API route. Made-with: Cursor --- src/api/courses.api.ts | 3 + .../content-management/HumanLanguagePage.tsx | 131 ++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/src/api/courses.api.ts b/src/api/courses.api.ts index 452bb6b..314c817 100644 --- a/src/api/courses.api.ts +++ b/src/api/courses.api.ts @@ -153,6 +153,9 @@ export const createCourseCategory = (data: CreateCourseCategoryRequest) => ? http.post("/course-management/sub-categories", { category_id: data.parent_id, name: data.name }) : http.post("/course-management/categories", { name: data.name }) +export const deleteCourseSubCategory = (subCategoryId: number) => + http.delete(`/course-management/sub-categories/${subCategoryId}`) + export const getCoursesByCategory = (categoryId: number) => http.get("/course-management/hierarchy").then((res) => { const rows: UnifiedHierarchyRow[] = res.data?.data ?? [] diff --git a/src/pages/content-management/HumanLanguagePage.tsx b/src/pages/content-management/HumanLanguagePage.tsx index 04a71a2..48843d1 100644 --- a/src/pages/content-management/HumanLanguagePage.tsx +++ b/src/pages/content-management/HumanLanguagePage.tsx @@ -35,6 +35,8 @@ import { createCourse, createCourseCategory, createHumanLanguageLesson, + deleteCourse, + deleteCourseSubCategory, deleteQuestionSet, deleteQuestion, deleteSubModule, @@ -325,6 +327,10 @@ export function HumanLanguagePage() { const [quickCourseName, setQuickCourseName] = useState("") const [quickSearch, setQuickSearch] = useState("") const [quickCreating, setQuickCreating] = useState(false) + const [subCategoryTargetDelete, setSubCategoryTargetDelete] = useState<{ id: number; name: string } | null>(null) + const [courseTargetDelete, setCourseTargetDelete] = useState<{ id: number; name: string } | null>(null) + const [deletingSubCategory, setDeletingSubCategory] = useState(false) + const [deletingCourse, setDeletingCourse] = useState(false) const [deletingKey, setDeletingKey] = useState(null) /** Course IDs whose path body is collapsed (headers stay visible). */ const [collapsedPathIds, setCollapsedPathIds] = useState([]) @@ -656,6 +662,41 @@ export function HumanLanguagePage() { } } + const handleDeleteSelectedSubCategory = async () => { + if (!subCategoryTargetDelete) return + setDeletingSubCategory(true) + try { + await deleteCourseSubCategory(subCategoryTargetDelete.id) + toast.success("Sub-category deleted") + setSubCategoryTargetDelete(null) + setSelectedSubCategoryId("ALL") + setSelectedCourseId("ALL") + await loadHierarchy() + } catch (error) { + console.error("Failed to delete sub-category:", error) + toast.error("Failed to delete sub-category") + } finally { + setDeletingSubCategory(false) + } + } + + const handleDeleteSelectedCourse = async () => { + if (!courseTargetDelete) return + setDeletingCourse(true) + try { + await deleteCourse(courseTargetDelete.id) + toast.success("Course deleted") + setCourseTargetDelete(null) + setSelectedCourseId("ALL") + await loadHierarchy() + } catch (error) { + console.error("Failed to delete course:", error) + toast.error("Failed to delete course") + } finally { + setDeletingCourse(false) + } + } + const loadPracticeQuestionsIfNeeded = async (practiceId: number, forceRefresh = false) => { let skipFetch = false setPracticeQuestionsState((prev) => { @@ -1164,6 +1205,44 @@ export function HumanLanguagePage() { +
+ + + +
+ {loading ? (
@@ -2170,6 +2249,58 @@ export function HumanLanguagePage() { + !open && setSubCategoryTargetDelete(null)}> + + + Delete sub-category? + + {subCategoryTargetDelete + ? `This will permanently delete "${subCategoryTargetDelete.name}" and all courses under it.` + : ""} + + + + + + + + + + !open && setCourseTargetDelete(null)}> + + + Delete course? + + {courseTargetDelete + ? `This will permanently delete "${courseTargetDelete.name}" and all nested content under it.` + : ""} + + + + + + + + + {