Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | import { useState, useCallback } from 'react'
import { useDropzone } from 'react-dropzone'
import { Upload, File, X, Loader2 } from 'lucide-react'
export default function FileDropzone({ onFileSelect, accept, maxSize = 100 * 1024 * 1024, disabled = false }) {
const [uploading, setUploading] = useState(false)
const [uploadedFile, setUploadedFile] = useState(null)
const onDrop = useCallback(async (acceptedFiles) => {
const file = acceptedFiles[0]
console.log('FileDropzone - File selected:', file?.name, file?.size)
if (file) {
setUploading(true)
try {
await onFileSelect(file)
setUploadedFile(file)
console.log('FileDropzone - File uploaded successfully')
} catch (error) {
console.error('FileDropzone - Error:', error)
} finally {
setUploading(false)
}
}
}, [onFileSelect])
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: accept || {
'application/pdf': ['.pdf'],
'image/*': ['.png', '.jpg', '.jpeg', '.tiff'],
'application/vnd.openxmlformats-officedocument.*': ['.docx', '.xlsx', '.pptx'],
'text/plain': ['.txt'],
},
maxSize,
disabled: disabled || uploading,
multiple: false
})
const handleRemove = () => {
setUploadedFile(null)
}
if (uploadedFile && !uploading) {
return (
<div className="border-2 border-dashed border-green-300 rounded-lg p-6 bg-green-50">
<div className="flex items-center justify-center">
<File className="w-8 h-8 text-green-600 mr-3" />
<div className="text-left flex-1">
<div className="font-medium text-gray-900">{uploadedFile.name}</div>
<div className="text-sm text-gray-500">{(uploadedFile.size / 1024 / 1024).toFixed(2)} MB</div>
</div>
<button
onClick={handleRemove}
className="p-2 text-gray-400 hover:text-red-600 transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
</div>
)
}
return (
<div
{...getRootProps()}
className={`border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors ${
isDragActive
? 'border-purple-500 bg-purple-50'
: 'border-gray-300 hover:border-purple-400 hover:bg-gray-50'
} ${disabled || uploading ? 'opacity-50 cursor-not-allowed' : ''}`}
>
<input {...getInputProps()} />
{uploading ? (
<>
<Loader2 className="w-10 h-10 text-purple-500 mx-auto mb-3 animate-spin" />
<p className="text-purple-600">Traitement en cours...</p>
</>
) : isDragActive ? (
<>
<Upload className="w-10 h-10 text-purple-500 mx-auto mb-3" />
<p className="text-lg text-purple-600">Déposez le fichier ici...</p>
</>
) : (
<>
<Upload className="w-10 h-10 text-gray-400 mx-auto mb-3" />
<p className="text-lg text-gray-600 mb-2">
Glissez-déposez un fichier, ou cliquez pour sélectionner
</p>
<p className="text-sm text-gray-500">
PDF, Images, Office, TXT • Max {(maxSize / 1024 / 1024).toFixed(0)}MB
</p>
</>
)}
</div>
)
}
|