mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
switched to ingredients in property editor
This commit is contained in:
@@ -45,31 +45,51 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="[i, food] in foods.entries()">
|
<tr v-for="[i, ingredient] in ingredients.entries()">
|
||||||
<td>{{ food.name }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<v-text-field type="number" v-model="food.fdcId" density="compact" hide-details @change="updateFood(food)" style="min-width: 180px"
|
{{ ingredient.food.name }}
|
||||||
:loading="food.loading">
|
<!-- TODO weird mixture of using ingredients but not in the correct relation to the recipe not good, properly sort out and add easy unitconversion/food edit features -->
|
||||||
|
<!-- <v-btn variant="outlined" block>-->
|
||||||
|
<!-- {{ ingredient.food.name }}-->
|
||||||
|
<!-- <model-edit-dialog model="Food" :item="ingredient.food!" @save="args => ingredient.food = args"></model-edit-dialog>-->
|
||||||
|
<!-- </v-btn>-->
|
||||||
|
<!-- <v-chip v-if="ingredient.unit && ingredient.food.propertiesFoodUnit && ingredient.unit.id == ingredient.food.propertiesFoodUnit.id" color="success"-->
|
||||||
|
<!-- size="small">{{ ingredient.unit.name }}-->
|
||||||
|
<!-- </v-chip>-->
|
||||||
|
<!-- <v-chip v-if="ingredient.unit && ingredient.food.propertiesFoodUnit && ingredient.unit.id != ingredient.food.propertiesFoodUnit.id" color="error"-->
|
||||||
|
<!-- size="small" class="cursor-pointer" prepend-icon="$create">-->
|
||||||
|
<!-- {{ $t('Conversion') }}: {{ ingredient.unit.name }} <i class="fa-solid fa-arrow-right me-1 ms-1"></i>-->
|
||||||
|
<!-- {{ ingredient.food.propertiesFoodUnit.name }}-->
|
||||||
|
<!-- <model-edit-dialog model="UnitConversion"-->
|
||||||
|
<!-- :item-defaults="{baseAmount: 1, baseUnit: ingredient.unit, convertedUnit: ingredient.food.propertiesFoodUnit, food: ingredient.food}"></model-edit-dialog>-->
|
||||||
|
<!-- </v-chip>-->
|
||||||
|
<!-- <v-chip v-if="ingredient.unit && !ingredient.food.propertiesFoodUnit" size="small">{{ ingredient.unit.name }}</v-chip>-->
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<v-text-field type="number" v-model="ingredient.food.fdcId" density="compact" hide-details @change="updateFood(ingredient)" style="min-width: 180px"
|
||||||
|
:loading="ingredient.loading">
|
||||||
<template #append-inner>
|
<template #append-inner>
|
||||||
<v-btn icon="$search" size="small" density="compact" variant="plain" v-if="food.fdcId == undefined" @click="fdcSelectedFood = food; fdcDialog = true"></v-btn>
|
<v-btn icon="$search" size="small" density="compact" variant="plain" v-if="ingredient.food.fdcId == undefined"
|
||||||
<v-btn @click="updateFoodFdcData(food)" icon="fa-solid fa-arrows-rotate" size="small" density="compact" variant="plain"
|
@click="fdcSelectedIngredient = ingredient; fdcDialog = true"></v-btn>
|
||||||
v-if="food.fdcId"></v-btn>
|
<v-btn @click="updateFoodFdcData(ingredient)" icon="fa-solid fa-arrows-rotate" size="small" density="compact" variant="plain"
|
||||||
<v-btn :href="`https://fdc.nal.usda.gov/food-details/${food.fdcId}/nutrients`" target="_blank" icon="fa-solid fa-arrow-up-right-from-square"
|
v-if="ingredient.food.fdcId"></v-btn>
|
||||||
size="small" variant="plain" v-if="food.fdcId"></v-btn>
|
<v-btn :href="`https://fdc.nal.usda.gov/food-details/${ingredient.food.fdcId}/nutrients`" target="_blank"
|
||||||
|
icon="fa-solid fa-arrow-up-right-from-square"
|
||||||
|
size="small" variant="plain" v-if="ingredient.food.fdcId"></v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<v-text-field type="number" v-model="food.propertiesFoodAmount" density="compact" hide-details @change="updateFood(food)"
|
<v-text-field type="number" v-model="ingredient.food.propertiesFoodAmount" density="compact" hide-details @change="updateFood(ingredient)"
|
||||||
:loading="food.loading"></v-text-field>
|
:loading="ingredient.loading"></v-text-field>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<model-select model="Unit" density="compact" v-model="food.propertiesFoodUnit" hide-details @update:model-value="updateFood(food)"
|
<model-select model="Unit" density="compact" v-model="ingredient.food.propertiesFoodUnit" hide-details @update:model-value="updateFood(ingredient)"
|
||||||
:loading="food.loading"></model-select>
|
:loading="ingredient.loading"></model-select>
|
||||||
</td>
|
</td>
|
||||||
<td v-for="p in food.properties" v-bind:key="`${food.id}_${p.propertyType.id}`">
|
<td v-for="p in ingredient.food.properties" v-bind:key="`${ingredient.food.id}_${p.propertyType.id}`">
|
||||||
<v-text-field type="number" v-model="p.propertyAmount" density="compact" hide-details v-if="p.propertyAmount != null" @change="updateFood(food)"
|
<v-text-field type="number" v-model="p.propertyAmount" density="compact" hide-details v-if="p.propertyAmount != null" @change="updateFood(ingredient)"
|
||||||
:loading="food.loading" @click:clear="deleteFoodProperty(p, food)" clearable></v-text-field>
|
:loading="ingredient.loading" @click:clear="deleteFoodProperty(p, ingredient)" clearable></v-text-field>
|
||||||
<v-btn variant="outlined" color="create" block v-if="p.propertyAmount == null" @click="p.propertyAmount = 0">
|
<v-btn variant="outlined" color="create" block v-if="p.propertyAmount == null" @click="p.propertyAmount = 0">
|
||||||
<v-icon icon="$create"></v-icon>
|
<v-icon icon="$create"></v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@@ -123,7 +143,8 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<fdc-search-dialog v-model="fdcDialog" @selected="(fdcId:number) => {fdcSelectedFood.fdcId = fdcId; updateFoodFdcData(fdcSelectedFood)}"></fdc-search-dialog>
|
<fdc-search-dialog v-model="fdcDialog"
|
||||||
|
@selected="(fdcId:number) => {fdcSelectedIngredient.food.fdcId = fdcId; updateFoodFdcData(fdcSelectedIngredient)}"></fdc-search-dialog>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
<v-dialog v-model="dialog" max-width="600">
|
<v-dialog v-model="dialog" max-width="600">
|
||||||
@@ -153,7 +174,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {computed, onMounted, ref} from "vue";
|
import {computed, onMounted, ref} from "vue";
|
||||||
import {ApiApi, Food, Property, PropertyType, Recipe, Unit} from "@/openapi";
|
import {ApiApi, Food, Ingredient, Property, PropertyType, Recipe, Unit} from "@/openapi";
|
||||||
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
import ModelSelect from "@/components/inputs/ModelSelect.vue";
|
||||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||||
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
|
||||||
@@ -162,7 +183,7 @@ import {useUrlSearchParams} from "@vueuse/core";
|
|||||||
import BtnCopy from "@/components/buttons/BtnCopy.vue";
|
import BtnCopy from "@/components/buttons/BtnCopy.vue";
|
||||||
import FdcSearchDialog from "@/components/dialogs/FdcSearchDialog.vue";
|
import FdcSearchDialog from "@/components/dialogs/FdcSearchDialog.vue";
|
||||||
|
|
||||||
type FoodLoading = Food & { loading?: boolean }
|
type IngredientLoading = Ingredient & { loading?: boolean }
|
||||||
|
|
||||||
const params = useUrlSearchParams('history', {})
|
const params = useUrlSearchParams('history', {})
|
||||||
|
|
||||||
@@ -179,11 +200,11 @@ const calculatorFromDenominator = ref(500)
|
|||||||
const calculatorToDenominator = ref(100)
|
const calculatorToDenominator = ref(100)
|
||||||
|
|
||||||
const fdcDialog = ref(false)
|
const fdcDialog = ref(false)
|
||||||
const fdcSelectedFood = ref<FoodLoading| undefined>(undefined)
|
const fdcSelectedIngredient = ref<IngredientLoading | undefined>(undefined)
|
||||||
|
|
||||||
const recipe = ref<undefined | Recipe>()
|
const recipe = ref<undefined | Recipe>()
|
||||||
const propertyTypes = ref([] as PropertyType[])
|
const propertyTypes = ref([] as PropertyType[])
|
||||||
const foods = ref(new Map<number, FoodLoading>())
|
const ingredients = ref(new Map<number, IngredientLoading>())
|
||||||
|
|
||||||
const recipeLoading = ref(false)
|
const recipeLoading = ref(false)
|
||||||
const propertyTypesLoading = ref(false)
|
const propertyTypesLoading = ref(false)
|
||||||
@@ -207,7 +228,7 @@ function loadRecipe(id: number) {
|
|||||||
recipeLoading.value = true
|
recipeLoading.value = true
|
||||||
api.apiRecipeRetrieve({id: id}).then(r => {
|
api.apiRecipeRetrieve({id: id}).then(r => {
|
||||||
recipe.value = r
|
recipe.value = r
|
||||||
buildFoodMap()
|
buildIngredientMap()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -223,7 +244,7 @@ function loadPropertyTypes() {
|
|||||||
propertyTypesLoading.value = true
|
propertyTypesLoading.value = true
|
||||||
api.apiPropertyTypeList().then(r => {
|
api.apiPropertyTypeList().then(r => {
|
||||||
propertyTypes.value = r.results
|
propertyTypes.value = r.results
|
||||||
buildFoodMap()
|
buildIngredientMap()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
@@ -236,16 +257,16 @@ function loadPropertyTypes() {
|
|||||||
* add properties if a food is missing any
|
* add properties if a food is missing any
|
||||||
* set null to indicate missing property, 0 for properties with the actual value 0
|
* set null to indicate missing property, 0 for properties with the actual value 0
|
||||||
*/
|
*/
|
||||||
function buildFoodMap() {
|
function buildIngredientMap() {
|
||||||
foods.value = new Map<number, FoodLoading>()
|
ingredients.value = new Map<number, IngredientLoading>()
|
||||||
|
|
||||||
if (recipe.value != undefined) {
|
if (recipe.value != undefined) {
|
||||||
recipe.value.steps.forEach(step => {
|
recipe.value.steps.forEach(step => {
|
||||||
step.ingredients.forEach(ingredient => {
|
step.ingredients.forEach(ingredient => {
|
||||||
if (ingredient.food && !foods.value.has(ingredient.food.id!)) {
|
if (ingredient.food && !ingredients.value.has(ingredient.food.id!)) {
|
||||||
let food: FoodLoading = buildFoodProperties(ingredient.food)
|
let i: IngredientLoading = buildIngredientFoodProperties(ingredient)
|
||||||
food.loading = false
|
i.loading = false
|
||||||
foods.value.set(food.id!, food)
|
ingredients.value.set(i.food.id!, i)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -255,43 +276,43 @@ function buildFoodMap() {
|
|||||||
/**
|
/**
|
||||||
* add all property types to food in the correct order
|
* add all property types to food in the correct order
|
||||||
* add null if no data exists for a property type to indicate a missing property
|
* add null if no data exists for a property type to indicate a missing property
|
||||||
* @param food
|
* @param ingredient
|
||||||
*/
|
*/
|
||||||
function buildFoodProperties(food: Food) {
|
function buildIngredientFoodProperties(ingredient: Ingredient) {
|
||||||
let existingProperties = new Map<number, Property>()
|
let existingProperties = new Map<number, Property>()
|
||||||
food.properties!.forEach(fp => {
|
ingredient.food.properties!.forEach(fp => {
|
||||||
existingProperties.set(fp.propertyType.id!, fp)
|
existingProperties.set(fp.propertyType.id!, fp)
|
||||||
})
|
})
|
||||||
|
|
||||||
food.properties = [] as Property[]
|
ingredient.food.properties = [] as Property[]
|
||||||
|
|
||||||
propertyTypes.value.forEach(pt => {
|
propertyTypes.value.forEach(pt => {
|
||||||
if (existingProperties.has(pt.id!)) {
|
if (existingProperties.has(pt.id!)) {
|
||||||
food.properties!.push(existingProperties.get(pt.id!))
|
ingredient.food.properties!.push(existingProperties.get(pt.id!))
|
||||||
} else {
|
} else {
|
||||||
food.properties!.push({propertyType: pt, propertyAmount: null} as Property)
|
ingredient.food.properties!.push({propertyType: pt, propertyAmount: null} as Property)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return food
|
return ingredient
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* deletes the given property either on client or also on server if it has an id
|
* deletes the given property either on client or also on server if it has an id
|
||||||
* @param p
|
* @param p
|
||||||
* @param food
|
* @param ingredient
|
||||||
*/
|
*/
|
||||||
function deleteFoodProperty(p: Property, food: FoodLoading) {
|
function deleteFoodProperty(p: Property, ingredient: IngredientLoading) {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
|
|
||||||
if (p.id) {
|
if (p.id) {
|
||||||
food.loading = true
|
ingredient.loading = true
|
||||||
api.apiPropertyDestroy({id: p.id}).then(r => {
|
api.apiPropertyDestroy({id: p.id}).then(r => {
|
||||||
p.propertyAmount = null
|
p.propertyAmount = null
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
|
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
food.loading = false
|
ingredient.loading = false
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
p.propertyAmount = null
|
p.propertyAmount = null
|
||||||
@@ -300,34 +321,35 @@ function deleteFoodProperty(p: Property, food: FoodLoading) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* update food
|
* update food
|
||||||
* @param food
|
* @param ingredient
|
||||||
*/
|
*/
|
||||||
function updateFood(food: FoodLoading) {
|
function updateFood(ingredient: IngredientLoading) {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
food.loading = true
|
ingredient.loading = true
|
||||||
api.apiFoodPartialUpdate({id: food.id!, patchedFood: food}).then(r => {
|
api.apiFoodPartialUpdate({id: ingredient.food.id!, patchedFood: ingredient.food}).then(r => {
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
food.loading = false
|
ingredient.loading = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the food FDC data on the server and put the updated food into the food map
|
* Update the food FDC data on the server and put the updated food into the food map
|
||||||
* @param food
|
* @param ingredient
|
||||||
*/
|
*/
|
||||||
function updateFoodFdcData(food: FoodLoading) {
|
function updateFoodFdcData(ingredient: IngredientLoading) {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
food.loading = true
|
ingredient.loading = true
|
||||||
if (food.fdcId) {
|
if (ingredient.food.fdcId) {
|
||||||
api.apiFoodFdcCreate({id: food.id!, food: food}).then(r => {
|
api.apiFoodFdcCreate({id: ingredient.food.id!, food: ingredient.food}).then(r => {
|
||||||
foods.value.set(r.id!, buildFoodProperties(r))
|
ingredient.food = r
|
||||||
|
ingredients.value.set(r.id!, buildIngredientFoodProperties(ingredient))
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
food.loading = false
|
ingredient.loading = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,9 +359,9 @@ function updateFoodFdcData(food: FoodLoading) {
|
|||||||
* @param unit
|
* @param unit
|
||||||
*/
|
*/
|
||||||
function changeAllUnits(unit: Unit) {
|
function changeAllUnits(unit: Unit) {
|
||||||
foods.value.forEach(food => {
|
ingredients.value.forEach(ingredient => {
|
||||||
food.propertiesFoodUnit = unit
|
ingredient.food.propertiesFoodUnit = unit
|
||||||
updateFood(food)
|
updateFood(ingredient)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,9 +370,9 @@ function changeAllUnits(unit: Unit) {
|
|||||||
* @param amount
|
* @param amount
|
||||||
*/
|
*/
|
||||||
function changeAllPropertyFoodAmounts(amount: number) {
|
function changeAllPropertyFoodAmounts(amount: number) {
|
||||||
foods.value.forEach(food => {
|
ingredients.value.forEach(ingredient => {
|
||||||
food.propertiesFoodAmount = amount
|
ingredient.food.propertiesFoodAmount = amount
|
||||||
updateFood(food)
|
updateFood(ingredient)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user