diff --git a/app/Filament/Resources/Entries/Schemas/EntryForm.php b/app/Filament/Resources/Entries/Schemas/EntryForm.php index 02b5aee..6c029f6 100644 --- a/app/Filament/Resources/Entries/Schemas/EntryForm.php +++ b/app/Filament/Resources/Entries/Schemas/EntryForm.php @@ -40,6 +40,7 @@ class EntryForm ->disk('public') ->visibility('public') ->columnSpanFull() + ->dehydrated(false) ->hintAction( Action::make('featured_picker') ->label('Pick from Gallery') @@ -49,40 +50,36 @@ class EntryForm ->label('Select an existing image') ->allowHtml() ->options(function () { - return Media::latest() - ->limit(30) // Limit to 30 most recent items for performance - ->get(['id', 'file_name', 'name', 'uuid', 'collection_name', 'model_type', 'model_id', 'disk']) - ->filter(function (Media $item) { - // Only include media items that have a valid disk - return $item->disk !== null; - }) + return Media::where('model_type', 'temp') + ->where('model_id', 0) + ->where('disk', 'public') + ->latest() + ->limit(30) + ->get(['id', 'file_name', 'name', 'disk']) ->mapWithKeys(function (Media $item) { try { $url = $item->getUrl(); + $fileName = e($item->file_name); + $name = e($item->name ?? ''); + + $html = "
" . + "{$fileName}" . + "
" . + "{$name}" . + "{$fileName}" . + "
"; + + return [$item->id => $html]; } catch (\Exception $e) { - // Skip items that can't generate URLs return []; } - - $fileName = e($item->file_name); - $name = e($item->name ?? ''); - - // Smaller image preview for better performance - $html = "
" . - "{$fileName}" . - "
" . - "{$name}" . - "{$fileName}" . - "
"; - - return [$item->id => $html]; })->toArray(); }) ->searchable() ->preload() ->required(), ]) - ->action(function (array $data, SpatieMediaLibraryFileUpload $component) { + ->action(function (array $data, SpatieMediaLibraryFileUpload $component): void { $record = $component->getRecord(); if (!$record) { @@ -92,25 +89,56 @@ class EntryForm ->send(); return; } - - if ($mediaItem = Media::find($data['image_id'])) { - // Clear existing featured image - $record->clearMediaCollection('featured-image'); - - // Associate the existing media with this entry instead of copying - $mediaItem->update([ - 'model_type' => get_class($record), - 'model_id' => $record->id, - 'collection_name' => 'featured-image' - ]); - - // Update component state - $component->state([$mediaItem->uuid]); - + + if (!$data['image_id']) { + return; + } + + $sourceMedia = Media::find($data['image_id']); + if (!$sourceMedia || !file_exists($sourceMedia->getPath())) { + \Filament\Notifications\Notification::make() + ->danger() + ->title('Image file not found') + ->send(); + return; + } + + $sourceFile = $sourceMedia->getPath(); + $tempCopy = sys_get_temp_dir() . '/' . uniqid() . '_' . $sourceMedia->file_name; + copy($sourceFile, $tempCopy); + + try { + // Verify record has ID + if (!$record->id) { + \Filament\Notifications\Notification::make() + ->danger() + ->title('Entry must be saved first') + ->send(); + return; + } + + // Add the copy to the entry's featured-image collection + $newMedia = $record->addMedia($tempCopy) + ->usingName($sourceMedia->name ?: pathinfo($sourceMedia->file_name, PATHINFO_FILENAME)) + ->usingFileName($sourceMedia->file_name) + ->toMediaCollection('featured-image', 'public'); + + // Dispatch event for app.js to handle + $component->getLivewire()->dispatch('featured-image-added', ['mediaId' => $newMedia->id]); + \Filament\Notifications\Notification::make() ->success() - ->title('Featured image set') + ->title('Image added to featured image') ->send(); + } catch (\Exception $e) { + \Filament\Notifications\Notification::make() + ->danger() + ->title('Error: ' . $e->getMessage()) + ->send(); + } finally { + if (file_exists($tempCopy)) { + unlink($tempCopy); + } } }) ), diff --git a/app/Livewire/GalleryPicker.php b/app/Livewire/GalleryPicker.php new file mode 100644 index 0000000..c1da485 --- /dev/null +++ b/app/Livewire/GalleryPicker.php @@ -0,0 +1,108 @@ +entryId = $entryId; + $this->loadMediaItems(); + $this->showModal = true; + } + + public function loadMediaItems(): void + { + $this->mediaItems = Media::where('model_type', 'temp') + ->where('model_id', 0) + ->where('disk', 'public') + ->latest() + ->limit(30) + ->get(['id', 'file_name', 'name', 'disk']) + ->toArray(); + } + + public function selectMedia($mediaId): void + { + $this->selectedMediaId = $mediaId; + } + + public function copyToEntry(): void + { + if (!$this->selectedMediaId || !$this->entryId) { + $this->dispatch('notify-error', ['message' => 'Please select an image']); + return; + } + + $sourceMedia = Media::find($this->selectedMediaId); + if (!$sourceMedia) { + $this->dispatch('notify-error', ['message' => 'Media not found']); + return; + } + + try { + // Get the entry + $entry = \App\Models\Entry::find($this->entryId); + if (!$entry) { + $this->dispatch('notify-error', ['message' => 'Entry not found']); + return; + } + + // Get source file + $sourceFile = $sourceMedia->getPath(); + if (!file_exists($sourceFile)) { + $this->dispatch('notify-error', ['message' => 'Source file not found']); + return; + } + + // Create temp copy + $tempCopy = sys_get_temp_dir() . '/' . uniqid() . '_' . $sourceMedia->file_name; + copy($sourceFile, $tempCopy); + + try { + // Clear existing featured image + $entry->clearMediaCollection('featured-image'); + + // Add to entry + $newMedia = $entry->addMedia($tempCopy) + ->usingName($sourceMedia->name ?: pathinfo($sourceMedia->file_name, PATHINFO_FILENAME)) + ->usingFileName($sourceMedia->file_name) + ->toMediaCollection('featured-image', 'public'); + + // Close modal and notify + $this->showModal = false; + $this->selectedMediaId = null; + $this->dispatch('media-selected', ['mediaId' => $newMedia->id, 'fileName' => $newMedia->file_name]); + $this->dispatch('notify-success', ['message' => 'Image added to entry']); + } finally { + if (file_exists($tempCopy)) { + unlink($tempCopy); + } + } + } catch (\Exception $e) { + $this->dispatch('notify-error', ['message' => 'Error: ' . $e->getMessage()]); + } + } + + public function closePicker(): void + { + $this->showModal = false; + $this->selectedMediaId = null; + } + + public function render() + { + return view('livewire.gallery-picker'); + } +} diff --git a/resources/js/app.js b/resources/js/app.js index b52c9ea..22e1c9c 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -33,6 +33,16 @@ document.addEventListener('livewire:init', () => { } } }); + + Livewire.on('featured-image-added', (data) => { + console.log('Received featured-image-added event:', data); + const payload = Array.isArray(data) ? data[0] : data; + + // Reload the page to show the updated featured image + setTimeout(() => { + window.location.reload(); + }, 500); + }); }); console.log('Testing if app.js is still running'); \ No newline at end of file diff --git a/resources/views/components/featured-image-display.blade.php b/resources/views/components/featured-image-display.blade.php new file mode 100644 index 0000000..437552f --- /dev/null +++ b/resources/views/components/featured-image-display.blade.php @@ -0,0 +1,32 @@ +
+ @php + $record = $this->data; + if ($record && isset($record['id'])) { + $entry = \App\Models\Entry::find($record['id']); + $media = $entry ? $entry->getMedia('featured-image') : []; + } else { + $media = []; + } + @endphp + +
+ + @if(count($media) > 0) +
+ @foreach($media as $item) +
+
+ +
+

{{ $item->name }}

+

{{ $item->file_name }}

+
+
+
+ @endforeach +
+ @else +

No featured image selected

+ @endif +
+
diff --git a/resources/views/livewire/gallery-picker.blade.php b/resources/views/livewire/gallery-picker.blade.php new file mode 100644 index 0000000..103b66b --- /dev/null +++ b/resources/views/livewire/gallery-picker.blade.php @@ -0,0 +1,72 @@ +
+ @if($showModal ?? false) +
+
+ +
+ + +
+
+
+

+ Select Image from Gallery +

+ +
+ + @if(empty($mediaItems ?? [])) +

No images in gallery

+ @else +
+ @foreach($mediaItems ?? [] as $item) + + @endforeach +
+ @endif +
+ +
+ + +
+
+
+
+ @endif +