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