import React, { useEffect, useMemo, useState } from 'react' import { Head, Link, router, useForm, usePage } from '@inertiajs/react' import AdminLayout from '../../../Layouts/AdminLayout' import NovaSelect from '../../../components/ui/NovaSelect' function laneKey(sectionId) { return sectionId == null ? 'unsectioned' : `section:${sectionId}` } function sortSections(items = []) { return [...items].sort((left, right) => { const orderDiff = Number(left?.order_num || 0) - Number(right?.order_num || 0) if (orderDiff !== 0) return orderDiff return Number(left?.id || 0) - Number(right?.id || 0) }) } function sortLessons(items = []) { return [...items].sort((left, right) => { const leftSection = left?.section_id == null ? -1 : Number(left.section_id) const rightSection = right?.section_id == null ? -1 : Number(right.section_id) if (leftSection !== rightSection) return leftSection - rightSection const orderDiff = Number(left?.order_num || 0) - Number(right?.order_num || 0) if (orderDiff !== 0) return orderDiff return Number(left?.id || 0) - Number(right?.id || 0) }) } function buildLessonLanes(sections = [], lessons = []) { const orderedSections = sortSections(sections) const orderedLessons = sortLessons(lessons) return [ { key: 'unsectioned', sectionId: null, title: 'Core lessons', description: 'Lessons shown before the course branches into sections.', isVisible: true, lessons: orderedLessons.filter((lesson) => lesson.section_id == null), }, ...orderedSections.map((section) => ({ key: laneKey(section.id), sectionId: section.id, title: section.title, description: section.description || 'Section lessons appear together in this stage.', isVisible: Boolean(section.is_visible), lessons: orderedLessons.filter((lesson) => Number(lesson.section_id) === Number(section.id)), })), ] } function reindexLessonsFromLanes(sections = [], lessons = []) { const lanes = buildLessonLanes(sections, lessons) return lanes.flatMap((lane) => lane.lessons.map((lesson, index) => ({ ...lesson, section_id: lane.sectionId, order_num: index, }))) } function moveLessonToPosition(sections = [], lessons = [], lessonId, nextSectionId, targetIndex) { const lanes = buildLessonLanes(sections, lessons).map((lane) => ({ ...lane, lessons: [...lane.lessons] })) let draggedLesson = null lanes.forEach((lane) => { const lessonIndex = lane.lessons.findIndex((lesson) => Number(lesson.id) === Number(lessonId)) if (lessonIndex === -1) return draggedLesson = { ...lane.lessons[lessonIndex], section_id: nextSectionId } lane.lessons.splice(lessonIndex, 1) }) if (!draggedLesson) return lessons const destinationLane = lanes.find((lane) => lane.sectionId === nextSectionId) if (!destinationLane) return lessons const nextIndex = Math.max(0, Math.min(Number(targetIndex), destinationLane.lessons.length)) destinationLane.lessons.splice(nextIndex, 0, draggedLesson) return reindexLessonsFromLanes(sections, lanes.flatMap((lane) => lane.lessons)) } function shiftLesson(sections = [], lessons = [], lessonId, direction) { const lanes = buildLessonLanes(sections, lessons) for (const lane of lanes) { const lessonIndex = lane.lessons.findIndex((lesson) => Number(lesson.id) === Number(lessonId)) if (lessonIndex === -1) continue const nextIndex = lessonIndex + direction if (nextIndex < 0 || nextIndex >= lane.lessons.length) { return lessons } return moveLessonToPosition(sections, lessons, lessonId, lane.sectionId, nextIndex) } return lessons } function placementSignature(lessons = []) { return JSON.stringify(sortLessons(lessons).map((lesson) => ({ id: Number(lesson.id), section_id: lesson.section_id == null ? null : Number(lesson.section_id), order_num: Number(lesson.order_num || 0), }))) } function formatStepLabel(value) { return `Step ${String(value).padStart(2, '0')}` } function resolveDraggedLessonId(event, fallbackLessonId = null) { const nativeLessonId = event?.dataTransfer?.getData('text/plain') || '' if (nativeLessonId !== '') { return Number(nativeLessonId) } return fallbackLessonId == null ? null : Number(fallbackLessonId) } function FormCard({ title, description, children }) { return (

Course builder

{title}

{description ?

{description}

: null}
{children}
) } function CheckboxCardField({ label, checked, onChange, description }) { return ( ) } function EditableSectionCard({ section }) { const form = useForm({ title: section.title || '', slug: section.slug || '', description: section.description || '', order_num: section.order_num || 0, is_visible: Boolean(section.is_visible), }) return (
{ event.preventDefault(); form.patch(section.updateUrl) }} className="rounded-[24px] border border-white/10 bg-black/20 p-4">