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]);
+ }
+ }
}