add quick-create path on empty human language view

Allow creating the initial subcategory/course path directly from the Human Language page empty state so module and sub-module creation can start immediately.

Made-with: Cursor
This commit is contained in:
Yared Yemane 2026-04-07 06:50:35 -07:00
parent ee2dbc5792
commit e6adf2850e

View File

@ -4,7 +4,7 @@ import { BookOpen, ChevronDown, ChevronRight, Languages, Loader2, Plus } from "l
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card"
import { Button } from "../../components/ui/button"
import { SpinnerIcon } from "../../components/ui/spinner-icon"
import { createHumanLanguageLesson, getHumanLanguageHierarchy } from "../../api/courses.api"
import { createCourse, createHumanLanguageLesson, getHumanLanguageHierarchy } from "../../api/courses.api"
import type { HumanLanguageCourseTree, HumanLanguageSubCategoryTree } from "../../types/course.types"
import { toast } from "sonner"
@ -20,6 +20,9 @@ export function HumanLanguagePage() {
const [selectedLevel, setSelectedLevel] = useState<CefrLevel | "ALL">("ALL")
const [collapsedLevels, setCollapsedLevels] = useState<CefrLevel[]>([])
const [creatingKey, setCreatingKey] = useState<string | null>(null)
const [quickSubCategoryName, setQuickSubCategoryName] = useState("")
const [quickCourseName, setQuickCourseName] = useState("")
const [quickCreating, setQuickCreating] = useState(false)
const loadHierarchy = async () => {
setLoading(true)
@ -147,6 +150,35 @@ export function HumanLanguagePage() {
}
}
const handleQuickCreatePath = async () => {
if (!categoryId) {
toast.error("Human Language category is not available")
return
}
if (!quickSubCategoryName.trim() || !quickCourseName.trim()) {
toast.error("Subcategory and course names are required")
return
}
setQuickCreating(true)
try {
const title = `${quickSubCategoryName.trim()} - ${quickCourseName.trim()}`
await createCourse({
category_id: categoryId,
title,
description: `${quickSubCategoryName.trim()} / ${quickCourseName.trim()}`,
})
toast.success("Subcategory/course path created")
setQuickSubCategoryName("")
setQuickCourseName("")
await loadHierarchy()
} catch (error) {
console.error("Failed to quick-create language path:", error)
toast.error("Failed to create subcategory/course path")
} finally {
setQuickCreating(false)
}
}
return (
<div className="space-y-6">
<div className="rounded-2xl border border-grayScale-200 bg-gradient-to-r from-white to-brand-50/30 p-5 shadow-sm">
@ -235,6 +267,42 @@ export function HumanLanguagePage() {
</div>
) : (
<div className="space-y-3">
{availableCourses.length === 0 ? (
<Card className="border-grayScale-200/80">
<CardContent className="flex flex-col items-start gap-3 p-4">
<p className="text-sm text-grayScale-600">
No Human Language subcategory/course is available yet. Create the language course path first, then you can add incremental modules and sub-modules per level.
</p>
<div className="grid w-full grid-cols-1 gap-2 md:grid-cols-3">
<input
className="h-10 rounded-md border border-grayScale-200 bg-white px-3 text-sm"
placeholder="Subcategory (e.g., English)"
value={quickSubCategoryName}
onChange={(e) => setQuickSubCategoryName(e.target.value)}
/>
<input
className="h-10 rounded-md border border-grayScale-200 bg-white px-3 text-sm"
placeholder="Course (e.g., Speaking)"
value={quickCourseName}
onChange={(e) => setQuickCourseName(e.target.value)}
/>
<Button onClick={handleQuickCreatePath} disabled={quickCreating || !categoryId}>
{quickCreating ? "Creating..." : "Quick Create Path"}
</Button>
</div>
<div className="flex flex-wrap gap-2">
<Link to="/content/courses">
<Button variant="outline">Open Courses</Button>
</Link>
{categoryId ? (
<Link to={`/content/category/${categoryId}/courses`}>
<Button>Open Human Language Courses</Button>
</Link>
) : null}
</div>
</CardContent>
</Card>
) : null}
{CEFR_LEVELS.filter((l) => selectedLevel === "ALL" || l === selectedLevel).map((level) => {
const modulesByCourse = selectedCourses
.map((course: HumanLanguageCourseTree) => {