"use client"; import { useState } from "react"; import MediaPlayer from "../MediaPlayer"; import FileUpload from "../FileUpload"; import { getImageUrl } from "@/lib/api"; export interface Marker { timestamp: number; question: string; options: string[]; correctIndex: number; } interface MediaBlockProps { id: string; title?: string; url: string; type: 'video' | 'audio' | 'image'; config: { maxPlays?: number; currentPlays?: number; show_transcript?: boolean; markers?: Marker[]; }; editMode: boolean; onChange: (updates: { title?: string; url?: string; config?: { maxPlays?: number; currentPlays?: number; show_transcript?: boolean; markers?: Marker[]; } }) => void; transcription?: { en?: string; es?: string; cues?: { start: number; end: number; text: string }[]; } | null; isGraded?: boolean; } export default function MediaBlock({ title, url, type, config, editMode, onChange, transcription, isGraded }: MediaBlockProps) { const [localPlays, setLocalPlays] = useState(config.currentPlays || 0); const [sourceType, setSourceType] = useState<"url" | "upload">( (url.startsWith("/assets/") || url.includes("/assets/")) ? "upload" : "url" ); const maxPlays = config.maxPlays || 0; const isLocked = maxPlays > 0 && localPlays >= maxPlays; const handleEnded = () => { if (maxPlays > 0) { const nextPlays = localPlays + 1; setLocalPlays(nextPlays); onChange({ config: { ...config, currentPlays: nextPlays } }); } }; // Full URL for display (handles relative paths from server) const displayUrl = getImageUrl(url); return (
{/* Block Header */}
{editMode ? (
onChange({ title: e.target.value })} placeholder="e.g. Masterclass Stream, Acoustic Analysis..." className="w-full bg-white dark:bg-black/40 border border-slate-200 dark:border-white/10 rounded-2xl px-6 py-3 text-sm font-black uppercase tracking-tight focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 transition-all outline-none shadow-sm" />
) : ( title &&

{title}

)}
{editMode && (
{sourceType === "url" ? (
onChange({ url: e.target.value })} placeholder="YouTube, Vimeo or static link" className="w-full bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-2xl px-6 py-4 text-sm font-bold focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 transition-all outline-none shadow-inner" />
) : (
onChange({ url: newUrl })} />
)}
onChange({ config: { ...config, maxPlays: parseInt(e.target.value) || 0 } })} className="w-full bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-2xl px-6 py-4 text-sm font-bold focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 transition-all outline-none shadow-inner h-14" />

Throttle cognitive load by limiting session repetition.

onChange({ config: { ...config, show_transcript: e.target.checked } })} className="w-6 h-6 rounded-lg border-2 border-slate-200 dark:border-white/10 appearance-none checked:bg-blue-600 checked:border-blue-600 transition-all cursor-pointer shadow-sm" />

Enable for accessibility; disable for auditory tests.

{/* Markers Editor */}
{(config.markers || []).map((marker, idx) => (
{Math.floor(marker.timestamp / 60)}:{String(marker.timestamp % 60).padStart(2, '0')}
{ const newMarkers = [...(config.markers || [])]; newMarkers[idx].question = e.target.value; onChange({ config: { ...config, markers: newMarkers } }); }} placeholder="Question for this timestamp..." className="flex-1 bg-transparent border-b border-slate-200 dark:border-white/10 focus:border-blue-500 outline-none text-sm font-bold text-slate-700 dark:text-white py-2" />
{/* Options Management */}
{marker.options.map((opt, optIdx) => (
{ const newMarkers = [...(config.markers || [])]; newMarkers[idx].correctIndex = optIdx; onChange({ config: { ...config, markers: newMarkers } }); }} className="w-5 h-5 accent-green-500 cursor-pointer" /> { const newMarkers = [...(config.markers || [])]; newMarkers[idx].options[optIdx] = e.target.value; onChange({ config: { ...config, markers: newMarkers } }); }} className={`flex-1 bg-white dark:bg-black/20 border border-slate-200 dark:border-white/10 rounded-xl px-4 py-2 text-sm font-medium focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all outline-none shadow-sm ${marker.correctIndex === optIdx ? 'text-green-600 dark:text-green-400 border-green-500/30' : 'text-slate-700 dark:text-gray-300'}`} />
))}
))}

Questions will pause the video at the specified second. Only simple Yes/No questions supported currently.

)}
{!editMode && maxPlays > 0 && (
Cognitive Reserve Remaining
{Math.max(0, maxPlays - localPlays)} / {maxPlays} Access Vectors
)}
); }