// ============ Pantalla: Lección (video / quiz / tarea / material) ============ function VideoPlayer({ title, url }) { const [playing, setPlaying] = useState(false); const [t, setT] = useState(0.18); if (url) { return (
); } return (
Grabación no disponible
); } function Comments({ courseId, lessonId }) { const [list, setList] = useState([]); const [val, setVal] = useState(""); useEffect(() => { API.getComments(courseId, lessonId) .then((data) => setList(data)) .catch((err) => console.warn("No se pudieron cargar los comentarios", err)); }, [courseId, lessonId]); const add = () => { if (!val.trim()) return; API.postComment(courseId, lessonId, val.trim()) .then((newComment) => { setList((l) => [...l, newComment]); setVal(""); }) .catch((err) => console.warn("No se pudo guardar el comentario", err)); }; const user = window.DATA && window.DATA.user ? window.DATA.user : { name: "Alumno", role: "" }; const getInitials = (name) => name.split(" ").slice(0, 2).map(n => n[0]).join("").toUpperCase() || "AL"; const userInit = user.avatar || getInitials(user.name); return (
setVal(e.target.value)} onKeyDown={(e) => e.key === "Enter" && add()} /> Enviar
{list.map((c) => (
{c.who}{c.role && {c.role}}{c.time}

{c.txt}

))}
); } function Quiz({ go, courseId, lesson }) { const quiz = (lesson && lesson.questions && lesson.questions.length > 0) ? { title: lesson.title, course: "", questions: lesson.questions } : DATA.quiz; const [i, setI] = useState(0); const [answers, setAnswers] = useState({}); const [picked, setPicked] = useState(null); const [done, setDone] = useState(false); const q = quiz.questions[i]; const last = i === quiz.questions.length - 1; const choose = (idx) => { if (answers[i] !== undefined) return; setPicked(idx); setAnswers((a) => ({ ...a, [i]: idx })); }; const nextQ = () => { if (last) { setDone(true); } else { setI(i + 1); setPicked(null); } }; const score = quiz.questions.reduce((s, qq, idx) => s + (answers[idx] === qq.correct ? 1 : 0), 0); if (done) { const pct = Math.round((score / quiz.questions.length) * 100); const pass = pct >= 60; return (

{pass ? "¡Aprobado! 🎉" : "Casi lo logras"}

Respondiste correctamente {score} de {quiz.questions.length} preguntas.

{ setI(0); setAnswers({}); setPicked(null); setDone(false); }}>Reintentar go("curso", { courseId })}>Volver al curso
); } return (
Pregunta {i + 1} de {quiz.questions.length}

{q.q}

{q.options.map((o, idx) => { const answered = answers[i] !== undefined; let cls = "quiz-opt"; if (answered) { if (idx === q.correct) cls += " correct"; else if (idx === answers[i]) cls += " wrong"; else cls += " dim"; } return ( ); })}
{answers[i] !== undefined ? {last ? "Ver resultado" : "Siguiente"} : Selecciona una respuesta}
); } function LessonView({ courseId, moduleId, lessonId, go }) { const c = DATA.courses.find((x) => x.id === courseId); const m = c.modules.find((x) => x.id === moduleId); const idx = m.lessons.findIndex((x) => x.id === lessonId); const l = m.lessons[idx]; const [tab, setTab] = useState("desc"); const [completed, setCompleted] = useState(l.done); const prev = m.lessons[idx - 1]; const next = m.lessons[idx + 1]; if (l.type === "quiz") { return (
); } if (l.type === "tarea") { return (
); } const tabs = [["desc", "Descripción"], ["materiales", "Materiales"], ["comentarios", "Comentarios"]]; return (
{l.type === "video" ? ( ) : l.file && l.file.url && l.file.url.toLowerCase().endsWith(".pdf") ? (