diff --git a/src/api/team.api.ts b/src/api/team.api.ts index c9b3270..c0b3d8f 100644 --- a/src/api/team.api.ts +++ b/src/api/team.api.ts @@ -1,5 +1,5 @@ import http from "./http" -import type { GetTeamMembersResponse, GetTeamMemberResponse } from "../types/team.types" +import type { GetTeamMembersResponse, GetTeamMemberResponse, CreateTeamMemberRequest } from "../types/team.types" export const getTeamMembers = (page?: number, pageSize?: number) => http.get("/team/members", { @@ -11,3 +11,6 @@ export const getTeamMembers = (page?: number, pageSize?: number) => export const getTeamMemberById = (id: number) => http.get(`/team/members/${id}`) + +export const createTeamMember = (data: CreateTeamMemberRequest) => + http.post("/team/register", data) diff --git a/src/app/AppRoutes.tsx b/src/app/AppRoutes.tsx index a93f80f..09cf9a8 100644 --- a/src/app/AppRoutes.tsx +++ b/src/app/AppRoutes.tsx @@ -35,6 +35,7 @@ import { IssuesPage } from "../pages/issues/IssuesPage" import { ProfilePage } from "../pages/ProfilePage" import { SettingsPage } from "../pages/SettingsPage" import { TeamManagementPage } from "../pages/team/TeamManagementPage" +import { AddTeamMemberPage } from "../pages/team/AddTeamMemberPage" import { TeamMemberDetailPage } from "../pages/team/TeamMemberDetailPage" import { LoginPage } from "../pages/auth/LoginPage" import { ForgotPasswordPage } from "../pages/auth/ForgotPasswordPage" @@ -89,6 +90,7 @@ export function AppRoutes() { } /> } /> + } /> } /> } /> } /> diff --git a/src/pages/content-management/AllCoursesPage.tsx b/src/pages/content-management/AllCoursesPage.tsx index 3c2cb6a..3935c08 100644 --- a/src/pages/content-management/AllCoursesPage.tsx +++ b/src/pages/content-management/AllCoursesPage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react" import { useNavigate } from "react-router-dom" -import { Search, Plus, RefreshCw } from "lucide-react" +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" @@ -15,7 +15,7 @@ import { } from "../../components/ui/table" import { Badge } from "../../components/ui/badge" import { FileUpload } from "../../components/ui/file-upload" -import { getCourseCategories, getCoursesByCategory, createCourse } from "../../api/courses.api" +import { getCourseCategories, getCoursesByCategory, createCourse, updateCourseStatus, updateCourse } from "../../api/courses.api" import type { Course, CourseCategory } from "../../types/course.types" import { Dialog, @@ -41,11 +41,18 @@ export function AllCoursesPage() { 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) @@ -92,9 +99,11 @@ export function AllCoursesPage() { }) const handleCreateCourse = async () => { - if (!createCategoryId || !createTitle.trim() || !createDescription.trim()) { + const effectiveCategoryId = createSubCategoryId || createCategoryId + + if (!effectiveCategoryId || !createTitle.trim() || !createDescription.trim()) { toast.error("Missing fields", { - description: "Category, title, and description are required.", + description: "Category (or subcategory), title, and description are required.", }) return } @@ -102,7 +111,7 @@ export function AllCoursesPage() { setCreating(true) try { await createCourse({ - category_id: Number(createCategoryId), + category_id: Number(effectiveCategoryId), title: createTitle.trim(), description: createDescription.trim(), }) @@ -113,6 +122,7 @@ export function AllCoursesPage() { setCreateOpen(false) setCreateCategoryId("") + setCreateSubCategoryId("") setCreateTitle("") setCreateDescription("") setCreateThumbnail(null) @@ -128,11 +138,60 @@ export function AllCoursesPage() { } } + 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 course 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("Course updated") + setEditOpen(false) + setCourseToEdit(null) + await fetchAllCourses() + } catch (err: any) { + console.error("Failed to update course:", err) + toast.error("Failed to update course", { + description: err?.response?.data?.message || "Please try again.", + }) + } finally { + setUpdating(false) + } + } + if (loading) { return (
-
- +
+

Loading all courses…

@@ -263,19 +322,48 @@ export function AllCoursesPage() { - +
+ + + +
))} @@ -298,7 +386,7 @@ export function AllCoursesPage() { {/* Create course dialog */} - + Create course @@ -308,24 +396,48 @@ export function AllCoursesPage() {
-
-
+
+
-
+
+ + +
+
@@ -407,6 +519,65 @@ export function AllCoursesPage() {
+ + {/* Edit course dialog */} + + + + Edit course + + Update the title and description for this course. Status can be toggled from the + table. + + + +
+
+ + setEditTitle(e.target.value)} + placeholder="Enter course title" + /> +
+
+ +