Refactor ingredients field structure

This commit is contained in:
Christopher C. Wells 2021-01-22 19:18:32 -08:00 committed by Christopher Charbonneau Wells
parent 0c0febed6c
commit 9f180b9b62
5 changed files with 59 additions and 44 deletions

View File

@ -70,8 +70,37 @@ class RecipeController extends Controller
*/
public function edit(Recipe $recipe): View
{
// Pre-populate ingredients from form data or current recipe.
$ingredients = [];
if ($old = old('ingredients')) {
foreach ($old['id'] as $key => $food_id) {
if (empty($food_id)) {
continue;
}
$ingredients[] = [
'amount' => $old['amount'][$key],
'unit' => $old['unit'][$key],
'food_id' => $food_id,
'food_name' => $old['name'][$key],
'detail' => $old['detail'][$key],
];
}
}
else {
foreach ($recipe->foodAmounts as $foodAmount) {
$ingredients[] = [
'amount' => $foodAmount->amount_formatted,
'unit' => $foodAmount->unit,
'food_id' => $foodAmount->food->id,
'food_name' => $foodAmount->food->name,
'detail' => $foodAmount->detail,
];
}
}
return view('recipes.edit')
->with('recipe', $recipe)
->with('ingredients', $ingredients)
->with('ingredients_units', new Collection([
['value' => 'tsp', 'label' => 'tsp.'],
['value' => 'tbsp', 'label' => 'tbsp.'],
@ -98,14 +127,14 @@ class RecipeController extends Controller
'description' => 'nullable|string',
'source' => 'nullable|string',
'servings' => 'required|numeric',
'ingredients_amount' => ['required', 'array', new ArrayNotEmpty],
'ingredients_amount.*' => ['required_with:ingredients.*', 'nullable', new StringIsDecimalOrFraction],
'ingredients_unit' => ['required', 'array'],
'ingredients_unit.*' => 'nullable|string',
'ingredients_detail' => ['required', 'array'],
'ingredients_detail.*' => 'nullable|string',
'ingredients' => ['required', 'array', new ArrayNotEmpty],
'ingredients.*' => 'required_with:ingredients_amount.*|nullable|exists:App\Models\Food,id',
'ingredients.amount' => ['required', 'array', new ArrayNotEmpty],
'ingredients.amount.*' => ['required_with:ingredients.id.*', 'nullable', new StringIsDecimalOrFraction],
'ingredients.unit' => ['required', 'array'],
'ingredients.unit.*' => 'nullable|string',
'ingredients.detail' => ['required', 'array'],
'ingredients.detail.*' => 'nullable|string',
'ingredients.id' => ['required', 'array', new ArrayNotEmpty],
'ingredients.id.*' => 'required_with:ingredients.amount.*|nullable|exists:App\Models\Food,id',
'steps' => ['required', 'array', new ArrayNotEmpty],
'steps.*' => 'nullable|string',
]);
@ -126,15 +155,15 @@ class RecipeController extends Controller
$food_amounts = [];
$weight = 0;
// TODO: Handle removals.
foreach (array_filter($input['ingredients_amount']) as $key => $amount) {
foreach (array_filter($input['ingredients']['id']) as $key => $food_id) {
$food_amounts[$key] = $recipe->foodAmounts[$key] ?? new FoodAmount();
$food_amounts[$key]->fill([
'amount' => Number::floatFromString($amount),
'unit' => $input['ingredients_unit'][$key],
'detail' => $input['ingredients_detail'][$key],
'amount' => Number::floatFromString($input['ingredients']['amount'][$key]),
'unit' => $input['ingredients']['unit'][$key],
'detail' => $input['ingredients']['detail'][$key],
'weight' => $weight++,
]);
$food_amounts[$key]->food()->associate($input['ingredients'][$key]);
$food_amounts[$key]->food()->associate($food_id);
}
$recipe->foodAmounts()->saveMany($food_amounts);

View File

@ -2,11 +2,11 @@
<div>
<div>
<x-inputs.input type="hidden"
name="ingredients[]"
name="ingredients[id][]"
value="{{ $defaultId ?? '' }}"
x-ref="ingredients"/>
<x-inputs.input type="text"
name="ingredients_name[]"
name="ingredients[name][]"
value="{{ $defaultName ?? '' }}"
placeholder="Search..."
autocomplete="off"

View File

@ -64,30 +64,9 @@
<!-- Ingredients -->
<h3 class="pt-2 mb-2 font-extrabold">Ingredients</h3>
<div x-data="{ ingredients: 0 }">
@if(old('ingredients'))
@foreach(old('ingredients') as $i => $ingredient)
@if (empty($ingredient) && empty(old('ingredients_amount')[$i]) && empty(old('ingredients_unit')[$i]))
@continue
@endif
@include('recipes.partials.ingredient-input', [
'amount' => old('ingredients_amount')[$i],
'unit' => old('ingredients_unit')[$i],
'food_id' => old('ingredients')[$i],
'food_name' => old('ingredients_name')[$i],
'detail' => old('ingredients_detail')[$i],
])
@endforeach
@else
@foreach($recipe->foodAmounts as $foodAmount)
@include('recipes.partials.ingredient-input', [
'amount' => $foodAmount->amount_formatted,
'unit' => $foodAmount->unit,
'food_id' => $foodAmount->food->id,
'food_name' => $foodAmount->food->name,
'detail' => $foodAmount->detail,
])
@endforeach
@endif
@foreach($ingredients as $ingredient)
@include('recipes.partials.ingredient-input', $ingredient)
@endforeach
<template x-for="i in ingredients + 1">
@include('recipes.partials.ingredient-input')
</template>
@ -100,7 +79,7 @@
<!-- Steps -->
<h3 class="pt-2 mb-2 font-extrabold">Steps</h3>
<div x-data="{ steps: 0, step_number: 0 }">
<div x-data="{ steps: 0 }">
@if(old('steps'))
@foreach(old('steps') as $i => $step_default)
@if (empty($step)) @continue @endif

View File

@ -1,9 +1,9 @@
<div class="flex flex-row space-x-4 mb-4">
<x-inputs.input type="text"
name="ingredients_amount[]"
name="ingredients[amount][]"
size="5"
:value="$amount ?? null" />
<x-inputs.select name="ingredients_unit[]"
<x-inputs.select name="ingredients[unit][]"
:options="$ingredients_units"
:selectedValue="$unit ?? null">
<option value=""></option>
@ -12,7 +12,7 @@
:default-name="$food_name ?? null" />
<x-inputs.input type="text"
class="block"
name="ingredients_detail[]"
name="ingredients[detail][]"
:value="$detail ?? null" />
<x-inputs.icon-button type="button" color="red" x-on:click="$event.target.parentNode.remove();">
<svg class="h-8 w-8 pointer-events-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">

View File

@ -1,7 +1,14 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
<h2 class="font-semibold text-xl text-gray-800 leading-tight flex flex-auto">
{{ $recipe->name }}
<a class="ml-2 text-gray-500 hover:text-gray-700 hover:border-gray-300 text-sm"
href="{{ route('recipes.edit', $recipe) }}">
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
<path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" />
<path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd" />
</svg>
</a>
</h2>
</x-slot>
<div class="py-12">