const { useState, useEffect, useRef, useMemo } = React; const App = () => { // Data State const [status, setStatus] = useState('upload'); // upload | dashboard const [jsonData, setJsonData] = useState(null); const [videoUrl, setVideoUrl] = useState(null); const [videoInfo, setVideoInfo] = useState({ name: '', duration: 0 }); // Playback State const [currentTime, setCurrentTime] = useState(0); const videoRef = useRef(null); // Annotations State const [markedErrors, setMarkedErrors] = useState(new Set()); // Set of indices const handleFilesLoaded = ({ data, videoUrl, videoFileName }) => { setJsonData(data); setVideoUrl(videoUrl); setVideoInfo(prev => ({ ...prev, name: videoFileName })); setStatus('dashboard'); }; // Helper to parse "HH:MM:SS.mmm" const parseTime = (timeStr) => { if (!timeStr) return 0; const [h, m, s] = timeStr.split(':'); return parseInt(h) * 3600 + parseInt(m) * 60 + parseFloat(s); }; // Find active segment const activeIndex = useMemo(() => { if (!jsonData || !jsonData.transcriptions) return -1; // Find the segment that contains currentTime return jsonData.transcriptions.findIndex(t => { const start = parseTime(t.start); const end = parseTime(t.end); return currentTime >= start && currentTime < end; }); }, [jsonData, currentTime]); const activeSegment = activeIndex !== -1 ? jsonData.transcriptions[activeIndex] : null; const handleSeek = (time) => { setCurrentTime(time); if (videoRef.current) { videoRef.current.currentTime = time; } }; const toggleErrorMark = (index) => { const newSet = new Set(markedErrors); if (newSet.has(index)) { newSet.delete(index); } else { newSet.add(index); } setMarkedErrors(newSet); }; return ( {status === 'upload' && ( )} {status === 'dashboard' && (
{/* Left Column: Video & Timeline (8 cols) */}
setVideoInfo(prev => ({ ...prev, duration: d }))} setVideoRef={(el) => videoRef.current = el} /> {/* Detail Panel moved below Timeline on mobile, or keep here */}
activeIndex !== -1 && toggleErrorMark(activeIndex)} isMarkedWrong={markedErrors.has(activeIndex)} />
{/* Right Column: List (4 cols) */}
{/* Mobile Detail Panel */}
activeIndex !== -1 && toggleErrorMark(activeIndex)} isMarkedWrong={markedErrors.has(activeIndex)} />
)}
); }; window.App = App; // Mount the application const root = ReactDOM.createRoot(document.getElementById('root')); root.render();