import { useState, useEffect, useRef } from 'react'; import { Upload, Image as ImageIcon, Trash2, Copy, CheckCircle2, Search, X, FolderOpen } from 'lucide-react'; import api, { BASE_DOMAIN } from '../services/api'; import Spinner from '../components/ui/Spinner'; interface Media { id: string; url: string; filename: string; mimetype: string; size: number; createdAt: string; } export default function MediaManager() { const [mediaList, setMediaList] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isUploading, setIsUploading] = useState(false); const [search, setSearch] = useState(''); const [copiedId, setCopiedId] = useState(null); const [isDragOver, setIsDragOver] = useState(false); const [previewUrl, setPreviewUrl] = useState(null); const fileInputRef = useRef(null); const pasteTimerRef = useRef>(null); useEffect(() => { fetchMedia(); }, []); useEffect(() => { const handlePaste = (e: ClipboardEvent) => { const items = e.clipboardData?.items; if (!items) return; for (const item of Array.from(items)) { if (item.type.startsWith('image/')) { e.preventDefault(); const file = item.getAsFile(); if (!file) continue; uploadFile(file); break; } } }; document.addEventListener('paste', handlePaste); return () => document.removeEventListener('paste', handlePaste); }, []); const fetchMedia = async () => { try { setIsLoading(true); const res = await api.get('/admin/media'); if (res.data?.success) { setMediaList(res.data.data); } } catch (error) { console.error('Error fetching media', error); } finally { setIsLoading(false); } }; const uploadFile = async (file: File) => { const formData = new FormData(); formData.append('file', file); try { setIsUploading(true); await api.post('/admin/media/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); fetchMedia(); } catch (error) { console.error('Upload failed', error); alert('خطا در آپلود فایل'); } finally { setIsUploading(false); } }; const handleUpload = async (e: React.ChangeEvent) => { if (!e.target.files || e.target.files.length === 0) return; await uploadFile(e.target.files[0]); if (fileInputRef.current) fileInputRef.current.value = ''; }; const handleDrop = async (e: React.DragEvent) => { e.preventDefault(); setIsDragOver(false); const file = e.dataTransfer.files[0]; if (file && file.type.startsWith('image/')) { await uploadFile(file); } }; const handleDelete = async (id: string) => { if (!window.confirm('آیا از حذف این تصویر مطمئن هستید؟')) return; try { await api.delete(`/admin/media/${id}`); setMediaList(prev => prev.filter(m => m.id !== id)); } catch (error) { console.error('Delete failed', error); } }; const handleCopyUrl = async (media: Media) => { const fullUrl = media.url.startsWith('http') ? media.url : `${BASE_DOMAIN}${media.url}`; try { await navigator.clipboard.writeText(fullUrl); setCopiedId(media.id); if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current); pasteTimerRef.current = setTimeout(() => setCopiedId(null), 2000); } catch { const textarea = document.createElement('textarea'); textarea.value = fullUrl; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); setCopiedId(media.id); if (pasteTimerRef.current) clearTimeout(pasteTimerRef.current); pasteTimerRef.current = setTimeout(() => setCopiedId(null), 2000); } }; const formatSize = (bytes: number) => { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; }; const filtered = mediaList.filter(m => !search || m.filename.toLowerCase().includes(search.toLowerCase()) ); const totalSize = mediaList.reduce((sum, m) => sum + m.size, 0); return (

مدیریت رسانه

{mediaList.length} فایل · {formatSize(totalSize)} فضا اشغال شده

Ctrl+V برای چسباندن تصویر
setSearch(e.target.value)} className="w-full bg-white border border-gray-200 rounded-xl py-3 pr-11 pl-4 text-sm focus:outline-none focus:ring-2 focus:ring-purple-500/20" />
{ e.preventDefault(); setIsDragOver(true); }} onDragLeave={() => setIsDragOver(false)} onDrop={handleDrop} className={`rounded-2xl border-2 border-dashed transition-colors ${ isDragOver ? 'border-purple-400 bg-purple-50' : 'border-gray-200 bg-white' }`} > {isLoading ? (
) : filtered.length === 0 ? (

{search ? 'فایلی با این نام یافت نشد' : 'گالری خالی است. اولین عکس را آپلود کنید!'}

) : (
{filtered.map(media => { const imgUrl = media.url.startsWith('http') ? media.url : `${BASE_DOMAIN}${media.url}`; return (
setPreviewUrl(imgUrl)} >
{media.filename}

{media.filename}

{formatSize(media.size)}

{new Date(media.createdAt).toLocaleDateString('fa-IR')}

); })}
)}
{previewUrl && (
setPreviewUrl(null)} >
Preview
)}
); }