import { useState, useEffect, useRef } from 'preact/hooks'; import { useStore } from '@nanostores/preact'; import ModalShell from '../ui/ModalShell'; import { $isOffline } from '../../stores/networkStore.js'; import { uploadWorkOrderPhoto } from '../../stores/fleetDashboardStore.js'; import { showToast } from '../../stores/toastStore.js'; const MAX_FILE_SIZE_MB = 10; const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024; const ACCEPTED_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/heic']; export default function WorkOrderPhotoUpload({ open, workOrderId, onClose, onSuccess, onBack }) { const isOffline = useStore($isOffline); const [images, setImages] = useState([]); const [description, setDescription] = useState(''); const [submitting, setSubmitting] = useState(false); const [progress, setProgress] = useState({ current: 0, total: 0 }); const [error, setError] = useState(''); const [isMounted, setIsMounted] = useState(false); const abortRef = useRef(null); useEffect(() => { setIsMounted(true); return () => { abortRef.current?.abort(); }; }, []); useEffect(() => { if (!open) { abortRef.current?.abort(); abortRef.current = null; setImages([]); setDescription(''); setError(''); setSubmitting(false); setProgress({ current: 0, total: 0 }); } }, [open]); if (!open || !isMounted) return null; const handleFileChange = (e) => { const files = Array.from(e.target.files ?? []); const oversized = files.filter((f) => f.size > MAX_FILE_SIZE_BYTES); const invalidType = files.filter((f) => !ACCEPTED_TYPES.includes(f.type)); if (oversized.length > 0) { setError(`Sljedeće datoteke prelaze ${MAX_FILE_SIZE_MB} MB: ${oversized.map((f) => f.name).join(', ')}`); return; } if (invalidType.length > 0) { setError(`Nepodržan format: ${invalidType.map((f) => f.name).join(', ')}. Koristite JPG, PNG, WEBP ili HEIC.`); return; } setError(''); setImages(files); }; const handleSubmit = async (e) => { e.preventDefault(); setError(''); if (!workOrderId) { setError('Nije poznat putni nalog za koji se upload vrši.'); return; } if (images.length === 0) { setError('Odaberite barem jednu fotografiju.'); return; } if (isOffline) { showToast('Upload fotografija nije dostupan u offline modu.', 'error'); return; } abortRef.current?.abort(); abortRef.current = new AbortController(); const { signal } = abortRef.current; setSubmitting(true); setProgress({ current: 0, total: images.length }); let successCount = 0; try { for (const [index, file] of images.entries()) { if (signal.aborted) break; setProgress({ current: index + 1, total: images.length }); await uploadWorkOrderPhoto(workOrderId, file, description, signal); successCount++; } if (!signal.aborted) { showToast(`${successCount} fotografija putnog naloga je uspješno uploadano.`, 'success'); e.target.reset(); setImages([]); setDescription(''); onSuccess?.(); onClose?.(); } } catch (err) { if (err?.name === 'AbortError') { return; } setError(err?.message || 'Greška pri uploadu fotografija putnog naloga.'); if (successCount > 0) { showToast(`${successCount} od ${images.length} fotografija uploadano.`, 'warning'); } } finally { if (!signal?.aborted) { setSubmitting(false); setProgress({ current: 0, total: 0 }); abortRef.current = null; } } }; const handleCancel = () => { abortRef.current?.abort(); abortRef.current = null; onClose?.(); }; return (
{onBack && ( )}

Upload fotografija putnog naloga

Putni nalog #{workOrderId}

JPG, PNG, WEBP, HEIC — max {MAX_FILE_SIZE_MB} MB po datoteci

{images.length > 0 && (
{images.map((file, i) => (

📎 [{i + 1}] {file.name}{' '} ({(file.size / 1024).toFixed(1)} KB)

))}
)} {submitting && progress.total > 1 && (
Uploading... {progress.current}/{progress.total}
)} {error && (
{error}
)}
); }