diff --git a/app/Filament/User/Resources/ProductResource.php b/app/Filament/User/Resources/ProductResource.php index 61b5cab..a9dceff 100644 --- a/app/Filament/User/Resources/ProductResource.php +++ b/app/Filament/User/Resources/ProductResource.php @@ -19,6 +19,8 @@ use Filament\Tables\Table; use Illuminate\Support\HtmlString; use App\Models\Packing; use App\Models\Recipe; +use App\Models\Spice; +use App\Rules\SumEquals100; use Picqer\Barcode\BarcodeGeneratorSVG; class ProductResource extends Resource { @@ -50,53 +52,52 @@ class ProductResource extends Resource { ->label('Beschreibung') ->content(fn ($record) => $record?->description ?? '—') ->columnSpanFull(), - Forms\Components\Select::make('recipes_id') - ->label('Rezept') - ->native(false) - ->searchable() - ->live() - ->relationship('recipe', 'name') - ->getOptionLabelFromRecordUsing(fn (Recipe $r) => "{$r->name} (v{$r->version})") - ->required() - ->createOptionForm(fn () => [ - Forms\Components\TextInput::make('name') + Forms\Components\Section::make('Rezept') + ->schema([ + TextInput::make('recipe_name') ->label('Name') ->required() - ->default(fn ($livewire) => $livewire->data['title'] ?? ''), - Forms\Components\Textarea::make('description') - ->label('Beschreibung'), + ->dehydrated(false) + ->afterStateHydrated(fn ($component, $record) => + $component->state($record?->recipe?->name ?? '')), + Placeholder::make('recipe_version') + ->label('Version') + ->content(fn ($record) => $record?->recipe + ? 'v' . $record->recipe->version . ' · ' . $record->recipe->created_at->format('d.m.Y') + : '—'), + Repeater::make('recipe_spices') + ->label('Zutaten') + ->schema([ + Select::make('spice_id') + ->label('Rohstoff') + ->options(Spice::all()->pluck('name', 'id')) + ->searchable() + ->required(), + TextInput::make('amount_in_percent') + ->label('Anteil (%)') + ->numeric() + ->minValue(0.01) + ->maxValue(100) + ->required(), + ]) + ->columns(2) + ->addActionLabel('Zutat hinzufügen') + ->dehydrated(false) + ->rules([new SumEquals100()]) + ->afterStateHydrated(function ($component, $record) { + if ($record?->recipe) { + $record->recipe->load('spices'); + $component->state( + $record->recipe->spices->map(fn ($s) => [ + 'spice_id' => $s->id, + 'amount_in_percent' => $s->pivot->amount_in_percent, + ])->toArray() + ); + } + }), ]) - ->createOptionUsing(function (array $data, $livewire) { - $productId = $livewire->record?->id; - $nextVersion = Recipe::where('product_id', $productId)->max('version') + 1; - return Recipe::create([ - 'name' => $data['name'], - 'description' => $data['description'] ?? null, - 'product_id' => $productId, - 'version' => $nextVersion, - ])->getKey(); - }) - ->editOptionForm([ - Forms\Components\TextInput::make('name') - ->label('Name') - ->required(), - Forms\Components\Textarea::make('description') - ->label('Beschreibung'), - ]), - Placeholder::make('recipe_summary') - ->label('Rezept-Inhalt') - ->content(function (Forms\Get $get, $record): HtmlString { - $recipeId = $get('recipes_id'); - $recipe = $recipeId ? Recipe::with('spices')->find($recipeId) : $record?->recipe?->load('spices'); - if (! $recipe || $recipe->spices->isEmpty()) { - return new HtmlString('Keine Zutaten hinterlegt'); - } - $items = $recipe->spices->map(fn ($s) => "
  • {$s->name} ({$s->pivot->amount_in_percent}%)
  • ")->implode(''); - $meta = "v{$recipe->version} · erstellt " . $recipe->created_at->format('d.m.Y'); - return new HtmlString("

    {$meta}

    "); - }) - ->columnSpanFull() - ->visible(fn (Forms\Get $get, $record) => filled($get('recipes_id')) || $record?->recipes_id), + ->columns(2) + ->columnSpanFull(), Repeater::make('sizes') ->schema([ Select::make('packing_id') diff --git a/app/Filament/User/Resources/ProductResource/Pages/CreateProduct.php b/app/Filament/User/Resources/ProductResource/Pages/CreateProduct.php index eb3c93d..48accaa 100644 --- a/app/Filament/User/Resources/ProductResource/Pages/CreateProduct.php +++ b/app/Filament/User/Resources/ProductResource/Pages/CreateProduct.php @@ -3,19 +3,20 @@ namespace App\Filament\User\Resources\ProductResource\Pages; use App\Filament\User\Resources\ProductResource; +use App\Models\ProductSize; +use App\Models\Recipe; use Filament\Resources\Pages\CreateRecord; use Illuminate\Database\Eloquent\Model; -use App\Models\ProductSize; class CreateProduct extends CreateRecord { protected static string $resource = ProductResource::class; - protected function handleRecordCreation(array $data): Model { - + protected function handleRecordCreation(array $data): Model + { $record = static::getModel()::create($data); - foreach ($data['sizes'] as $size) { + foreach ($data['sizes'] ?? [] as $size) { ProductSize::create([ 'product_id' => $record->id, 'packing_id' => $size['packing_id'], @@ -25,6 +26,25 @@ class CreateProduct extends CreateRecord 'gtin' => $size['gtin'] ?? null, ]); } + + $recipeName = $data['recipe_name'] ?? null; + $spices = $data['recipe_spices'] ?? []; + + if ($recipeName) { + $recipe = Recipe::create([ + 'name' => $recipeName, + 'product_id' => $record->id, + 'version' => 1, + ]); + + $pivotData = collect($spices)->mapWithKeys(fn ($s) => [ + $s['spice_id'] => ['amount_in_percent' => $s['amount_in_percent']], + ])->toArray(); + + $recipe->spices()->sync($pivotData); + $record->update(['recipes_id' => $recipe->id]); + } + return $record; } } diff --git a/app/Filament/User/Resources/ProductResource/Pages/EditProduct.php b/app/Filament/User/Resources/ProductResource/Pages/EditProduct.php index 4c35679..6828054 100644 --- a/app/Filament/User/Resources/ProductResource/Pages/EditProduct.php +++ b/app/Filament/User/Resources/ProductResource/Pages/EditProduct.php @@ -3,6 +3,7 @@ namespace App\Filament\User\Resources\ProductResource\Pages; use App\Filament\User\Resources\ProductResource; +use App\Models\Recipe; use Filament\Actions; use Filament\Resources\Pages\EditRecord; @@ -19,6 +20,7 @@ class EditProduct extends EditRecord protected function afterSave(): void { $this->syncSizes(); + $this->syncRecipe(); } protected function syncSizes(): void { @@ -39,4 +41,33 @@ class EditProduct extends EditRecord $product->sizes()->sync($sizes); } + + protected function syncRecipe(): void + { + $product = $this->record; + $name = $this->data['recipe_name'] ?? null; + $spices = $this->data['recipe_spices'] ?? []; + + if (! $name) { + return; + } + + $pivotData = collect($spices)->mapWithKeys(fn ($s) => [ + $s['spice_id'] => ['amount_in_percent' => $s['amount_in_percent']], + ])->toArray(); + + if ($product->recipe) { + $product->recipe->update(['name' => $name]); + $product->recipe->spices()->sync($pivotData); + } else { + $nextVersion = Recipe::where('product_id', $product->id)->max('version') + 1; + $recipe = Recipe::create([ + 'name' => $name, + 'product_id' => $product->id, + 'version' => $nextVersion, + ]); + $recipe->spices()->sync($pivotData); + $product->update(['recipes_id' => $recipe->id]); + } + } }