From e289fbc06880ea60773c332dc321ebe1bb399251 Mon Sep 17 00:00:00 2001 From: Vasyka Date: Thu, 6 Aug 2026 05:41:09 +0000 Subject: [PATCH] feat(vehicle): dedicated photo upload with MediaLibrary + form field Vehicle model now implements HasMedia + InteractsWithMedia and registers a 'photos' collection. VehicleResource form gets a SpatieMediaLibraryFileUpload section (collapsible, max 6 photos, imageEditor enabled). Dashboard already checks vehicle->getFirstMediaUrl('photos') first and falls back to the WO's photos, so uploading here immediately populates the vehicle card on the dashboard without any view changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/Filament/Tenant/Resources/VehicleResource.php | 10 ++++++++++ app/Models/Tenant/Vehicle.php | 11 +++++++++-- lang/en.json | 1 + lang/ru.json | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/Filament/Tenant/Resources/VehicleResource.php b/app/Filament/Tenant/Resources/VehicleResource.php index fd72466..e5fb0f8 100644 --- a/app/Filament/Tenant/Resources/VehicleResource.php +++ b/app/Filament/Tenant/Resources/VehicleResource.php @@ -93,6 +93,16 @@ class VehicleResource extends Resource Forms\Components\TextInput::make('mileage')->label(__('Kilometraj'))->numeric()->default(0), Forms\Components\TextInput::make('color')->maxLength(40), ]), + Schemas\Components\Section::make(__('Foto')) + ->collapsible()->collapsed()->compact() + ->schema([ + Forms\Components\SpatieMediaLibraryFileUpload::make('photos') + ->label(__('Fotografii')) + ->collection('photos') + ->multiple()->reorderable()->image()->imageEditor()->maxFiles(6) + ->helperText(__('Prima poză apare pe dashboard-ul fișei ca imagine principală a mașinii.')) + ->columnSpanFull(), + ]), Forms\Components\Textarea::make('notes')->label(__('Notițe'))->columnSpanFull()->rows(3), ]); } diff --git a/app/Models/Tenant/Vehicle.php b/app/Models/Tenant/Vehicle.php index b214719..5569cb8 100644 --- a/app/Models/Tenant/Vehicle.php +++ b/app/Models/Tenant/Vehicle.php @@ -7,10 +7,12 @@ use App\Models\Concerns\Auditable; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; +use Spatie\MediaLibrary\HasMedia; +use Spatie\MediaLibrary\InteractsWithMedia; -class Vehicle extends Model +class Vehicle extends Model implements HasMedia { - use Auditable, BelongsToTenant, SoftDeletes; + use Auditable, BelongsToTenant, InteractsWithMedia, SoftDeletes; public const BODY_TYPES = [ 'sedan' => 'Sedan', 'hatchback' => 'Hatchback', 'suv' => 'SUV', @@ -44,4 +46,9 @@ class Vehicle extends Model { return trim("{$this->make} {$this->model} " . ($this->year ?: '')); } + + public function registerMediaCollections(): void + { + $this->addMediaCollection('photos'); + } } diff --git a/lang/en.json b/lang/en.json index 37d190b..dba2ecc 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1579,6 +1579,7 @@ "Prețuri": "Prices", "Prețurile se înregistrează automat la fiecare recepție de PO.": "Prices are auto-recorded on every PO receipt.", "Price": "Price", + "Prima poză apare pe dashboard-ul fișei ca imagine principală a mașinii.": "The first photo appears on the work-order dashboard as the vehicle's main image.", "Prima vizită": "First visit", "Primește cereri din canalul Telegram + trimite confirmări automate.": "Receive requests from the Telegram channel + send auto-confirmations.", "Primit": "Incoming", diff --git a/lang/ru.json b/lang/ru.json index 0e9fed2..2bbc087 100644 --- a/lang/ru.json +++ b/lang/ru.json @@ -1579,6 +1579,7 @@ "Prețuri": "Цены", "Prețurile se înregistrează automat la fiecare recepție de PO.": "Цены регистрируются автоматически при каждой приёмке PO.", "Price": "Цена", + "Prima poză apare pe dashboard-ul fișei ca imagine principală a mașinii.": "Первое фото отображается на дашборде заказ-наряда как основное изображение автомобиля.", "Prima vizită": "Первый визит", "Primește cereri din canalul Telegram + trimite confirmări automate.": "Получайте заявки из Telegram-канала + отправляйте автоподтверждения.", "Primit": "Входящий",