File size: 9,586 Bytes
c075953
4a6c290
c075953
a706099
 
 
 
02158b8
a706099
 
 
 
f444dc0
3ecd1bf
70e74ea
e79fdda
70e74ea
 
 
 
 
 
 
 
 
4a6c290
 
8066d07
 
70e74ea
 
3ecd1bf
 
70e74ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3ecd1bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70e74ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a706099
 
 
 
 
8d0b379
a706099
 
 
 
 
8d0b379
 
 
f444dc0
 
 
 
 
63428e7
 
 
a706099
 
 
 
 
 
9ded9e1
a706099
9f60175
3ecd1bf
70e74ea
9f60175
 
 
 
 
 
 
4a6c290
 
 
 
 
 
 
 
 
 
98d2bd7
a706099
9ded9e1
c075953
 
 
a706099
c075953
e79fdda
 
 
 
 
 
ae3be96
f444dc0
 
 
 
9f60175
f444dc0
9f60175
3ecd1bf
 
d38750a
f444dc0
 
c075953
b1e57e4
63428e7
e79fdda
 
 
 
 
 
a706099
 
 
 
 
e79fdda
 
 
 
 
ae3be96
e79fdda
d38750a
 
f444dc0
 
 
 
 
 
 
 
70e74ea
a706099
70e74ea
 
 
 
 
 
 
3ecd1bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e79fdda
b1e57e4
a706099
c075953
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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;