import React, { useMemo, useRef, useState } from 'react' function formatBytes(bytes) { const value = Number(bytes || 0) if (!Number.isFinite(value) || value <= 0) return null if (value < 1024 * 1024) return `${Math.round(value / 1024)} KB` return `${(value / (1024 * 1024)).toFixed(1)} MB` } export default function WorldMediaUploadField({ label, slot, value, previewUrl, emptyLabel, helperText, uploadUrl, deleteUrl, worldId = null, onChange, isTemporaryValue = false, accept = 'image/jpeg,image/png,image/webp', maxFileSizeMb = 6, }) { const inputRef = useRef(null) const [dragging, setDragging] = useState(false) const [uploading, setUploading] = useState(false) const [error, setError] = useState('') const [meta, setMeta] = useState(null) const csrfToken = useMemo(() => { if (typeof document === 'undefined') { return '' } return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '' }, []) const deleteTemporaryUpload = async (path) => { if (!deleteUrl || !path) return const response = await fetch(deleteUrl, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken, Accept: 'application/json', }, credentials: 'same-origin', body: JSON.stringify({ path, world_id: worldId || undefined, }), }) const payload = await response.json().catch(() => ({})) if (!response.ok) { throw new Error(payload?.message || payload?.error || 'Could not remove uploaded image.') } } const handleFile = async (file) => { if (!file || uploading) return const allowed = ['image/jpeg', 'image/png', 'image/webp'] if (!allowed.includes(String(file.type || '').toLowerCase())) { setError('Use a JPG, PNG, or WEBP image.') return } if (file.size > maxFileSizeMb * 1024 * 1024) { setError(`Image is too large. Maximum allowed size is ${maxFileSizeMb} MB.`) return } setUploading(true) setError('') try { if (value && isTemporaryValue) { await deleteTemporaryUpload(value) } const body = new FormData() body.append('slot', slot) body.append('image', file) if (worldId) { body.append('world_id', String(worldId)) } const response = await fetch(uploadUrl, { method: 'POST', headers: { 'X-CSRF-TOKEN': csrfToken, Accept: 'application/json', }, credentials: 'same-origin', body, }) const payload = await response.json().catch(() => ({})) if (!response.ok) { throw new Error(payload?.message || payload?.error || 'Upload failed.') } setMeta({ width: payload?.width || null, height: payload?.height || null, size: formatBytes(payload?.size_bytes), }) onChange?.({ path: payload?.path || '', url: payload?.url || '' }) } catch (uploadError) { setError(uploadError?.message || 'Upload failed.') } finally { setUploading(false) if (inputRef.current) { inputRef.current.value = '' } } } return (