SokratesAI / frontend /src /components /DocumentProcessor.jsx
Alleinzellgaenger's picture
Implement comprehensive onboarding flow with white theme
70e74ea
import 'katex/dist/katex.min.css';
import { useState, useEffect } from 'react';
// Import custom hooks
import { useDocumentProcessor } from '../hooks/useDocumentProcessor';
import { useChunkNavigation } from '../hooks/useChunkNavigation';
import { usePanelResize } from '../hooks/usePanelResize';
// Import components
import LoadingAnimation from './LoadingAnimation';
import DocumentViewer from './DocumentViewer';
import ChunkPanel from './ChunkPanel';
import ProgressBar from './ProgressBar';
import WelcomeScreen from './WelcomeScreen';
import OnboardingWizard from './OnboardingWizard';
import Highlights from '../highlights.json';
function DocumentProcessor({ initialFile, fileName, academicBackground }) {
const onboardingData = {
hasFile: !!initialFile,
fileName,
academicBackground
};
// State for PDF navigation
const [pdfNavigation, setPdfNavigation] = useState(null);
// State for first LLM response loading
const [waitingForFirstResponse, setWaitingForFirstResponse] = useState(false);
// State for welcome screen visibility - if coming from onboarding, skip welcome
const [showWelcomeScreen, setShowWelcomeScreen] = useState(!onboardingData?.hasFile);
// State for document controls (like scrollToPage)
const [documentControls, setDocumentControls] = useState(null);
// State for onboarding wizard
const [showOnboarding, setShowOnboarding] = useState(!!onboardingData?.hasFile);
const [onboardingCompleted, setOnboardingCompleted] = useState(false);
// Custom hooks
const {
fileInputRef,
selectedFile,
processing,
uploadProgress,
documentData,
handleFileChange,
processDocument,
setSelectedFile
} = useDocumentProcessor();
// Auto-load document when coming from onboarding
useEffect(() => {
if (onboardingData?.hasFile && initialFile && !selectedFile && !documentData) {
// Use the actual uploaded file
setSelectedFile(initialFile);
setTimeout(() => {
processDocument();
}, 500);
}
}, [onboardingData, selectedFile, documentData, setSelectedFile, processDocument, initialFile]);
// Function to get the page number of the first chunk
const getFirstChunkPage = () => {
if (testPreloadedHighlights && testPreloadedHighlights[0] && testPreloadedHighlights[0].length > 0) {
return testPreloadedHighlights[0][0].position.boundingRect.pageNumber;
}
return 1; // Default to page 1 if no highlights found
};
// Function to handle "Let's start" click
const handleGetStarted = () => {
setShowWelcomeScreen(false);
// Scroll to the first chunk after a short delay to ensure the PDF viewer is ready
if (documentControls && documentControls.scrollToFirstChunk) {
setTimeout(() => {
documentControls.scrollToFirstChunk();
}, 500);
} else {
// Retry after a longer delay
setTimeout(() => {
if (documentControls && documentControls.scrollToFirstChunk) {
documentControls.scrollToFirstChunk();
}
}, 2000);
}
};
// Function to handle onboarding completion
const handleOnboardingComplete = (onboardingPreferences) => {
console.log('Onboarding preferences:', onboardingPreferences);
setShowOnboarding(false);
setOnboardingCompleted(true);
// TODO: Store onboarding preferences for use in tutoring
// Scroll to the first chunk after a short delay
if (documentControls && documentControls.scrollToFirstChunk) {
setTimeout(() => {
documentControls.scrollToFirstChunk();
}, 500);
}
};
const {
chunkStates,
currentChunkIndex,
chunkExpanded,
showChat,
goToNextChunk,
goToPrevChunk,
skipChunk,
markChunkUnderstood,
startInteractiveLesson,
setChunkExpanded,
setShowChat,
setChunkAsInteractive,
updateGlobalChatHistory,
getGlobalChatHistory,
addMessageToChunk,
getCurrentChunkMessages,
hasChunkMessages,
isChunkLoading,
streamResponse
} = useChunkNavigation(documentData);
const {
leftPanelWidth,
isDragging,
containerRef,
handleMouseDown
} = usePanelResize(50);
// Add test preloaded highlights data - keyed by chunk index
// Lennart version
const testPreloadedHighlights = Highlights;
// Temporarily inject test highlights into documentData for testing
const documentDataWithHighlights = documentData ? {
...documentData,
preloadedHighlights: testPreloadedHighlights
} : null;
// Sync PDF page navigation with chunk switching
useEffect(() => {
if (pdfNavigation && documentData && documentData.chunks[currentChunkIndex]) {
const currentChunk = documentData.chunks[currentChunkIndex];
if (currentChunk.page && pdfNavigation.goToPage) {
pdfNavigation.goToPage(currentChunk.page);
}
}
}, [currentChunkIndex, pdfNavigation, documentData]);
// Simplified startInteractiveLesson
const handleStartInteractiveLesson = () => {
startInteractiveLesson();
};
// Main render
return (
<div
ref={containerRef}
className="h-screen bg-gray-100 flex gap-2 p-6 overflow-hidden"
style={{ cursor: isDragging ? 'col-resize' : 'default' }}
>
{/* Left Panel - Document */}
<div style={{ width: `${leftPanelWidth}%`, height: '100%' }} className="flex flex-col">
{/* Document Viewer */}
<div className="flex-1 min-h-0">
<DocumentViewer
selectedFile={selectedFile}
documentData={documentDataWithHighlights}
onPageChange={setPdfNavigation}
preloadedHighlights={documentDataWithHighlights?.preloadedHighlights || null}
currentChunkIndex={currentChunkIndex}
onDocumentReady={setDocumentControls}
isChunkLoading={isChunkLoading}
/>
</div>
</div>
{/* Resizable Divider */}
<div
className="flex items-center justify-center cursor-col-resize group transition-all duration-200"
style={{ width: '8px' }}
onMouseDown={handleMouseDown}
>
<div
className="w-px h-full rounded-full transition-all duration-200 group-hover:shadow-lg"
style={{
backgroundColor: isDragging ? 'rgba(59, 130, 246, 0.8)' : 'transparent',
boxShadow: isDragging ? '0 0 8px rgba(59, 130, 246, 0.8)' : 'none'
}}
></div>
</div>
{/* Right Panel Container */}
<div
className="flex flex-col"
style={{ width: `${100 - leftPanelWidth}%` }}
>
{/* Progress Bar */}
<div className="mb-4 flex-shrink-0">
<ProgressBar
currentChunkIndex={currentChunkIndex}
totalChunks={documentData?.chunks?.length || 0}
onChunkClick={null} // Start with linear progression only
/>
</div>
{/* Right Panel Content - Welcome Screen, Onboarding, or Chunk Panel */}
<div className="flex-1 flex flex-col min-h-0 bg-white rounded-lg shadow-sm">
{showOnboarding ? (
<OnboardingWizard
fileName={onboardingData?.fileName || 'Unknown Paper'}
academicBackground={onboardingData?.academicBackground || ''}
onComplete={handleOnboardingComplete}
/>
) : showWelcomeScreen ? (
<WelcomeScreen onGetStarted={handleGetStarted} />
) : (
<ChunkPanel
documentData={documentDataWithHighlights}
currentChunkIndex={currentChunkIndex}
showChat={showChat}
updateGlobalChatHistory={updateGlobalChatHistory}
getGlobalChatHistory={getGlobalChatHistory}
addMessageToChunk={addMessageToChunk}
getCurrentChunkMessages={getCurrentChunkMessages}
hasChunkMessages={hasChunkMessages}
setWaitingForFirstResponse={setWaitingForFirstResponse}
isChunkLoading={isChunkLoading}
markChunkUnderstood={markChunkUnderstood}
skipChunk={skipChunk}
goToPrevChunk={goToPrevChunk}
streamResponse={streamResponse}
/>
)}
</div>
</div>
</div>
);
}
export default DocumentProcessor;