mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 22:11:11 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
199
src-old/components/upload/DragDropZone.tsx
Normal file
199
src-old/components/upload/DragDropZone.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Upload, Image, X } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
|
||||
interface DragDropZoneProps {
|
||||
onFilesAdded: (files: File[]) => void;
|
||||
maxFiles?: number;
|
||||
maxSizeMB?: number;
|
||||
allowedFileTypes?: string[];
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function DragDropZone({
|
||||
onFilesAdded,
|
||||
maxFiles = 10,
|
||||
maxSizeMB = 25,
|
||||
allowedFileTypes = ['image/*'],
|
||||
disabled = false,
|
||||
className = '',
|
||||
children,
|
||||
}: DragDropZoneProps) {
|
||||
const [isDragOver, setIsDragOver] = useState(false);
|
||||
const { toast } = useToast();
|
||||
|
||||
const validateFiles = useCallback((files: FileList) => {
|
||||
const validFiles: File[] = [];
|
||||
const errors: string[] = [];
|
||||
|
||||
Array.from(files).forEach((file) => {
|
||||
// Check file type
|
||||
const isValidType = allowedFileTypes.some(type => {
|
||||
if (type === 'image/*') {
|
||||
return file.type.startsWith('image/');
|
||||
}
|
||||
return file.type === type;
|
||||
});
|
||||
|
||||
if (!isValidType) {
|
||||
errors.push(`${file.name}: Invalid file type`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
if (file.size > maxSizeMB * 1024 * 1024) {
|
||||
errors.push(`${file.name}: File too large (max ${maxSizeMB}MB)`);
|
||||
return;
|
||||
}
|
||||
|
||||
validFiles.push(file);
|
||||
});
|
||||
|
||||
// Check total file count
|
||||
if (validFiles.length > maxFiles) {
|
||||
errors.push(`Too many files. Maximum ${maxFiles} files allowed.`);
|
||||
return { validFiles: validFiles.slice(0, maxFiles), errors };
|
||||
}
|
||||
|
||||
return { validFiles, errors };
|
||||
}, [allowedFileTypes, maxSizeMB, maxFiles]);
|
||||
|
||||
const handleDragOver = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!disabled) {
|
||||
setIsDragOver(true);
|
||||
}
|
||||
}, [disabled]);
|
||||
|
||||
const handleDragLeave = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragOver(false);
|
||||
}, []);
|
||||
|
||||
const handleDrop = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsDragOver(false);
|
||||
|
||||
if (disabled) return;
|
||||
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length === 0) return;
|
||||
|
||||
const { validFiles, errors } = validateFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
toast({
|
||||
variant: 'destructive',
|
||||
title: 'File Validation Error',
|
||||
description: errors.join(', '),
|
||||
});
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
onFilesAdded(validFiles);
|
||||
}
|
||||
}, [disabled, validateFiles, onFilesAdded, toast]);
|
||||
|
||||
const handleFileInput = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (disabled) return;
|
||||
|
||||
const files = e.target.files;
|
||||
if (!files || files.length === 0) return;
|
||||
|
||||
const { validFiles, errors } = validateFiles(files);
|
||||
|
||||
if (errors.length > 0) {
|
||||
toast({
|
||||
variant: 'destructive',
|
||||
title: 'File Validation Error',
|
||||
description: errors.join(', '),
|
||||
});
|
||||
}
|
||||
|
||||
if (validFiles.length > 0) {
|
||||
onFilesAdded(validFiles);
|
||||
}
|
||||
|
||||
// Reset input
|
||||
e.target.value = '';
|
||||
}, [disabled, validateFiles, onFilesAdded, toast]);
|
||||
|
||||
if (children) {
|
||||
return (
|
||||
<div
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
className={cn(
|
||||
"relative transition-all duration-200",
|
||||
isDragOver && !disabled && "ring-2 ring-accent ring-offset-2",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
multiple
|
||||
accept={allowedFileTypes.join(',')}
|
||||
onChange={handleFileInput}
|
||||
disabled={disabled}
|
||||
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
className={cn(
|
||||
"relative border-2 border-dashed rounded-lg transition-all duration-200 p-8",
|
||||
isDragOver && !disabled
|
||||
? "border-accent bg-accent/5 scale-[1.02]"
|
||||
: "border-border hover:border-accent/50",
|
||||
disabled && "opacity-50 cursor-not-allowed",
|
||||
!disabled && "cursor-pointer hover:bg-muted/50",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
multiple
|
||||
accept={allowedFileTypes.join(',')}
|
||||
onChange={handleFileInput}
|
||||
disabled={disabled}
|
||||
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
|
||||
/>
|
||||
|
||||
<div className="text-center space-y-4">
|
||||
<div className="mx-auto w-16 h-16 bg-accent/10 rounded-full flex items-center justify-center">
|
||||
{isDragOver ? (
|
||||
<Upload className="w-8 h-8 text-accent animate-bounce" />
|
||||
) : (
|
||||
<Image className="w-8 h-8 text-accent" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-lg font-medium">
|
||||
{isDragOver ? 'Drop files here' : 'Drag & drop photos here'}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
or click to browse files
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Max {maxFiles} files, {maxSizeMB}MB each
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user