'use client' import * as React from 'react' import { useState, useEffect, useCallback, useRef } from 'react' import { Header } from '@/components/Header' import { VideoPlayer } from '@/components/VideoPlayer' import { ModuleAccordion } from '@/components/ModuleAccordion' import { LessonBookmarks } from '@/components/LessonBookmarks' import { QuizPlayer } from '@/components/QuizPlayer' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Progress } from '@/components/ui/progress' import { Play, Clock, CheckCircle, BookOpen, ArrowLeft, ChevronLeft, ChevronRight, Volume2, VolumeX, Maximize, Minimize, Settings, Loader2, SkipBack, SkipForward, Film, Music, FileText, Image as ImageIcon, HelpCircle, } from 'lucide-react' import Link from 'next/link' import { formatDuration, formatTime, cn } from '@/lib/utils' import { getCourseDisplayName } from '@/lib/course-display' interface SubtitleTrackType { id?: string src: string lang: string label: string format?: string isDefault: boolean } interface LessonType { id: string title: string slug: string order: number moduleId: string module: { name: string; courseId?: string; id: string } type: string duration: number | null filePath: string thumbnail: string | null subtitlePath: string | null subtitles?: SubtitleTrackType[] progress?: { completed: boolean; position: number; lastWatched: string } | null quiz?: { version: 1 source: 'quizapi' | 'the-trivia-api' topic: string title: string description: string fetchedAt: string updatedAt: string questions: Array<{ id: string prompt: string options: string[] answerIndex: number explanation?: string }> } | null } interface CourseType { id: string slug: string name: string modules: Array<{ id: string name: string slug: string order: number lessons: Array<{ id: string title: string slug: string order: number type: string duration: number | null moduleId: string progress?: { completed: boolean; position: number; lastWatched: Date | string | null } | null }> }> stats: { totalLessons: number completedLessons: number percentage: number } } interface WatchPageClientProps { initialData: { lesson: LessonType course: CourseType prevLesson: { id: string; courseSlug: string } | null nextLesson: { id: string; courseSlug: string } | null currentIndex: number totalLessons: number } } const lessonTypeIcons: Record = { VIDEO: , AUDIO: , PDF: , MARKDOWN: , HTML: , IMAGE: , QUIZ: , OTHER: , } function saveProgressFn(lessonId: string, courseId: string, moduleId: string, position: number) { return fetch('/api/progress', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ lessonId, courseId, moduleId, position, completed: false }) }) } function markCompleteFn(lessonId: string, courseId: string, moduleId: string, position: number) { return fetch('/api/progress', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ lessonId, courseId, moduleId, position, completed: true }) }) } function VideoContent({ lesson, lessonProgress, onSave, onEnd, onTimeUpdate, seekRequest }: { lesson: { id: string; filePath: string; thumbnail: string | null; duration: number | null; subtitlePath: string | null; subtitles?: SubtitleTrackType[] } lessonProgress: { completed: boolean; position: number; lastWatched: string } onSave: (position: number) => void onEnd: () => void onTimeUpdate: (time: number) => void seekRequest: { time: number; nonce: number } | null }) { const subtitleTracks = React.useMemo(() => { if (lesson.subtitles && lesson.subtitles.length > 0) { return lesson.subtitles.map(track => ({ src: '/api/files/' + track.src, srcLang: track.lang, label: track.label, default: track.isDefault, })) } return lesson.subtitlePath ? [{ src: '/api/files/' + lesson.subtitlePath, srcLang: 'en', label: 'English', default: true }] : [] }, [lesson.subtitlePath, lesson.subtitles]) return ( ) } function NonVideoContent({ lesson }: { lesson: { type: string; filePath: string; title: string; duration: number | null } }) { return (
{lesson.type === 'AUDIO' && (