import { ChevronLeft, ChevronRight, Loader2 } from 'lucide-react'; import { CourseSidebar, type CourseSidebarProps } from './CourseSidebar'; import { useEffect, useMemo, useState } from 'react'; import { useCompleteLessonMutation, useCourseProgress, } from '../../hooks/use-course'; import { NextLessonAlertModal } from './NextLessonAlertModal'; import { useStore } from '@nanostores/react'; import { currentLesson } from '../../stores/course'; import { getPercentage } from '../../helper/number'; import { cn } from '../../lib/classname'; import { CourseNotes } from '../CourseNotes/CourseNotes'; type CourseLayoutProps = { children: React.ReactNode; } & Omit; export function CourseLayout(props: CourseLayoutProps) { const { children, ...sidebarProps } = props; const { chapters, activeCourseId, activeChapterId, activeLessonId, lesson } = sidebarProps; const $currentLesson = useStore(currentLesson); const [showNextWarning, setShowNextWarning] = useState(false); const { data: courseProgress } = useCourseProgress(activeCourseId); const completeLesson = useCompleteLessonMutation(activeCourseId); const completeLessonSet = useMemo( () => new Set( (courseProgress?.completed || []).map( (l) => `/learn/${activeCourseId}/${l.chapterId}/${l.lessonId}`, ), ), [courseProgress], ); const allLessonLinks = useMemo(() => { const lessons: string[] = []; for (const chapter of chapters) { for (const lesson of chapter.lessons) { lessons.push(`/learn/${activeCourseId}/${chapter.id}/${lesson.id}`); } } return lessons; }, [chapters]); const courseProgressPercentage = useMemo(() => { const completedCount = allLessonLinks.filter((lessonLink) => completeLessonSet.has(lessonLink), ).length; return getPercentage(completedCount, allLessonLinks.length); }, [allLessonLinks, completeLessonSet]); const currentLessonUrl = `/learn/${activeCourseId}/${activeChapterId}/${activeLessonId}`; const isCurrentLessonCompleted = completeLessonSet.has(currentLessonUrl); const currentLessonIndex = allLessonLinks.indexOf(currentLessonUrl); const prevLessonLink = allLessonLinks[currentLessonIndex - 1] || ''; const nextLessonLink = allLessonLinks[currentLessonIndex + 1] || ''; const isCurrentLessonLast = currentLessonIndex === allLessonLinks.length - 1; const handleCompleteLesson = () => { if (isCurrentLessonCompleted) { window.location.href = nextLessonLink; return; } if (!activeChapterId || !activeLessonId) { return; } completeLesson.mutate( { chapterId: activeChapterId, lessonId: activeLessonId, }, { onSuccess: () => { if (isCurrentLessonLast) { return; } window.location.href = nextLessonLink; }, }, ); }; useEffect(() => { if ($currentLesson) { return; } currentLesson.set({ courseId: activeCourseId, chapterId: activeChapterId, lessonId: activeLessonId, lessonType: lesson?.frontmatter?.type, challengeStatus: 'pending', quizStatus: 'pending', }); }, [$currentLesson]); return ( <> {showNextWarning && ( { setShowNextWarning(false); handleCompleteLesson(); }} onClose={() => setShowNextWarning(false)} /> )}
{children}
{activeChapterId && activeLessonId && ( )}
); }