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;
}
$ingredients[] = [
$ingredients[$key] = [
'date' => $old['date'][$key],
'meal' => $old['meal'][$key],
'amount' => $amount,
@ -91,6 +91,18 @@ class JournalEntryController extends Controller
'type' => $old['type'][$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,
'servingUnitFormatted' => $resource->serving_unit_formatted,
'servingWeight' => $resource->serving_weight,
'unitsSupported' => $resource->units_supported->pluck('value'),
'createdAt' => $resource->created_at,
'updatedAt' => $resource->updated_at,
'showUrl' => route('foods.show', $resource),

View File

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

View File

@ -73,6 +73,7 @@ use Laravel\Scout\Searchable;
* @mixin \Eloquent
* @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)
* @property-read \Illuminate\Support\Collection $units_supported
*/
final class Food extends Model
{
@ -129,7 +130,8 @@ final class Food extends Model
*/
protected $appends = [
'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 \Illuminate\Database\Eloquent\Collection|\App\Models\RecipeSeparator[] $separators
* @property-read int|null $separators_count
* @property-read Collection $units_supported
*/
final class Recipe extends Model implements HasMedia
{
@ -132,6 +133,7 @@ final class Recipe extends Model implements HasMedia
protected $appends = [
'serving_weight',
'time_total',
'units_supported'
];
/**

View File

@ -3,8 +3,10 @@
namespace App\Models\Traits;
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\Support\Collection;
use Illuminate\Support\Facades\DB;
use Spatie\Tags\Tag;
@ -40,7 +42,7 @@ trait Ingredient
*
* @see \Spatie\Tags\HasTags
*/
public static function getTagTotals(string $locale = null): Collection {
public static function getTagTotals(string $locale = null): DatabaseCollection {
$locale = $locale ?? app()->getLocale();
return Tag::query()->join('taggables', 'taggables.tag_id', '=', 'id')
->select(['id', 'name', DB::raw('count(*) as total')])
@ -49,4 +51,20 @@ trait Ingredient
->orderBy("name->{$locale}")
->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 int|null $goals_count
* @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
{

View File

@ -16,6 +16,7 @@ class Nutrients
* Each entry has two keys:
* - value: Machine name for the unit.
* - label: Human-readable name for the unit.
* - type: Unit type -- matching types can be converted.
*
* @return \Illuminate\Support\Collection
*/
@ -23,27 +24,33 @@ class Nutrients
return new Collection([
'cup' => [
'value' => 'cup',
'label' => 'cup'
'label' => 'cup',
'type' => 'volume',
],
'gram' => [
'value' => 'gram',
'label' => 'gram'
'label' => 'gram',
'type' => 'weight',
],
'oz' => [
'value' => 'oz',
'label' => 'oz'
'label' => 'oz',
'type' => 'weight',
],
'serving' => [
'value' => 'serving',
'label' => 'serving'
'label' => 'serving',
'type' => 'division',
],
'tbsp' => [
'value' => 'tbsp',
'label' => 'tbsp.'
'label' => 'tbsp.',
'type' => 'volume',
],
'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.select name="ingredients[unit][]"
class="block w-full"
:options="$units"
:options="$units ?? []"
:selectedValue="$unit ?? null">
<option value="">-- Unit --</option>
</x-inputs.select>
@ -74,7 +74,20 @@
window.addEventListener('ingredient-picked', (e) => {
const entryItem = e.target.closest('.entry-item');
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.
if (ingredient.type === 'App\\Models\\Recipe') {