'required|file|max:102400', // 100MB total 'uploadDescription' => 'nullable|string|max:500', 'uploadCategory' => 'required|in:image,document,other', ]; protected $messages = [ 'uploadFiles.*.max' => 'Cada archivo debe pesar menos de 100MB.', ]; public function mount($mediableType, $mediableId) { $this->mediableType = $mediableType; $this->mediableId = $mediableId; $this->entity = $mediableType::findOrFail($mediableId); $this->loadMedia(); } public function loadMedia() { $this->mediaItems = Media::where('mediable_type', $this->mediableType) ->where('mediable_id', $this->mediableId) ->with('uploader') ->latest() ->get(); } public function upload() { $user = Auth::user(); if (!$user->can('upload layers') && !$user->hasRole('Admin')) { session()->flash('error', 'Sin permisos.'); return; } $this->validate(); if (empty($this->uploadFiles)) { session()->flash('error', 'Selecciona al menos un archivo.'); return; } $uploaded = 0; foreach ($this->uploadFiles as $file) { $mime = $file->getMimeType(); $ext = $file->getClientOriginalExtension(); $size = $file->getSize(); $name = $file->getClientOriginalName(); // Determinar categoría automática $category = $this->uploadCategory; if (str_starts_with($mime, 'image/')) { $category = 'image'; } elseif (in_array($mime, ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'])) { $category = 'document'; } // Guardar en disco $entityType = class_basename($this->entity); $dir = "uploads/{$entityType}s/{$this->mediableId}/media"; $path = $file->store($dir, 'public'); Media::create([ 'mediable_type' => $this->mediableType, 'mediable_id' => $this->mediableId, 'name' => $name, 'file_path' => $path, 'file_type' => $mime, 'file_extension' => $ext, 'file_size' => $size, 'category' => $category, 'description' => $this->uploadDescription, 'uploaded_by' => $user->id, ]); $uploaded++; } $this->reset(['uploadFiles', 'uploadDescription']); $this->loadMedia(); // Notificar al mapa si corresponde $this->dispatch('mediaUploaded', [ 'mediableType' => $this->mediableType, 'mediableId' => $this->mediableId, ]); session()->flash('message', "$uploaded archivo(s) subido(s) correctamente."); } public function deleteMedia($mediaId) { $media = Media::findOrFail($mediaId); $user = Auth::user(); if (!$user->hasRole('Admin') && $media->uploaded_by !== $user->id) { session()->flash('error', 'No puedes borrar archivos de otro usuario.'); return; } $media->delete(); $this->loadMedia(); session()->flash('message', 'Archivo eliminado.'); } public function viewMedia($mediaId) { $media = Media::findOrFail($mediaId); if (!$media->is_image) { // Si no es imagen, abrir en nueva pestaña $this->dispatch('openUrl', $media->url); return; } $this->viewingMedia = $media; $this->showViewer = true; } public function closeViewer() { $this->showViewer = false; $this->viewingMedia = null; } public function render() { return view('livewire.media-manager', [ 'entityName' => class_basename($this->entity) . ': ' . ($this->entity->name ?? $this->entity->id), 'images' => $this->mediaItems->filter(fn($m) => $m->is_image), 'documents' => $this->mediaItems->filter(fn($m) => !$m->is_image), ]); } }