import { useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { useForm, useFieldArray, useWatch } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { ArrowLeft, House, Plus, Trash2 } from "lucide-react"; import { useCourses } from "@/contexts/AdminCoursesContext"; import { useAuth } from "@/contexts/AuthContext"; import { PageMeta } from "@/contexts/MetadataContext"; import AppBreadcrumb from "@/components/generic/Breadcrumb/AppBreadcrumb"; import api from "@/utils/api.util"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Spinner } from "@/components/ui/spinner"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { useUnsavedChangesGuard } from "@/hooks/useUnsavedChangesGuard"; import CompletionRequirementBuilder from "@/modules/admin/components/courses/CompletionRequirementBuilder"; const schema = z.object({ title: z.string().min(1, "Title is required."), description: z.string().optional(), order: z.coerce.number().min(0).default(0), subscription: z.string().optional(), objectives: z.array( z.object({ value: z.string().min(1, "Objective cannot be empty.") }) ).optional(), }); function FieldError({ message }) { if (!message) return null; return

{message}

; } export default function EditLesson() { const navigate = useNavigate(); const { courseId, unitId, lessonId } = useParams(); const { fetchLesson, updateLesson, fetchCourse, fetchUnit, course, unit, loading, fetchLessonRequirements, syncLessonRequirements } = useCourses(); const { user } = useAuth(); const [lessonTitle, setLessonTitle] = useState(""); const [tierCategories, setTierCategories] = useState([]); useEffect(() => { api.get("/admin/tiers/categories") .then(({ data }) => setTierCategories((data.data ?? []).filter((c) => c.is_active))) .catch(() => {}); }, []); const { register, handleSubmit, reset, control, setValue, formState: { errors, isDirty } } = useForm({ resolver: zodResolver(schema), defaultValues: { title: "", description: "", order: 0, subscription: "free", objectives: [] }, }); const watchedSubscr = useWatch({ control, name: "subscription" }); const defaultTierSlug = tierCategories.find((c) => c.is_default)?.slug || "free"; const { fields, append, remove, insert, update } = useFieldArray({ control, name: "objectives" }); const handleObjectivePaste = (e, index) => { const text = e.clipboardData.getData("text"); const lines = text.split(/\r\n|\r|\n/).map((l) => l.trim()).filter(Boolean); if (lines.length <= 1) return; e.preventDefault(); update(index, { value: lines[0] }); lines.slice(1).forEach((line, i) => { insert(index + 1 + i, { value: line }); }); }; const { bypassOnce, dialog: unsavedChangesDialog } = useUnsavedChangesGuard(isDirty); useEffect(() => { (async () => { const res = await fetchLesson(courseId, unitId, lessonId); const lesson = res?.data?.data ?? null; if (!lesson) return; setLessonTitle(lesson.title ?? ""); reset({ title: lesson.title ?? "", description: lesson.description ?? "", order: lesson.order ?? 0, subscription: lesson.subscription || defaultTierSlug, objectives: lesson.objectives?.map((v) => ({ value: v.text })) ?? [], }); })(); fetchUnit(courseId, unitId); if (!course || String(course.course_id) !== String(courseId)) { fetchCourse(courseId); } }, [courseId, unitId, lessonId]); const onSubmit = async (data) => { if (!isDirty) { bypassOnce(); return navigate(`/admin/courses/${courseId}/units/${unitId}/lessons/${lessonId}/view`); } const result = await updateLesson(courseId, unitId, lessonId, { ...data, subscription: data.subscription || defaultTierSlug, objectives: data.objectives?.map((o, i) => ({ objective_id: o.objective_id ?? null, text: o.value, order_index: i, })) ?? [], updatedBy: user?.user_id, }); if (!result) return; bypassOnce(); navigate(`/admin/courses/${courseId}/units/${unitId}/lessons/${lessonId}/view`); }; return (

Edit Lesson

Lessons live in the shared Library — changes here apply everywhere this lesson is used, not just{unit ? ` "${unit.title}"` : " this unit"} {course ? ` (${course.title})` : ""}.