Filter supported units in ingredient picker

This commit is contained in:
Christopher C. Wells 2021-04-04 14:55:19 -07:00
parent 0ba768d7dc
commit edbcd877c2
9 changed files with 70 additions and 12 deletions

View File

@ -82,7 +82,7 @@ class JournalEntryController extends Controller
) { ) {
continue; continue;
} }
$ingredients[] = [ $ingredients[$key] = [
'date' => $old['date'][$key], 'date' => $old['date'][$key],
'meal' => $old['meal'][$key], 'meal' => $old['meal'][$key],
'amount' => $amount, 'amount' => $amount,
@ -91,6 +91,18 @@ class JournalEntryController extends Controller
'type' => $old['type'][$key], 'type' => $old['type'][$key],
'name' => $old['name'][$key], 'name' => $old['name'][$key],
]; ];
// Add supported units for the ingredient.
$ingredient = NULL;
if ($ingredients[$key]['type'] === Food::class) {
$ingredient = Food::whereId($ingredients[$key]['id'])->first();
}
elseif ($ingredients[$key]['type'] === Recipe::class) {
$ingredient = Recipe::whereId($ingredients[$key]['id'])->first();
}
if ($ingredient) {
$ingredients[$key]['units'] = $ingredient->units_supported;
}
} }
} }

View File

@ -43,6 +43,7 @@ class FoodSchema extends SchemaProvider
'servingUnit' => $resource->serving_unit, 'servingUnit' => $resource->serving_unit,
'servingUnitFormatted' => $resource->serving_unit_formatted, 'servingUnitFormatted' => $resource->serving_unit_formatted,
'servingWeight' => $resource->serving_weight, 'servingWeight' => $resource->serving_weight,
'unitsSupported' => $resource->units_supported->pluck('value'),
'createdAt' => $resource->created_at, 'createdAt' => $resource->created_at,
'updatedAt' => $resource->updated_at, 'updatedAt' => $resource->updated_at,
'showUrl' => route('foods.show', $resource), 'showUrl' => route('foods.show', $resource),

View File

@ -36,6 +36,7 @@ class RecipeSchema extends SchemaProvider
'servings' => $resource->servings, 'servings' => $resource->servings,
'weight' => $resource->weight, 'weight' => $resource->weight,
'serving_weight' => $resource->serving_weight, 'serving_weight' => $resource->serving_weight,
'units_supported' => $resource->units_supported->pluck('label'),
'caloriesPerServing' => $resource->caloriesPerServing(), 'caloriesPerServing' => $resource->caloriesPerServing(),
'carbohydratesPerServing' => $resource->carbohydratesPerServing(), 'carbohydratesPerServing' => $resource->carbohydratesPerServing(),
'cholesterolPerServing' => $resource->cholesterolPerServing(), 'cholesterolPerServing' => $resource->cholesterolPerServing(),

View File

@ -73,6 +73,7 @@ use Laravel\Scout\Searchable;
* @mixin \Eloquent * @mixin \Eloquent
* @method static \Illuminate\Database\Eloquent\Builder|Food withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug) * @method static \Illuminate\Database\Eloquent\Builder|Food withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
* @method static \Database\Factories\FoodFactory factory(...$parameters) * @method static \Database\Factories\FoodFactory factory(...$parameters)
* @property-read \Illuminate\Support\Collection $units_supported
*/ */
final class Food extends Model final class Food extends Model
{ {
@ -129,7 +130,8 @@ final class Food extends Model
*/ */
protected $appends = [ protected $appends = [
'serving_size_formatted', 'serving_size_formatted',
'serving_unit_formatted' 'serving_unit_formatted',
'units_supported',
]; ];
/** /**

View File

@ -77,6 +77,7 @@ use Spatie\MediaLibrary\MediaCollections\Models\Media;
* @property-read Collection $ingredients_list * @property-read Collection $ingredients_list
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\RecipeSeparator[] $separators * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\RecipeSeparator[] $separators
* @property-read int|null $separators_count * @property-read int|null $separators_count
* @property-read Collection $units_supported
*/ */
final class Recipe extends Model implements HasMedia final class Recipe extends Model implements HasMedia
{ {
@ -132,6 +133,7 @@ final class Recipe extends Model implements HasMedia
protected $appends = [ protected $appends = [
'serving_weight', 'serving_weight',
'time_total', 'time_total',
'units_supported'
]; ];
/** /**

View File

@ -3,8 +3,10 @@
namespace App\Models\Traits; namespace App\Models\Traits;
use App\Models\IngredientAmount; use App\Models\IngredientAmount;
use Illuminate\Database\Eloquent\Collection; use App\Support\Nutrients;
use Illuminate\Database\Eloquent\Collection as DatabaseCollection;
use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Spatie\Tags\Tag; use Spatie\Tags\Tag;
@ -40,7 +42,7 @@ trait Ingredient
* *
* @see \Spatie\Tags\HasTags * @see \Spatie\Tags\HasTags
*/ */
public static function getTagTotals(string $locale = null): Collection { public static function getTagTotals(string $locale = null): DatabaseCollection {
$locale = $locale ?? app()->getLocale(); $locale = $locale ?? app()->getLocale();
return Tag::query()->join('taggables', 'taggables.tag_id', '=', 'id') return Tag::query()->join('taggables', 'taggables.tag_id', '=', 'id')
->select(['id', 'name', DB::raw('count(*) as total')]) ->select(['id', 'name', DB::raw('count(*) as total')])
@ -49,4 +51,20 @@ trait Ingredient
->orderBy("name->{$locale}") ->orderBy("name->{$locale}")
->get(); ->get();
} }
/**
* Get a collection of units supported by this ingredient.
*/
public function getUnitsSupportedAttribute(): Collection {
$units = Nutrients::units();
$supported = $units->where('value', 'serving');
if (!empty($this->serving_unit)) {
$type = $units->where('value', $this->serving_unit)->pluck('type')->first();
$supported = $supported->merge($units->where('type', $type));
}
if (!empty($this->serving_weight)) {
$supported = $supported->merge($units->where('type', 'weight'));
}
return $supported->sortBy('label');
}
} }

View File

@ -38,6 +38,8 @@ use Illuminate\Support\Facades\Auth;
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Goal[] $goals * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\Goal[] $goals
* @property-read int|null $goals_count * @property-read int|null $goals_count
* @method static \Database\Factories\UserFactory factory(...$parameters) * @method static \Database\Factories\UserFactory factory(...$parameters)
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\JournalEntry[] $journalEntries
* @property-read int|null $journal_entries_count
*/ */
final class User extends Authenticatable final class User extends Authenticatable
{ {

View File

@ -16,6 +16,7 @@ class Nutrients
* Each entry has two keys: * Each entry has two keys:
* - value: Machine name for the unit. * - value: Machine name for the unit.
* - label: Human-readable name for the unit. * - label: Human-readable name for the unit.
* - type: Unit type -- matching types can be converted.
* *
* @return \Illuminate\Support\Collection * @return \Illuminate\Support\Collection
*/ */
@ -23,27 +24,33 @@ class Nutrients
return new Collection([ return new Collection([
'cup' => [ 'cup' => [
'value' => 'cup', 'value' => 'cup',
'label' => 'cup' 'label' => 'cup',
'type' => 'volume',
], ],
'gram' => [ 'gram' => [
'value' => 'gram', 'value' => 'gram',
'label' => 'gram' 'label' => 'gram',
'type' => 'weight',
], ],
'oz' => [ 'oz' => [
'value' => 'oz', 'value' => 'oz',
'label' => 'oz' 'label' => 'oz',
'type' => 'weight',
], ],
'serving' => [ 'serving' => [
'value' => 'serving', 'value' => 'serving',
'label' => 'serving' 'label' => 'serving',
'type' => 'division',
], ],
'tbsp' => [ 'tbsp' => [
'value' => 'tbsp', 'value' => 'tbsp',
'label' => 'tbsp.' 'label' => 'tbsp.',
'type' => 'volume',
], ],
'tsp' => [ 'tsp' => [
'value' => 'tsp', 'value' => 'tsp',
'label' => 'tsp.' 'label' => 'tsp.',
'type' => 'volume',
], ],
]); ]);
} }

View File

@ -46,7 +46,7 @@
<x-inputs.label for="ingredients[unit][]" value="Unit" class="md:hidden"/> <x-inputs.label for="ingredients[unit][]" value="Unit" class="md:hidden"/>
<x-inputs.select name="ingredients[unit][]" <x-inputs.select name="ingredients[unit][]"
class="block w-full" class="block w-full"
:options="$units" :options="$units ?? []"
:selectedValue="$unit ?? null"> :selectedValue="$unit ?? null">
<option value="">-- Unit --</option> <option value="">-- Unit --</option>
</x-inputs.select> </x-inputs.select>
@ -74,7 +74,20 @@
window.addEventListener('ingredient-picked', (e) => { window.addEventListener('ingredient-picked', (e) => {
const entryItem = e.target.closest('.entry-item'); const entryItem = e.target.closest('.entry-item');
const ingredient = e.detail.ingredient; const ingredient = e.detail.ingredient;
let servingSize, servingUnit; let servingSize, servingUnit
// Restrict unit select list values to supported units.
const unitsSelectList = entryItem.querySelector(':scope select[name="ingredients[unit][]"]');
for (const [key, option] in unitsSelectList.options) {
unitsSelectList.remove(key);
}
for (const key in ingredient.units_supported) {
const unit = ingredient.units_supported[key];
const option = document.createElement('option');
option.value = unit.value;
option.text = unit.label;
unitsSelectList.add(option);
}
// Always set recipes to a default of 1 serving. // Always set recipes to a default of 1 serving.
if (ingredient.type === 'App\\Models\\Recipe') { if (ingredient.type === 'App\\Models\\Recipe') {