cookie-har-analyzer / frontend /src /components /FileUploadPanel.tsx
Hamza4100's picture
Upload 54 files
5aaf491 verified
Raw History Blame Contribute Delete
3.9 kB
import { useCallback, useRef, useState } from 'react';
import { Upload, X, FileText, AlertCircle, CheckCircle2 } from 'lucide-react';
interface FileUploadProps {
label: string;
accept: string;
icon?: React.ReactNode;
file: File | null;
onFile: (file: File | null) => void;
description?: string;
id: string;
}
function formatSize(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
export function FileUploadPanel({ label, accept, icon, file, onFile, description, id }: FileUploadProps) {
const [isDragging, setIsDragging] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
const handleDrop = useCallback(
(e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
const dropped = e.dataTransfer.files[0];
if (dropped) onFile(dropped);
},
[onFile]
);
const handleDragOver = useCallback((e: React.DragEvent) => {
e.preventDefault();
setIsDragging(true);
}, []);
const handleDragLeave = useCallback(() => setIsDragging(false), []);
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const selected = e.target.files?.[0];
if (selected) onFile(selected);
},
[onFile]
);
return (
<div className="flex flex-col gap-2">
<label className="text-xs font-semibold text-gray-400 uppercase tracking-wider">{label}</label>
{file ? (
<div className="card flex items-center gap-3 px-4 py-3 animate-fade-in">
<div className="flex-shrink-0 w-9 h-9 rounded-lg bg-green-500/15 border border-green-500/30 flex items-center justify-center">
<CheckCircle2 className="w-4 h-4 text-green-400" />
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-gray-200 truncate">{file.name}</p>
<p className="text-xs text-gray-500">{formatSize(file.size)}</p>
</div>
<button
id={`${id}-remove`}
onClick={() => {
onFile(null);
if (inputRef.current) inputRef.current.value = '';
}}
className="flex-shrink-0 p-1.5 rounded-lg text-gray-500 hover:text-red-400 hover:bg-red-500/10 transition-all"
title="Remove file"
>
<X className="w-4 h-4" />
</button>
</div>
) : (
<div
className={`drop-zone p-6 text-center ${isDragging ? 'drop-zone-active' : ''}`}
onDrop={handleDrop}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onClick={() => inputRef.current?.click()}
role="button"
tabIndex={0}
id={id}
onKeyDown={(e) => e.key === 'Enter' && inputRef.current?.click()}
>
<div className={`mb-3 flex justify-center transition-transform duration-200 ${isDragging ? 'scale-110' : ''}`}>
<div className="w-12 h-12 rounded-xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center">
{icon || <Upload className="w-5 h-5 text-blue-400" />}
</div>
</div>
<p className="text-sm font-medium text-gray-300 mb-1">
{isDragging ? 'Drop it here' : 'Drop file here'}
</p>
<p className="text-xs text-gray-500 mb-2">
or <span className="text-blue-400 hover:text-blue-300 font-medium">browse</span>
</p>
{description && <p className="text-xs text-gray-600">{description}</p>}
<input
ref={inputRef}
type="file"
accept={accept}
className="sr-only"
onChange={handleChange}
id={`${id}-input`}
/>
</div>
)}
</div>
);
}