fix category and course loading with duplicate names

Normalize duplicate category names in hierarchy responses and aggregate courses across same-name category IDs so Human Language and Courses tabs consistently show data.

Made-with: Cursor
This commit is contained in:
Yared Yemane 2026-04-14 05:36:54 -07:00
parent da6754e6f5
commit 78111f161f

View File

@ -81,7 +81,10 @@ type CourseHierarchyRow = {
export const getCourseCategories = () => export const getCourseCategories = () =>
http.get("/course-management/hierarchy").then((res) => { http.get("/course-management/hierarchy").then((res) => {
const rows: UnifiedHierarchyRow[] = res.data?.data ?? [] const rows: UnifiedHierarchyRow[] = res.data?.data ?? []
const categoriesMap = new Map<number, { id: number; name: string; is_active: boolean; created_at: string }>() const categoriesMap = new Map<
number,
{ id: number; name: string; is_active: boolean; created_at: string; subCategoryCount: number; courseCount: number }
>()
rows.forEach((r) => { rows.forEach((r) => {
if (!categoriesMap.has(r.category_id)) { if (!categoriesMap.has(r.category_id)) {
categoriesMap.set(r.category_id, { categoriesMap.set(r.category_id, {
@ -89,10 +92,50 @@ export const getCourseCategories = () =>
name: r.category_name, name: r.category_name,
is_active: true, is_active: true,
created_at: new Date().toISOString(), created_at: new Date().toISOString(),
subCategoryCount: 0,
courseCount: 0,
}) })
} }
const category = categoriesMap.get(r.category_id)!
if (r.sub_category_id) category.subCategoryCount += 1
if (r.course_id) category.courseCount += 1
}) })
const categories = Array.from(categoriesMap.values())
// Merge duplicate top-level category names by selecting the richest representative.
type CategoryAggregate = {
id: number
name: string
is_active: boolean
created_at: string
subCategoryCount: number
courseCount: number
}
const categoryByName = new Map<string, CategoryAggregate>()
Array.from(categoriesMap.values()).forEach((category) => {
const key = category.name.trim().toLowerCase()
const existing = categoryByName.get(key)
if (!existing) {
categoryByName.set(key, category)
return
}
if (category.subCategoryCount > existing.subCategoryCount) {
categoryByName.set(key, category)
return
}
if (category.subCategoryCount === existing.subCategoryCount && category.courseCount > existing.courseCount) {
categoryByName.set(key, category)
return
}
if (
category.subCategoryCount === existing.subCategoryCount &&
category.courseCount === existing.courseCount &&
category.id > existing.id
) {
categoryByName.set(key, category)
}
})
const categories = Array.from(categoryByName.values()).map(({ subCategoryCount, courseCount, ...category }) => category)
return { return {
...res, ...res,
data: { data: {
@ -113,17 +156,32 @@ export const createCourseCategory = (data: CreateCourseCategoryRequest) =>
export const getCoursesByCategory = (categoryId: number) => export const getCoursesByCategory = (categoryId: number) =>
http.get("/course-management/hierarchy").then((res) => { http.get("/course-management/hierarchy").then((res) => {
const rows: UnifiedHierarchyRow[] = res.data?.data ?? [] const rows: UnifiedHierarchyRow[] = res.data?.data ?? []
const courses = rows
.filter((r) => r.category_id === categoryId && r.course_id) const requestedCategoryRows = rows.filter((r) => r.category_id === categoryId)
.map((r) => ({ const requestedCategoryName = requestedCategoryRows.find((r) => !!r.category_name)?.category_name?.trim().toLowerCase()
id: Number(r.course_id), const relevantRows = requestedCategoryName
category_id: r.category_id, ? rows.filter((r) => r.category_name?.trim().toLowerCase() === requestedCategoryName)
sub_category_id: r.sub_category_id ?? null, : requestedCategoryRows
title: r.course_title ?? "",
description: "", const courseMap = new Map<number, { id: number; category_id: number; sub_category_id: number | null; title: string; description: string; thumbnail: string; is_active: boolean }>()
thumbnail: "", relevantRows
is_active: true, .filter((r) => r.course_id)
})) .forEach((r) => {
const id = Number(r.course_id)
if (!Number.isFinite(id)) return
if (courseMap.has(id)) return
courseMap.set(id, {
id,
category_id: r.category_id,
sub_category_id: r.sub_category_id ?? null,
title: r.course_title ?? "",
description: "",
thumbnail: "",
is_active: true,
})
})
const courses = Array.from(courseMap.values())
return { return {
...res, ...res,
data: { ...res.data, data: { courses, total_count: courses.length } }, data: { ...res.data, data: { courses, total_count: courses.length } },