import React, { useEffect, useMemo, useState } from 'react' import { Link, usePage } from '@inertiajs/react' import SeoHead from '../../components/seo/SeoHead' function CourseBreadcrumbs({ items = [] }) { if (!items.length) return null return ( ) } function ProgressMeter({ progress }) { const percent = Math.max(0, Math.min(100, Number(progress?.percent || 0))) return (

Progress

{percent}%

{progress ? 'In progress' : 'Not started'}

{progress ? `${progress.completedRequired}/${progress.totalRequired} required lessons completed` : 'Start the course to begin tracking progress through required lessons.'}

) } function LessonChip({ lesson }) { const thumbnail = lesson?.cover_image_url || lesson?.article_cover_image_url || lesson?.cover_image || lesson?.article_cover_image || '' const stepLabel = lesson?.course_step_label || null const stepNumber = Number(lesson?.course_step_number || 0) const isCompleted = Boolean(lesson?.completed) const readingMinutes = Number(lesson?.reading_minutes || 0) const ctaLabel = isCompleted ? 'Review lesson' : 'Open lesson' return (
{thumbnail ? ( ) : (
)}
{lesson.is_required ? ( Required ) : ( Optional )} {isCompleted ? ( Done ) : null}
{stepLabel ?

{stepLabel}

: null} {stepNumber > 0 ?

{String(stepNumber).padStart(2, '0')}

: null}
{stepLabel ?

{stepLabel}

: null} {lesson.formatted_lesson_number ? {lesson.formatted_lesson_number} : null} {lesson.difficulty || 'lesson'} {lesson.access_level || 'free'} {readingMinutes > 0 ? {readingMinutes} min : null}

{lesson.title}

{isCompleted ? 'You already finished this lesson.' : 'Follow this step next in the course path.'}

{lesson.excerpt || lesson.content_preview || 'Open this lesson inside the course.'}

{lesson.lesson_type || 'article'} {lesson.category_name ? {lesson.category_name} : null}

Status

{isCompleted ? 'Completed' : 'Up next'}

Access

{lesson.access_level || 'Free'}

Read time

{readingMinutes > 0 ? `${readingMinutes} min` : 'Quick read'}

Continue path {ctaLabel}
) } function SectionBlock({ section, isActive = false }) { if (!section?.is_visible) return null return (

Course section

{section.order_num + 1}

{section.title}

{section.description ?

{section.description}

: null}
{section.lessons?.length || 0} lessons {isActive ? Reading now : null}
{(section.lessons || []).map((lesson) => ( ))}
) } export default function AcademyCoursesShow({ seo, course, sections = [], unsectionedLessons = [], pricingUrl }) { const flash = usePage().props.flash || {} const cover = course?.cover_image_url || course?.cover_image || course?.teaser_image_url || course?.teaser_image || '' const progress = course?.progress || null const sectionJumpItems = useMemo( () => [ ...(unsectionedLessons.length ? [{ id: 'course-outline-core', label: 'Core lessons', count: unsectionedLessons.length }] : []), ...sections .filter((section) => section?.is_visible) .map((section) => ({ id: `section-${section.id}`, label: section.title, count: (section.lessons || []).length })), ], [sections, unsectionedLessons], ) const [activeJumpId, setActiveJumpId] = useState(sectionJumpItems[0]?.id || null) const breadcrumbs = [ { label: 'Academy', href: '/academy' }, { label: 'Courses', href: '/academy/courses' }, { label: course?.title || 'Course', href: course?.public_url || '#' }, ] useEffect(() => { if (!sectionJumpItems.length || typeof window === 'undefined' || typeof IntersectionObserver === 'undefined') { return undefined } const observer = new IntersectionObserver( (entries) => { const visibleEntries = entries.filter((entry) => entry.isIntersecting).sort((left, right) => right.intersectionRatio - left.intersectionRatio) if (!visibleEntries.length) return setActiveJumpId(visibleEntries[0].target.id) }, { rootMargin: '-20% 0px -55% 0px', threshold: [0.2, 0.45, 0.7], }, ) const elements = sectionJumpItems.map((item) => document.getElementById(item.id)).filter(Boolean) elements.forEach((element) => observer.observe(element)) return () => observer.disconnect() }, [sectionJumpItems]) return (
{flash.success ?
{flash.success}
: null} {flash.error ?
{flash.error}
: null}
{cover ? : null}
Academy course {course?.difficulty} {course?.access_level} {progress?.percent ? {progress.percent}% complete : null}

{course?.title}

{course?.subtitle ?

{course.subtitle}

: null}

{course?.excerpt || course?.description}

{cover ? ( ) : (
No course cover image yet
)}
{unsectionedLessons.length ? ( ) : null} {sections.filter((section) => section?.is_visible).map((section) => ( ))}
) }