From 57fa25b73ad9fc3be6cc8529f9bc8925032263d6 Mon Sep 17 00:00:00 2001 From: Kenneth Obsequio Date: Sat, 4 Jul 2026 05:55:27 +0800 Subject: [PATCH] add: more things Signed-off-by: Kenneth Obsequio --- .../admin/components/courses/LessonsTable.jsx | 1 - .../admin/components/courses/UnitsTable.jsx | 1 - .../courses/lessons/rowActions.config.jsx | 10 +- .../courses/units/rowActions.config.jsx | 10 +- src/modules/admin/pages/courses/AddCourse.jsx | 168 ++++++++++++++++-- .../admin/pages/courses/CourseList.jsx | 15 +- 6 files changed, 172 insertions(+), 33 deletions(-) diff --git a/src/modules/admin/components/courses/LessonsTable.jsx b/src/modules/admin/components/courses/LessonsTable.jsx index 3aec87c..49234a1 100644 --- a/src/modules/admin/components/courses/LessonsTable.jsx +++ b/src/modules/admin/components/courses/LessonsTable.jsx @@ -52,7 +52,6 @@ export default function LessonsTable({ courseId, unitId }) { onViewPage: (row) => navigate(`/admin/courses/${courseId}/units/${unitId}/lessons/${row.lesson_id}/page/view`), onCreatePage: (row) => navigate(`/admin/courses/${courseId}/units/${unitId}/lessons/${row.lesson_id}/page`), onView: (row) => navigate(`/admin/courses/${courseId}/units/${unitId}/lessons/${row.lesson_id}/view`), - onEdit: (row) => navigate(`/admin/courses/${courseId}/units/${unitId}/lessons/${row.lesson_id}/edit`), onArchive: (row) => setArchiveTarget(row), }), [courseId, unitId]); diff --git a/src/modules/admin/components/courses/UnitsTable.jsx b/src/modules/admin/components/courses/UnitsTable.jsx index c3e87e4..a3206e2 100644 --- a/src/modules/admin/components/courses/UnitsTable.jsx +++ b/src/modules/admin/components/courses/UnitsTable.jsx @@ -55,7 +55,6 @@ export default function UnitsTable({ courseId }) { onQuiz: (row) => navigate(`/admin/courses/${courseId}/units/${row.unit_id}/quiz/edit`), onViewLessons: (row) => navigate(`/admin/courses/${courseId}/units/${row.unit_id}/lessons`), onView: (row) => navigate(`/admin/courses/${courseId}/units/${row.unit_id}/view`), - onEdit: (row) => navigate(`/admin/courses/${courseId}/units/${row.unit_id}/edit`), onArchive: (row) => setArchiveTarget(row), }), [courseId]); diff --git a/src/modules/admin/config/courses/lessons/rowActions.config.jsx b/src/modules/admin/config/courses/lessons/rowActions.config.jsx index e2952b6..8bbd5bb 100644 --- a/src/modules/admin/config/courses/lessons/rowActions.config.jsx +++ b/src/modules/admin/config/courses/lessons/rowActions.config.jsx @@ -1,6 +1,6 @@ -import { Eye, Pencil, Archive, SquarePlus, SquareChartGantt } from "lucide-react"; +import { Eye, Archive, SquarePlus, SquareChartGantt } from "lucide-react"; -export function buildRowActions({ onCreatePage, onViewPage, onView, onEdit, onArchive }) { +export function buildRowActions({ onCreatePage, onViewPage, onView, onArchive }) { return [ { key: "view", @@ -8,12 +8,6 @@ export function buildRowActions({ onCreatePage, onViewPage, onView, onEdit, onAr icon: , onClick: (row) => onView(row), }, - { - key: "edit", - label: "Edit Lesson", - icon: , - onClick: (row) => onEdit(row), - }, { key: "edit", label: "View Content", diff --git a/src/modules/admin/config/courses/units/rowActions.config.jsx b/src/modules/admin/config/courses/units/rowActions.config.jsx index 52437be..d597c86 100644 --- a/src/modules/admin/config/courses/units/rowActions.config.jsx +++ b/src/modules/admin/config/courses/units/rowActions.config.jsx @@ -1,6 +1,6 @@ -import { Eye, Pencil, Archive, BookCheck, NotebookPen, ClipboardList, PlusCircle } from "lucide-react"; +import { Eye, Archive, BookCheck, NotebookPen, ClipboardList, PlusCircle } from "lucide-react"; -export function buildRowActions({ onViewLessons, onView, onEdit, onArchive, onQuiz, onViewQuiz }) { +export function buildRowActions({ onViewLessons, onView, onArchive, onQuiz, onViewQuiz }) { return [ { key: "view", @@ -8,12 +8,6 @@ export function buildRowActions({ onViewLessons, onView, onEdit, onArchive, onQu icon: , onClick: (row) => onView(row), }, - { - key: "edit", - label: "Edit Info", - icon: , - onClick: (row) => onEdit(row), - }, { key: "view_units", label: "View Lessons", diff --git a/src/modules/admin/pages/courses/AddCourse.jsx b/src/modules/admin/pages/courses/AddCourse.jsx index 5d49ae1..33f7f8d 100644 --- a/src/modules/admin/pages/courses/AddCourse.jsx +++ b/src/modules/admin/pages/courses/AddCourse.jsx @@ -44,13 +44,24 @@ const schema = z.object({ subscription: z.string().min(1, "Subscription is required.").default("free"), objectives: z.array(z.object({ text: z.string().min(1, "Objective cannot be empty.") })).default([]), achievement_keys: z.array(z.string()).max(1).default([]), + + unit_title: z.string().min(1, "Unit title is required."), + unit_description: z.string().optional(), + unit_order: z.coerce.number().min(0).default(0), + + lesson_title: z.string().min(1, "Lesson title is required."), + lesson_description: z.string().optional(), + lesson_order: z.coerce.number().min(0).default(0), + lesson_objectives: z.array(z.object({ text: z.string().min(1, "Objective cannot be empty.") })).default([]), }); // ─── Steps config ───────────────────────────────────────────────────────────── const STEPS = [ - { label: "Basic Info", description: "Title, level & objectives" }, - { label: "Rewards", description: "Badge & achievements" }, + { label: "Basic Info", description: "Title, level & objectives" }, + { label: "First Unit", description: "The course's first unit" }, + { label: "First Lesson", description: "A lesson inside that unit" }, + { label: "Rewards", description: "Badge & achievements" }, ]; // ─── Helpers ────────────────────────────────────────────────────────────────── @@ -128,7 +139,7 @@ function StepIndicator({ steps, current, onStepClick }) { export default function AddCourse() { const navigate = useNavigate(); - const { createCourse, loading } = useCourses(); + const { createCourse, createUnit, createLesson, loading } = useCourses(); const { user } = useAuth(); const [currentStep, setCurrentStep] = useState(0); @@ -163,12 +174,22 @@ export default function AddCourse() { subscription: "free", objectives: [], achievement_keys: [], + unit_title: "", + unit_description: "", + unit_order: 0, + lesson_title: "", + lesson_description: "", + lesson_order: 0, + lesson_objectives: [], }, }); const { fields: objectiveFields, append: appendObjective, remove: removeObjective } = useFieldArray({ control, name: "objectives" }); + const { fields: lessonObjectiveFields, append: appendLessonObjective, remove: removeLessonObjective } = + useFieldArray({ control, name: "lesson_objectives" }); + const currentAchKeys = useWatch({ control, name: "achievement_keys" }); const watchedTitle = useWatch({ control, name: "title" }); const watchedLevel = useWatch({ control, name: "level" }); @@ -189,34 +210,68 @@ export default function AddCourse() { } }; + const STEP_FIELDS = [ + ["title", "subscription", "objectives"], + ["unit_title", "unit_order"], + ["lesson_title", "lesson_order", "lesson_objectives"], + [], + ]; + const handleNext = async (e) => { // The Next button occupies the same DOM position as the eventual // type="submit" Create Course button. Advancing the step re-renders // that node's type attribute in place *before* the browser evaluates // this click's default action, which would otherwise submit the form. e.preventDefault(); - if (currentStep === 0) { - const valid = await trigger(["title", "subscription", "objectives"]); + const fields = STEP_FIELDS[currentStep]; + if (fields?.length) { + const valid = await trigger(fields); if (!valid) return; } setCurrentStep((s) => s + 1); }; const onSubmit = async (values) => { - const payload = { - ...values, - objectives: values.objectives.map((o) => o.text), - level: values.level || null, + const coursePayload = { + title: values.title, + description: values.description, course_code: values.course_code || null, + order_index: values.order_index, + level: values.level || null, + subscription: values.subscription, + objectives: values.objectives.map((o) => o.text), + achievement_keys: values.achievement_keys, badge_color: badgeColor, badge_asset_id: badgeAssetId ?? null, badge_image_url: badgeImageUrl ?? null, createdBy: user?.user_id ?? null, }; - const result = await createCourse(payload); - if (!result) return; - navigate("/admin/courses"); + const courseResult = await createCourse(coursePayload); + const newCourse = courseResult?.data?.data ?? null; + if (!newCourse) return; + + const unitResult = await createUnit(newCourse.course_id, { + title: values.unit_title, + description: values.unit_description, + order: values.unit_order, + createdBy: user?.user_id, + }); + const newUnit = unitResult?.data?.data ?? null; + if (!newUnit) { + navigate(`/admin/courses/${newCourse.course_id}/view`); + return; + } + + await createLesson(newCourse.course_id, newUnit.unit_id, { + title: values.lesson_title, + description: values.lesson_description, + order: values.lesson_order, + objectives: values.lesson_objectives.map((o) => o.text), + createdBy: user?.user_id, + }); + + navigate(`/admin/courses/${newCourse.course_id}/view`); }; return ( @@ -366,8 +421,95 @@ export default function AddCourse() { )} - {/* ── Step 1: Rewards ── */} + {/* ── Step 1: First Unit ── */} {currentStep === 1 && ( + +
+ + + +
+ +
+ +