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> | |
) | |
} |