Spaces:
Sleeping
Sleeping
| "use client" | |
| import { useState, useRef } from 'react' | |
| import { Box, Typography, Button, CircularProgress, Chip, Stack } from '@mui/material' | |
| import UploadFileIcon from '@mui/icons-material/UploadFile' | |
| import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile' | |
| interface FileUploadProps { | |
| onDocumentsLoaded: (documents: { text: string }[]) => void; | |
| } | |
| export default function FileUpload({ onDocumentsLoaded }: FileUploadProps) { | |
| const [loading, setLoading] = useState(false) | |
| const [error, setError] = useState<string | null>(null) | |
| const [uploadedFiles, setUploadedFiles] = useState<string[]>([]) | |
| const fileInputRef = useRef<HTMLInputElement>(null) | |
| const handleButtonClick = () => { | |
| fileInputRef.current?.click() | |
| } | |
| const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => { | |
| const files = e.target.files | |
| if (!files?.length) return | |
| setLoading(true) | |
| setError(null) | |
| try { | |
| const formData = new FormData() | |
| const fileNames: string[] = [] | |
| Array.from(files).forEach(file => { | |
| formData.append('files', file) | |
| fileNames.push(file.name) | |
| }) | |
| const response = await fetch('/api/upload', { | |
| method: 'POST', | |
| body: formData, | |
| }) | |
| if (!response.ok) { | |
| const errorData = await response.json() | |
| throw new Error(errorData.error || 'Upload failed') | |
| } | |
| const data = await response.json() | |
| setUploadedFiles(prev => [...prev, ...fileNames]) | |
| onDocumentsLoaded(data.documents) | |
| } catch (err) { | |
| console.error('Upload error:', err) | |
| setError(err instanceof Error ? err.message : 'Failed to process files. Please try again.') | |
| } finally { | |
| setLoading(false) | |
| if (fileInputRef.current) { | |
| fileInputRef.current.value = '' | |
| } | |
| } | |
| } | |
| return ( | |
| <Box> | |
| <Typography variant="subtitle1" sx={{ mb: 1, color: 'text.primary' }}> | |
| Upload Documents | |
| </Typography> | |
| <Typography variant="body2" sx={{ mb: 2, color: 'text.secondary' }}> | |
| You can upload multiple PDF and Word documents at once | |
| </Typography> | |
| {uploadedFiles.length > 0 && ( | |
| <Box sx={{ mb: 3 }}> | |
| <Typography variant="body2" sx={{ mb: 1, color: 'text.secondary' }}> | |
| {uploadedFiles.length} {uploadedFiles.length === 1 ? 'file' : 'files'} uploaded | |
| </Typography> | |
| <Stack direction="row" spacing={1} sx={{ flexWrap: 'wrap', gap: 1 }}> | |
| {uploadedFiles.map((fileName, index) => ( | |
| <Chip | |
| key={index} | |
| icon={<InsertDriveFileIcon />} | |
| label={fileName} | |
| variant="outlined" | |
| sx={{ | |
| backgroundColor: 'rgba(37, 99, 235, 0.1)', | |
| borderColor: 'rgba(37, 99, 235, 0.2)', | |
| '& .MuiChip-icon': { | |
| color: 'primary.main', | |
| } | |
| }} | |
| /> | |
| ))} | |
| </Stack> | |
| </Box> | |
| )} | |
| <input | |
| ref={fileInputRef} | |
| type="file" | |
| onChange={handleFileUpload} | |
| accept=".pdf,.doc,.docx" | |
| multiple | |
| style={{ display: 'none' }} | |
| disabled={loading} | |
| /> | |
| <Button | |
| variant="outlined" | |
| fullWidth | |
| onClick={handleButtonClick} | |
| disabled={loading} | |
| startIcon={loading ? <CircularProgress size={20} /> : <UploadFileIcon />} | |
| sx={{ | |
| py: 3, | |
| borderStyle: 'dashed', | |
| borderWidth: 2, | |
| backgroundColor: 'rgba(255, 255, 255, 0.8)', | |
| '&:hover': { | |
| borderColor: 'primary.main', | |
| backgroundColor: 'rgba(37, 99, 235, 0.04)', | |
| } | |
| }} | |
| > | |
| {loading ? 'Processing...' : 'Click to upload PDF or Word documents'} | |
| </Button> | |
| {error && ( | |
| <Typography color="error" sx={{ mt: 2, fontSize: '0.875rem' }}> | |
| {error} | |
| </Typography> | |
| )} | |
| </Box> | |
| ) | |
| } |