import { inject, ref } from 'vue'; /** * Shared image upload composable used by both the left-panel ImageDropZone * and the right-side preview block drop zones. * * @param {() => string | null} getUploadUrl A getter (or plain string) for the upload endpoint. * @param {(url: string) => void} onSuccess Called immediately with a blob URL, then again with the server URL. */ export const useImageUpload = (getUploadUrl, onSuccess) => { const isDragOver = ref(false); const isUploading = ref(false); const error = ref(null); // Plugs into the parent editor's pending-upload counter so the form submit // can be blocked while this upload is in flight. const pendingUploads = inject('editorPendingUploads', null); const uploadFile = async (file) => { if (!file || !file.type.startsWith('image/')) { return; } const uploadUrl = typeof getUploadUrl === 'function' ? getUploadUrl() : getUploadUrl; if (!uploadUrl) { return; } // Emit blob URL immediately so the preview renders at once const blobUrl = URL.createObjectURL(file); onSuccess(blobUrl); isUploading.value = true; error.value = null; if (pendingUploads) pendingUploads.value++; try { const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') ?? ''; const formData = new FormData(); formData.append('image', file); const response = await fetch(uploadUrl, { method: 'POST', headers: { 'X-CSRF-TOKEN': csrfToken }, body: formData, }); if (!response.ok) { throw new Error('Upload failed'); } const data = await response.json(); URL.revokeObjectURL(blobUrl); onSuccess(data.url); } catch { error.value = 'Upload failed. Please try again.'; URL.revokeObjectURL(blobUrl); onSuccess(''); } finally { isUploading.value = false; if (pendingUploads) pendingUploads.value--; } }; const onDragOver = (event) => { event.preventDefault(); isDragOver.value = true; }; const onDragLeave = () => { isDragOver.value = false; }; const onDrop = (event) => { event.preventDefault(); isDragOver.value = false; const file = event.dataTransfer?.files?.[0]; if (file) { uploadFile(file); } }; const fileInputRef = ref(null); const openPicker = () => { if (!fileInputRef.value) return; fileInputRef.value.value = ''; fileInputRef.value.click(); }; const onFileSelected = (event) => { const file = event.target.files[0]; if (file) { uploadFile(file); } }; return { isDragOver, isUploading, error, fileInputRef, onDragOver, onDragLeave, onDrop, openPicker, onFileSelected, uploadFile }; };