import { useEffect, useRef, useState } from 'react'; import { FileUpload } from 'primereact/fileupload'; import { Button } from 'primereact/button'; import { Tag } from 'primereact/tag'; import { ProgressBar } from 'primereact/progressbar'; import { Toast } from 'primereact/toast'; function formatBytes(value) { const parsed = Number(value); if (!Number.isFinite(parsed) || parsed < 0) { return 'n/a'; } if (parsed === 0) { return '0 B'; } const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; let unitIndex = 0; let current = parsed; while (current >= 1024 && unitIndex < units.length - 1) { current /= 1024; unitIndex += 1; } const digits = unitIndex <= 1 ? 0 : 2; return `${current.toFixed(digits)} ${units[unitIndex]}`; } function normalizeJobId(value) { const parsed = Number(value); if (!Number.isFinite(parsed) || parsed <= 0) { return null; } return Math.trunc(parsed); } export default function AudiobookUploadPanel({ audiobookUpload, onAudiobookUpload, onUploaded = null }) { const toastRef = useRef(null); const fileUploadRef = useRef(null); const [uploadFile, setUploadFile] = useState(null); const [statusVisible, setStatusVisible] = useState(false); const phase = String(audiobookUpload?.phase || 'idle').trim().toLowerCase(); const uploadBusy = phase === 'uploading' || phase === 'processing'; const progress = Number.isFinite(Number(audiobookUpload?.progressPercent)) ? Math.max(0, Math.min(100, Number(audiobookUpload.progressPercent))) : 0; const loadedBytes = Number(audiobookUpload?.loadedBytes || 0); const totalBytes = Number(audiobookUpload?.totalBytes || 0); const fileName = String(audiobookUpload?.fileName || '').trim() || String(uploadFile?.name || '').trim() || null; const statusTone = phase === 'error' ? 'danger' : phase === 'completed' ? 'success' : phase === 'processing' ? 'info' : phase === 'uploading' ? 'warning' : 'secondary'; const statusLabel = phase === 'uploading' ? 'Upload laeuft' : phase === 'processing' ? 'Server verarbeitet' : phase === 'completed' ? 'Bereit' : phase === 'error' ? 'Fehler' : 'Inaktiv'; useEffect(() => { if (phase === 'idle') { setStatusVisible(false); return; } setStatusVisible(true); if (phase === 'completed') { const timer = setTimeout(() => setStatusVisible(false), 5000); return () => clearTimeout(timer); } return undefined; }, [phase]); const handleUpload = async () => { if (!uploadFile) { toastRef.current?.show({ severity: 'warn', summary: 'Keine Datei', detail: 'Bitte zuerst eine AAX-Datei auswaehlen.', life: 2600 }); return; } try { const response = await onAudiobookUpload?.(uploadFile, { startImmediately: false }); const uploadedJobId = normalizeJobId(response?.result?.jobId); if (uploadedJobId) { toastRef.current?.show({ severity: 'success', summary: 'Audiobook importiert', detail: `Job #${uploadedJobId} ist bereit.`, life: 3200 }); } else { toastRef.current?.show({ severity: 'success', summary: 'Audiobook importiert', detail: 'Upload abgeschlossen.', life: 2600 }); } setUploadFile(null); fileUploadRef.current?.clear?.(); onUploaded?.(uploadedJobId, response); } catch (error) { toastRef.current?.show({ severity: 'error', summary: 'Upload fehlgeschlagen', detail: error?.message || 'Bitte Logs pruefen.', life: 4200 }); } }; return (
void handleUpload()} disabled={uploadBusy} onSelect={(event) => setUploadFile(event.files[0] || null)} onClear={() => setUploadFile(null)} onRemove={() => setUploadFile(null)} chooseOptions={{ icon: 'pi pi-images', iconOnly: true, className: 'p-button-rounded p-button-outlined' }} uploadOptions={{ icon: 'pi pi-cloud-upload', iconOnly: true, className: 'p-button-rounded p-button-outlined p-button-success' }} cancelOptions={{ icon: 'pi pi-times', iconOnly: true, className: 'p-button-rounded p-button-outlined p-button-danger' }} itemTemplate={(file, options) => (
{file.name} {options.formatSize}
)} emptyTemplate={() => (

AAX-Datei hier ablegen

oder oben "Auswaehlen" klicken
)} /> {statusVisible ? (
{statusLabel}
{audiobookUpload?.statusText ? {audiobookUpload.statusText} : null} {fileName ? ( Datei: {fileName} ) : null}
{phase === 'processing' ? '100% | Upload fertig, Job wird vorbereitet ...' : totalBytes > 0 ? `${Math.round(progress)}% | ${formatBytes(loadedBytes)} / ${formatBytes(totalBytes)}` : `${Math.round(progress)}%`}
) : null}
); }