| import React, { useCallback, useState } from 'react';
|
| import { useDropzone } from 'react-dropzone';
|
| import axios from 'axios';
|
| import { UploadCloud, File, CheckCircle, AlertCircle, Loader2 } from 'lucide-react';
|
| import { motion, AnimatePresence } from 'framer-motion';
|
|
|
| const DropZone = ({ onUploadSuccess }) => {
|
| const [uploading, setUploading] = useState(false);
|
| const [uploadStatus, setUploadStatus] = useState(null);
|
| const [message, setMessage] = useState('');
|
|
|
| const onDrop = useCallback(async (acceptedFiles) => {
|
| const file = acceptedFiles[0];
|
| if (!file) return;
|
|
|
| setUploading(true);
|
| setUploadStatus(null);
|
| setMessage('');
|
|
|
| const formData = new FormData();
|
| formData.append('file', file);
|
|
|
| try {
|
|
|
| await axios.post('http://localhost:8000/upload', formData, {
|
| headers: {
|
| 'Content-Type': 'multipart/form-data',
|
| },
|
| });
|
| setUploadStatus('success');
|
| setMessage(`Successfully uploaded ${file.name}`);
|
| if (onUploadSuccess) onUploadSuccess();
|
| } catch (error) {
|
| console.error(error);
|
| setUploadStatus('error');
|
| setMessage(error.response?.data?.detail || 'Upload failed');
|
| } finally {
|
| setUploading(false);
|
| }
|
| }, [onUploadSuccess]);
|
|
|
| const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
| onDrop,
|
| accept: {
|
| 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
|
| 'application/vnd.ms-excel': ['.xls']
|
| },
|
| maxFiles: 1,
|
| multiple: false
|
| });
|
|
|
| return (
|
| <div className="w-full max-w-xl mx-auto mb-8">
|
| <div
|
| {...getRootProps()}
|
| className={`relative group cursor-pointer overflow-hidden rounded-2xl border-2 border-dashed transition-all duration-300 ease-in-out
|
| ${isDragActive ? 'border-blue-500 bg-blue-500/10' : 'border-gray-600 hover:border-gray-500 bg-gray-800/50 hover:bg-gray-800'}
|
| ${uploading ? 'pointer-events-none opacity-80' : ''}
|
| `}
|
| >
|
| <input {...getInputProps()} />
|
|
|
| <div className="flex flex-col items-center justify-center p-10 text-center space-y-4">
|
| <div className={`p-4 rounded-full bg-gray-700/50 transition-transform duration-300 ${isDragActive ? 'scale-110' : 'group-hover:scale-110'}`}>
|
| {uploading ? (
|
| <Loader2 className="w-10 h-10 text-blue-400 animate-spin" />
|
| ) : (
|
| <UploadCloud className={`w-10 h-10 ${isDragActive ? 'text-blue-400' : 'text-gray-400'}`} />
|
| )}
|
| </div>
|
|
|
| <div className="space-y-1">
|
| <h3 className="text-lg font-semibold text-gray-200">
|
| {uploading ? 'Uploading...' : isDragActive ? 'Drop your file here' : 'Click or Drag & Drop'}
|
| </h3>
|
| <p className="text-sm text-gray-400">
|
| Support for .xlsx files (Max 1 file)
|
| </p>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| <AnimatePresence mode="wait">
|
| {uploadStatus && (
|
| <motion.div
|
| initial={{ opacity: 0, y: 10 }}
|
| animate={{ opacity: 1, y: 0 }}
|
| exit={{ opacity: 0, y: -10 }}
|
| className={`flex items-center p-4 rounded-lg border ${uploadStatus === 'success'
|
| ? 'bg-green-500/10 border-green-500/20 text-green-200'
|
| : 'bg-red-500/10 border-red-500/20 text-red-200'
|
| }`}
|
| >
|
| {uploadStatus === 'success' ? <CheckCircle className="w-5 h-5 mr-3" /> : <AlertCircle className="w-5 h-5 mr-3" />}
|
| <span className="text-sm font-medium">{message}</span>
|
| </motion.div>
|
| )}
|
| </AnimatePresence>
|
| </div>
|
| );
|
| };
|
|
|
| export default DropZone;
|
|
|