File size: 4,481 Bytes
c5ef85d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
98
99
100
101
102
103
104
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); // 'success' | 'error' | 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 {
            // Assuming backend is on port 8000
            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;