diff --git a/frontend/src/features/admin/media/MediaPanel.tsx b/frontend/src/features/admin/media/MediaPanel.tsx index 8aa30bc..02e0ac4 100644 --- a/frontend/src/features/admin/media/MediaPanel.tsx +++ b/frontend/src/features/admin/media/MediaPanel.tsx @@ -32,7 +32,9 @@ export function MediaPanel() { const { t } = useTranslation() const queryClient = useQueryClient() const fileInput = useRef(null) - const [progress, setProgress] = useState(null) + const [upload, setUpload] = useState<{ current: number; total: number; percent: number } | null>( + null, + ) const { data, isLoading } = useQuery({ queryKey: ['admin', 'media'], @@ -50,18 +52,26 @@ export function MediaPanel() { const deleteMutation = useMutation({ mutationFn: deleteMedia, onSuccess: invalidate, onError }) - const handleFile = async (file: File) => { - setProgress(0) - try { - await uploadMedia(file, setProgress) - toast.success(t('admin.media.uploaded')) - invalidate() - } catch (error) { - onError(error) - } finally { - setProgress(null) - if (fileInput.current) fileInput.current.value = '' + // Массовая загрузка: файлы отправляются по одному (обработка всё равно в очереди по одному), + // прогресс — «текущий/всего · %». Список обновляется после каждого файла. + const handleFiles = async (files: FileList) => { + const list = Array.from(files) + let uploaded = 0 + for (let i = 0; i < list.length; i++) { + setUpload({ current: i + 1, total: list.length, percent: 0 }) + try { + await uploadMedia(list[i], (percent) => + setUpload({ current: i + 1, total: list.length, percent }), + ) + uploaded++ + invalidate() + } catch (error) { + onError(error) + } } + setUpload(null) + if (fileInput.current) fileInput.current.value = '' + if (uploaded > 0) toast.success(t('admin.media.uploadedCount', { count: uploaded })) } return ( @@ -69,24 +79,23 @@ export function MediaPanel() {

{t('admin.media.title')}

- {progress != null && ( - {progress}% + {upload != null && ( + + {upload.current}/{upload.total} · {upload.percent}% + )} { - const file = e.target.files?.[0] - if (file) void handleFile(file) + const files = e.target.files + if (files && files.length > 0) void handleFiles(files) }} /> - diff --git a/frontend/src/shared/lib/i18n.ts b/frontend/src/shared/lib/i18n.ts index bc4eb77..38274d3 100644 --- a/frontend/src/shared/lib/i18n.ts +++ b/frontend/src/shared/lib/i18n.ts @@ -105,6 +105,7 @@ const resources = { title: 'Медиа', upload: 'Загрузить', uploaded: 'Файл загружен, идёт обработка', + uploadedCount: 'Загружено файлов: {{count}}', name: 'Файл', status: 'Статус', duration: 'Длительность', @@ -273,6 +274,7 @@ const resources = { title: 'Media', upload: 'Upload', uploaded: 'File uploaded, processing started', + uploadedCount: 'Uploaded files: {{count}}', name: 'File', status: 'Status', duration: 'Duration',