File size: 7,763 Bytes
219cba3
 
 
 
 
625853d
219cba3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e4735a0
9c9e9f8
 
 
 
 
625853d
 
9c9e9f8
 
625853d
9c9e9f8
 
625853d
 
9c9e9f8
625853d
 
 
9c9e9f8
 
 
625853d
 
 
219cba3
9c9e9f8
219cba3
 
 
 
 
 
 
 
 
9c9e9f8
 
625853d
 
 
 
9c9e9f8
 
 
625853d
 
9c9e9f8
 
 
 
 
 
 
 
 
219cba3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 React, { useState, useRef } from 'react';
import { Upload, FileText, File, X, CheckCircle, AlertCircle } from 'lucide-react';
import { useTheme } from '../contexts/ThemeContext';
import '../styles/FileUpload.css'

const FileUpload = ({ onFileUploaded, isUploading, onUploadStart, currentChatSessionId = null, authToken = null  }) => {
  const [dragActive, setDragActive] = useState(false);
  const [uploadStatus, setUploadStatus] = useState(null); // 'success', 'error', null
  const [uploadMessage, setUploadMessage] = useState('');
  const [selectedFile, setSelectedFile] = useState(null);
  const fileInputRef = useRef(null);
  const { isDark } = useTheme();

  const supportedTypes = {
    'application/pdf': { ext: 'PDF', icon: FileText, color: '#EF4444' },
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': { ext: 'DOCX', icon: File, color: '#3B82F6' },
    'text/plain': { ext: 'TXT', icon: FileText, color: '#10B981' }
  };

  const validateFile = (file) => {
    if (!supportedTypes[file.type]) {
      return { valid: false, error: 'Only PDF, DOCX, and TXT files are supported.' };
    }
    
    if (file.size > 10 * 1024 * 1024) { // 10MB limit
      return { valid: false, error: 'File size must be less than 10MB.' };
    }
    
    return { valid: true };
  };

  const uploadFile = async (file) => {
    const validation = validateFile(file);
    if (!validation.valid) {
      setUploadStatus('error');
      setUploadMessage(validation.error);
      return;
    }

    setSelectedFile(file);
    onUploadStart && onUploadStart();
    
    const formData = new FormData();
    formData.append('file', file);

    try {
      let uploadUrl = `${process.env.REACT_APP_API_URL}/upload-document`;
      
      console.log('=== DOCUMENT UPLOAD DEBUG ===');
      console.log('currentChatSessionId:', currentChatSessionId);
      console.log('authToken available:', !!authToken);
      
      if (currentChatSessionId) {
        uploadUrl += `?chat_session_id=${currentChatSessionId}`;
        console.log('Uploading to specific chat session:', currentChatSessionId);
        console.log('Final upload URL:', uploadUrl);
      } else {
        console.log('WARNING: No currentChatSessionId - uploading to new session');
        console.log('This will cause session mismatch!');
      }

      // Include auth token in headers if available
      const headers = {};
      if (authToken) {
        headers['Authorization'] = `Bearer ${authToken}`;
        console.log('Auth token included in request');
      } else {
        console.log('WARNING: No auth token available');
      }

      const response = await fetch(uploadUrl, {
        method: 'POST',
        headers: headers,
        body: formData,
      });

      if (response.ok) {
        const data = await response.json();
        setUploadStatus('success');
        setUploadMessage(`${file.name} uploaded successfully and added to context.`);
        onFileUploaded && onFileUploaded(file, data);
        
        // ENHANCED: Better debug logging
        console.log('=== UPLOAD RESULT ===');
        console.log('Document upload result:', {
          filename: data.filename,
          session_id: data.session_id,
          chat_session_id: data.chat_session_id,
          user_id: data.user_id,
          chunks_created: data.chunks_created,
          currentSessionId: currentChatSessionId
        });
        
        // Check for session mismatch
        if (data.chat_session_id !== currentChatSessionId) {
          console.error('SESSION MISMATCH DETECTED!');
          console.error('Expected:', currentChatSessionId);
          console.error('Got:', data.chat_session_id);
        } else {
          console.log('✅ Session IDs match correctly');
        }
        
        // Auto-clear success message after 5 seconds
        setTimeout(() => {
          setUploadStatus(null);
          setSelectedFile(null);
          setUploadMessage('');
        }, 5000);
      } else {
        const errorData = await response.json();
        throw new Error(errorData.detail || 'Upload failed');
      }
    } catch (error) {
      setUploadStatus('error');
      setUploadMessage(`Upload failed: ${error.message}`);
      console.error('Upload error:', error);
    }
  };

  const handleDrag = (e) => {
    e.preventDefault();
    e.stopPropagation();
    if (e.type === 'dragenter' || e.type === 'dragover') {
      setDragActive(true);
    } else if (e.type === 'dragleave') {
      setDragActive(false);
    }
  };

  const handleDrop = (e) => {
    e.preventDefault();
    e.stopPropagation();
    setDragActive(false);
    
    if (isUploading) return;
    
    const files = Array.from(e.dataTransfer.files);
    if (files.length > 0) {
      uploadFile(files[0]);
    }
  };

  const handleFileSelect = (e) => {
    const files = Array.from(e.target.files);
    if (files.length > 0) {
      uploadFile(files[0]);
    }
  };

  const openFileDialog = () => {
    if (!isUploading) {
      fileInputRef.current?.click();
    }
  };

  const clearStatus = () => {
    setUploadStatus(null);
    setSelectedFile(null);
    setUploadMessage('');
  };

  const getFileIcon = (file) => {
    const fileInfo = supportedTypes[file.type];
    if (fileInfo) {
      const Icon = fileInfo.icon;
      return <Icon size={16} style={{ color: fileInfo.color }} />;
    }
    return <File size={16} />;
  };

  return (
    <div className="file-upload-container">
      {/* Upload Status Banner */}
      {uploadStatus && (
        <div className={`upload-status ${uploadStatus}`}>
          <div className="status-content">
            {uploadStatus === 'success' ? (
              <CheckCircle size={16} className="status-icon success" />
            ) : (
              <AlertCircle size={16} className="status-icon error" />
            )}
            <span className="status-message">{uploadMessage}</span>
            <button onClick={clearStatus} className="status-close">
              <X size={14} />
            </button>
          </div>
        </div>
      )}

      {/* Upload Area */}
      <div 
        className={`file-upload-area ${dragActive ? 'drag-active' : ''} ${isUploading ? 'uploading' : ''}`}
        onDragEnter={handleDrag}
        onDragLeave={handleDrag}
        onDragOver={handleDrag}
        onDrop={handleDrop}
        onClick={openFileDialog}
      >
        <input
          ref={fileInputRef}
          type="file"
          onChange={handleFileSelect}
          accept=".pdf,.docx,.txt"
          style={{ display: 'none' }}
          disabled={isUploading}
        />
        
        <div className="upload-content">
          {isUploading ? (
            <>
              <div className="upload-spinner">
                <div className="spinner"></div>
              </div>
              <p className="upload-text">Uploading {selectedFile?.name}...</p>
            </>
          ) : (
            <>
              <Upload size={24} className="upload-icon" />
              <p className="upload-text">
                <span className="upload-primary">Click to upload</span> or drag and drop
              </p>
              <p className="upload-secondary">PDF, DOCX, or TXT files only</p>
            </>
          )}
        </div>
      </div>
      
      {/* Supported File Types */}
      <div className="supported-types">
        {Object.entries(supportedTypes).map(([mimeType, info]) => {
          const Icon = info.icon;
          return (
            <div key={mimeType} className="file-type-chip">
              <Icon size={12} style={{ color: info.color }} />
              <span>{info.ext}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default FileUpload;