import { useEffect, useState, useRef } from "react" import { Link, useParams, useNavigate } from "react-router-dom" import { Plus, ArrowLeft, BookOpen, ToggleLeft, ToggleRight, X, Trash2, MoreVertical, Edit, RefreshCw, AlertCircle } from "lucide-react" import { Card, CardContent } from "../../components/ui/card" import { Button } from "../../components/ui/button" import { Badge } from "../../components/ui/badge" import { Input } from "../../components/ui/input" import { FileUpload } from "../../components/ui/file-upload" import { getCoursesByCategory, getCourseCategories, createCourse, deleteCourse, updateCourseStatus, updateCourse } from "../../api/courses.api" import type { Course, CourseCategory } from "../../types/course.types" function CourseThumbnail({ src, alt, gradient }: { src?: string; alt: string; gradient: string }) { const [imgError, setImgError] = useState(false) if (!src || imgError) { return
} return ( {alt} setImgError(true)} /> ) } export function CoursesPage() { const { categoryId } = useParams<{ categoryId: string }>() const navigate = useNavigate() const [courses, setCourses] = useState([]) const [category, setCategory] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showModal, setShowModal] = useState(false) const [title, setTitle] = useState("") const [description, setDescription] = useState("") const [saving, setSaving] = useState(false) const [saveError, setSaveError] = useState(null) const [newThumbnailFile, setNewThumbnailFile] = useState(null) const [newVideoFile, setNewVideoFile] = useState(null) const [showDeleteModal, setShowDeleteModal] = useState(false) const [courseToDelete, setCourseToDelete] = useState(null) const [deleting, setDeleting] = useState(false) const [togglingId, setTogglingId] = useState(null) const [openMenuId, setOpenMenuId] = useState(null) const menuRef = useRef(null) const [showEditModal, setShowEditModal] = useState(false) const [courseToEdit, setCourseToEdit] = useState(null) const [editTitle, setEditTitle] = useState("") const [editDescription, setEditDescription] = useState("") const [editThumbnail, setEditThumbnail] = useState("") const [updating, setUpdating] = useState(false) const [updateError, setUpdateError] = useState(null) useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(event.target as Node)) { setOpenMenuId(null) } } if (openMenuId !== null) { document.addEventListener("mousedown", handleClickOutside) } return () => document.removeEventListener("mousedown", handleClickOutside) }, [openMenuId]) const fetchCourses = async () => { if (!categoryId) return try { const coursesRes = await getCoursesByCategory(Number(categoryId)) console.log("Courses response:", coursesRes.data.data.courses) setCourses(coursesRes.data.data.courses ?? []) } catch (err) { console.error("Failed to fetch courses:", err) } } useEffect(() => { const fetchData = async () => { if (!categoryId) return try { const [coursesRes, categoriesRes] = await Promise.all([ getCoursesByCategory(Number(categoryId)), getCourseCategories(), ]) setCourses(coursesRes.data.data.courses) const foundCategory = categoriesRes.data.data.categories.find( (c) => c.id === Number(categoryId) ) setCategory(foundCategory ?? null) } catch (err) { console.error("Failed to fetch courses:", err) setError("Failed to load courses") } finally { setLoading(false) } } fetchData() }, [categoryId]) const handleOpenModal = () => { setTitle("") setDescription("") setSaveError(null) setNewThumbnailFile(null) setNewVideoFile(null) setShowModal(true) } const handleCloseModal = () => { setShowModal(false) setTitle("") setDescription("") setSaveError(null) setNewThumbnailFile(null) setNewVideoFile(null) } const handleSave = async () => { if (!title.trim()) { setSaveError("Title is required") return } if (!description.trim()) { setSaveError("Description is required") return } setSaving(true) setSaveError(null) try { await createCourse({ category_id: Number(categoryId), title: title.trim(), description: description.trim(), }) handleCloseModal() await fetchCourses() } catch (err: any) { console.error("Failed to create course:", err) setSaveError(err.response?.data?.message || "Failed to create course") } finally { setSaving(false) } } const handleDeleteClick = (course: Course) => { setCourseToDelete(course) setShowDeleteModal(true) } const handleConfirmDelete = async () => { if (!courseToDelete) return setDeleting(true) try { await deleteCourse(courseToDelete.id) setShowDeleteModal(false) setCourseToDelete(null) await fetchCourses() } catch (err) { console.error("Failed to delete course:", err) } finally { setDeleting(false) } } const handleToggleStatus = async (course: Course) => { setTogglingId(course.id) try { await updateCourseStatus(course.id, !course.is_active) await fetchCourses() } catch (err) { console.error("Failed to update course status:", err) } finally { setTogglingId(null) } } const handleEditClick = (course: Course) => { setCourseToEdit(course) setEditTitle(course.title || "") setEditDescription(course.description || "") setEditThumbnail(course.thumbnail || "") setUpdateError(null) setShowEditModal(true) } const handleCloseEditModal = () => { setShowEditModal(false) setCourseToEdit(null) setEditTitle("") setEditDescription("") setEditThumbnail("") setUpdateError(null) } const handleUpdate = async () => { if (!courseToEdit) return if (!editTitle.trim()) { setUpdateError("Title is required") return } if (!editDescription.trim()) { setUpdateError("Description is required") return } setUpdating(true) setUpdateError(null) try { await updateCourse(courseToEdit.id, { title: editTitle.trim(), description: editDescription.trim(), thumbnail: editThumbnail.trim() || undefined, is_active: courseToEdit.is_active, }) handleCloseEditModal() await fetchCourses() } catch (err: any) { console.error("Failed to update course:", err) setUpdateError(err.response?.data?.message || "Failed to update course") } finally { setUpdating(false) } } const handleCourseClick = (courseId: number) => { navigate(`/content/category/${categoryId}/courses/${courseId}/sub-courses`) } if (loading) { return (

Loading courses...

) } if (error) { return (

{error}

) } return (
{/* Header */}

{category?.name} Courses

{courses.length} courses available

{/* Course grid or empty state */} {courses.length === 0 ? (

No courses yet

No courses found in this category

) : (
{courses.map((course, index) => { const gradients = [ "bg-gradient-to-br from-blue-100 to-blue-200", "bg-gradient-to-br from-purple-100 to-purple-200", "bg-gradient-to-br from-green-100 to-green-200", "bg-gradient-to-br from-yellow-100 to-yellow-200", ] return ( handleCourseClick(course.id)} > {/* Thumbnail */}
{/* Content */}
{/* Status and menu */}
{course.is_active ? "ACTIVE" : "INACTIVE"}
e.stopPropagation()}> {openMenuId === course.id && (
)}
{/* Title */}

{course.title}

{course.description || "No description available"}

{/* Edit button */}
) })}
)} {/* Add Course Modal */} {showModal && (

Add New Course

{saveError && (
{saveError}
)}
setTitle(e.target.value)} />