Add stealer parser
Signed-off-by: Andrea Pavone <info@andreapavone.com>
This commit is contained in:
162
resources/js/Components/FileUpload.tsx
Normal file
162
resources/js/Components/FileUpload.tsx
Normal file
@ -0,0 +1,162 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { Upload, AlertCircle, FileText, X, Check } from 'lucide-react';
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/Components/ui/card";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Alert, AlertDescription } from "@/Components/ui/alert";
|
||||
|
||||
export default function FileUpload({ onFileUpload, maxSize = 5 }: {
|
||||
onFileUpload: (file: File) => void;
|
||||
maxSize?: number;
|
||||
}) {
|
||||
const [dragActive, setDragActive] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleDrag = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (e.type === "dragenter" || e.type === "dragover") {
|
||||
setDragActive(true);
|
||||
} else if (e.type === "dragleave") {
|
||||
setDragActive(false);
|
||||
}
|
||||
};
|
||||
|
||||
const validateFile = (file: File): boolean => {
|
||||
setError(null);
|
||||
|
||||
// Check file type
|
||||
if (file.type !== 'text/plain' && !file.name.endsWith('.txt')) {
|
||||
setError('Only .txt files are allowed');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
if (file.size > maxSize * 1024 * 1024) {
|
||||
setError(`File size must be less than ${maxSize}MB`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setDragActive(false);
|
||||
|
||||
const file = e.dataTransfer.files?.[0];
|
||||
if (file && validateFile(file)) {
|
||||
setSelectedFile(file);
|
||||
onFileUpload(file);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file && validateFile(file)) {
|
||||
setSelectedFile(file);
|
||||
onFileUpload(file);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
inputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleRemove = () => {
|
||||
setSelectedFile(null);
|
||||
setError(null);
|
||||
if (inputRef.current) {
|
||||
inputRef.current.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Upload Text File</CardTitle>
|
||||
<CardDescription>
|
||||
Drag and drop a .txt file or click to browse
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex flex-col items-center justify-center w-full h-64 p-6 border-2 border-dashed rounded-lg transition-colors",
|
||||
dragActive ? "border-primary bg-primary/5" : "border-muted-foreground/25",
|
||||
selectedFile && "border-success bg-success/5"
|
||||
)}
|
||||
onDragEnter={handleDrag}
|
||||
onDragLeave={handleDrag}
|
||||
onDragOver={handleDrag}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="file"
|
||||
accept=".txt"
|
||||
onChange={handleChange}
|
||||
className="hidden"
|
||||
/>
|
||||
|
||||
{selectedFile ? (
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<div className="flex items-center gap-2 text-success">
|
||||
<Check className="w-8 h-8" />
|
||||
<FileText className="w-8 h-8" />
|
||||
</div>
|
||||
<p className="text-sm font-medium">{selectedFile.name}</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{(selectedFile.size / 1024).toFixed(1)} KB
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mt-2"
|
||||
onClick={handleRemove}
|
||||
>
|
||||
<X className="w-4 h-4 mr-2" />
|
||||
Remove file
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<Upload className="w-8 h-8 text-muted-foreground" />
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleClick}
|
||||
>
|
||||
Choose a file
|
||||
</Button>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
or drag and drop it here
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Only .txt files up to {maxSize}MB are supported
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<Alert variant="destructive" className="mt-4">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user