import { useEffect, useState } from "react" import { useNavigate } from "react-router-dom" import { Search, Plus, RefreshCw, Edit2, ToggleLeft, ToggleRight } from "lucide-react" import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card" import { Button } from "../../components/ui/button" import { Input } from "../../components/ui/input" import { Select } from "../../components/ui/select" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../../components/ui/table" import { Badge } from "../../components/ui/badge" import { FileUpload } from "../../components/ui/file-upload" import { getCourseCategories, getCoursesByCategory, createCourse, updateCourseStatus, updateCourse } from "../../api/courses.api" import type { Course, CourseCategory } from "../../types/course.types" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "../../components/ui/dialog" import { Textarea } from "../../components/ui/textarea" import { toast } from "sonner" type CourseWithCategory = Course & { category_name: string } export function AllCoursesPage() { const navigate = useNavigate() const [courses, setCourses] = useState([]) const [categories, setCategories] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [search, setSearch] = useState("") const [categoryFilter, setCategoryFilter] = useState<"all" | string>("all") const [createOpen, setCreateOpen] = useState(false) const [createCategoryId, setCreateCategoryId] = useState("") const [createSubCategoryId, setCreateSubCategoryId] = useState("") const [createTitle, setCreateTitle] = useState("") const [createDescription, setCreateDescription] = useState("") const [createThumbnail, setCreateThumbnail] = useState(null) const [createVideo, setCreateVideo] = useState(null) const [creating, setCreating] = useState(false) const [togglingId, setTogglingId] = useState(null) const [editOpen, setEditOpen] = useState(false) const [courseToEdit, setCourseToEdit] = useState(null) const [editTitle, setEditTitle] = useState("") const [editDescription, setEditDescription] = useState("") const [updating, setUpdating] = useState(false) const fetchAllCourses = async () => { setLoading(true) setError(null) try { const categoriesRes = await getCourseCategories() const cats = categoriesRes.data.data.categories ?? [] setCategories(cats) const allCourses: CourseWithCategory[] = [] for (const cat of cats) { const res = await getCoursesByCategory(cat.id) const catCourses = res.data.data.courses ?? [] allCourses.push( ...catCourses.map((c) => ({ ...c, category_name: cat.name, })), ) } setCourses(allCourses) } catch (err) { console.error("Failed to load courses:", err) setError("Failed to load sub-categories") } finally { setLoading(false) } } useEffect(() => { fetchAllCourses() }, []) const filteredCourses = courses.filter((course) => { if (categoryFilter !== "all" && String(course.category_id) !== categoryFilter) { return false } if (search.trim()) { const q = search.toLowerCase() const haystack = `${course.title} ${course.description} ${course.category_name}`.toLowerCase() if (!haystack.includes(q)) return false } return true }) const handleCreateCourse = async () => { const effectiveCategoryId = createSubCategoryId || createCategoryId if (!effectiveCategoryId || !createTitle.trim() || !createDescription.trim()) { toast.error("Missing fields", { description: "Category (or subcategory), title, and description are required.", }) return } setCreating(true) try { await createCourse({ category_id: Number(effectiveCategoryId), title: createTitle.trim(), description: createDescription.trim(), }) toast.success("Sub-category created", { description: `"${createTitle.trim()}" has been created.`, }) setCreateOpen(false) setCreateCategoryId("") setCreateSubCategoryId("") setCreateTitle("") setCreateDescription("") setCreateThumbnail(null) setCreateVideo(null) await fetchAllCourses() } catch (err: any) { console.error("Failed to create course:", err) toast.error("Failed to create sub-category", { description: err?.response?.data?.message || "Please try again.", }) } finally { setCreating(false) } } const handleToggleStatus = async (course: CourseWithCategory) => { setTogglingId(course.id) try { await updateCourseStatus(course.id, !course.is_active) await fetchAllCourses() } catch (err) { console.error("Failed to update course status:", err) toast.error("Failed to update sub-category status") } finally { setTogglingId(null) } } const openEditDialog = (course: CourseWithCategory) => { setCourseToEdit(course) setEditTitle(course.title) setEditDescription(course.description || "") setEditOpen(true) } const handleUpdateCourse = async () => { if (!courseToEdit) return if (!editTitle.trim() || !editDescription.trim()) { toast.error("Missing fields", { description: "Title and description are required.", }) return } setUpdating(true) try { await updateCourse(courseToEdit.id, { title: editTitle.trim(), description: editDescription.trim(), }) toast.success("Sub-category updated") setEditOpen(false) setCourseToEdit(null) await fetchAllCourses() } catch (err: any) { console.error("Failed to update course:", err) toast.error("Failed to update sub-category", { description: err?.response?.data?.message || "Please try again.", }) } finally { setUpdating(false) } } if (loading) { return (

Loading all sub-categories…

) } if (error) { return (

{error}

) } return (
{/* Header */}

All Sub-categories

View and manage sub-categories across all categories.

Sub-category Management {/* Search / Filters */}
setSearch(e.target.value)} className="pl-10 transition-colors focus:border-brand-300 focus:ring-brand-200" />
Showing {filteredCourses.length} of {courses.length} courses
{/* Courses Table */} {filteredCourses.length > 0 ? (
Course Category Status Actions {filteredCourses.map((course, index) => ( navigate( `/content/category/${course.category_id}/courses/${course.id}/sub-courses`, ) } >
{course.title}
{course.description && (
{course.description}
)}
{course.category_name} {course.is_active ? "Active" : "Inactive"}
))}
) : (

No sub-categories found

Try adjusting your search or category filter, or create a new sub-category.

)}
{/* Create course dialog */} Create sub-category Choose a category, add basic details, and optionally attach a thumbnail and intro video.
setCreateTitle(e.target.value)} />