feat(media): enable full page drag and drop for all media types with progress bar
All checks were successful
Deploy Canina / deploy (push) Successful in 59s
All checks were successful
Deploy Canina / deploy (push) Successful in 59s
This commit is contained in:
parent
813c96742d
commit
387519ff6b
@ -46,6 +46,7 @@ export default function MediaSelector({ isOpen, onClose, onSelect, multiple = fa
|
||||
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
||||
const [uploadProgress, setUploadProgress] = useState<number | null>(null);
|
||||
const [filterType, setFilterType] = useState<'all' | 'image' | 'video' | 'audio' | 'pdf'>('all');
|
||||
const [dragOver, setDragOver] = useState(false);
|
||||
|
||||
const fetchMedia = useCallback(async () => {
|
||||
try {
|
||||
@ -187,13 +188,11 @@ export default function MediaSelector({ isOpen, onClose, onSelect, multiple = fa
|
||||
}
|
||||
};
|
||||
|
||||
const [dragOver, setDragOver] = useState(false);
|
||||
|
||||
const handleDrop = async (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
setDragOver(false);
|
||||
if (!e.dataTransfer.files || e.dataTransfer.files.length === 0) return;
|
||||
const files = Array.from(e.dataTransfer.files).filter(f => f.type.startsWith('image/'));
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
if (files.length === 0) return;
|
||||
|
||||
setIsUploading(true);
|
||||
@ -203,7 +202,12 @@ export default function MediaSelector({ isOpen, onClose, onSelect, multiple = fa
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return api.post('/admin/media/upload', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const total = progressEvent.total || file.size;
|
||||
const percent = Math.round((progressEvent.loaded * 100) / total);
|
||||
setUploadProgress(percent);
|
||||
}
|
||||
});
|
||||
});
|
||||
const results = await Promise.allSettled(uploadPromises);
|
||||
@ -212,14 +216,18 @@ export default function MediaSelector({ isOpen, onClose, onSelect, multiple = fa
|
||||
});
|
||||
|
||||
if (successCount > 0) {
|
||||
toast.success(`${successCount} تصویر با موفقیت آپلود شد`);
|
||||
toast.success(`${successCount} فایل با موفقیت بارگذاری شد`);
|
||||
await fetchMedia();
|
||||
}
|
||||
if (successCount < files.length) {
|
||||
toast.error(`خطا در بارگذاری ${files.length - successCount} فایل`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Drop upload failed', error);
|
||||
toast.error('خطا در آپلود تصاویر رها شده');
|
||||
toast.error('خطا در آپلود فایلهای رها شده');
|
||||
} finally {
|
||||
setIsUploading(false);
|
||||
setUploadProgress(null);
|
||||
}
|
||||
};
|
||||
|
||||
@ -243,7 +251,7 @@ export default function MediaSelector({ isOpen, onClose, onSelect, multiple = fa
|
||||
{dragOver && (
|
||||
<div className="absolute inset-0 z-50 bg-purple-600/90 backdrop-blur-xs flex flex-col items-center justify-center text-white pointer-events-none animate-in fade-in">
|
||||
<Upload className="w-16 h-16 mb-2 animate-bounce" />
|
||||
<p className="text-xl font-bold">تصاویر را اینجا رها کنید تا آپلود شوند</p>
|
||||
<p className="text-xl font-bold">فایلها (تصویر، ویدئو، پادکست، PDF) را اینجا رها کنید تا آپلود شوند</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -257,7 +257,26 @@ export default function MediaManager() {
|
||||
const totalSize = mediaList.reduce((sum, m) => sum + m.size, 0);
|
||||
|
||||
return (
|
||||
<div className="space-y-6 font-vazir" dir="rtl">
|
||||
<div
|
||||
className="space-y-6 font-vazir relative min-h-[80vh]"
|
||||
dir="rtl"
|
||||
onDragOver={(e) => { e.preventDefault(); setIsDragOver(true); }}
|
||||
onDragLeave={(e) => {
|
||||
if (!e.currentTarget.contains(e.relatedTarget as Node)) {
|
||||
setIsDragOver(false);
|
||||
}
|
||||
}}
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
{/* Full Page Drag & Drop Overlay */}
|
||||
{isDragOver && (
|
||||
<div className="fixed inset-0 z-50 bg-purple-600/90 backdrop-blur-xs flex flex-col items-center justify-center text-white pointer-events-none animate-in fade-in">
|
||||
<Upload className="w-16 h-16 mb-4 animate-bounce" />
|
||||
<p className="text-2xl font-black mb-2">فایلها را در هر جای صفحه رها کنید تا آپلود شوند</p>
|
||||
<p className="text-sm font-medium opacity-80">پشتیبانی از تصاویر، ویدئوها، پادکستهای صوتی و اسناد PDF</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user