basic food property viewer in recipe view
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
from cookbook.models import FoodPropertyType
|
||||
from cookbook.models import FoodPropertyType, Unit, Food, FoodProperty, Recipe, Step
|
||||
|
||||
|
||||
class FoodPropertyHelper:
|
||||
@ -25,7 +25,7 @@ class FoodPropertyHelper:
|
||||
ingredients += s.ingredients.all()
|
||||
|
||||
for fpt in property_types: # TODO is this safe or should I require the request context?
|
||||
computed_properties[fpt.id] = {'id': fpt.id, 'name': fpt.name, 'icon': fpt.icon, 'description': fpt.description, 'unit': fpt.unit, 'food_values': {}, 'total_value': 0}
|
||||
computed_properties[fpt.id] = {'id': fpt.id, 'name': fpt.name, 'icon': fpt.icon, 'description': fpt.description, 'unit': fpt.unit, 'food_values': {}, 'total_value': 0, 'missing_value': False}
|
||||
|
||||
# TODO unit conversion support
|
||||
|
||||
@ -33,9 +33,10 @@ class FoodPropertyHelper:
|
||||
for pt in property_types:
|
||||
p = i.food.foodproperty_set.filter(space=self.space, property_type=pt).first()
|
||||
if p:
|
||||
computed_properties[p.property_type.id]['total_value'] += (i.amount / p.food_amount) * p.property_amount
|
||||
computed_properties[p.property_type.id]['food_values'] = self.add_or_create(computed_properties[p.property_type.id]['food_values'], i.food.id, (i.amount / p.food_amount) * p.property_amount, i.food)
|
||||
computed_properties[pt.id]['total_value'] += (i.amount / p.food_amount) * p.property_amount
|
||||
computed_properties[pt.id]['food_values'] = self.add_or_create(computed_properties[p.property_type.id]['food_values'], i.food.id, (i.amount / p.food_amount) * p.property_amount, i.food)
|
||||
else:
|
||||
computed_properties[pt.id]['missing_value'] = True
|
||||
computed_properties[pt.id]['food_values'][i.food.id] = {'id': i.food.id, 'food': i.food.name, 'value': 0}
|
||||
|
||||
return computed_properties
|
||||
@ -49,3 +50,40 @@ class FoodPropertyHelper:
|
||||
else:
|
||||
d[key] = {'id': food.id, 'food': food.name, 'value': value}
|
||||
return d
|
||||
|
||||
def generate_debug_recipe(self):
|
||||
"""
|
||||
DEBUG FUNCTION ONLY, generates a test recipe
|
||||
"""
|
||||
unit_gram = Unit.objects.create(name='gram', base_unit='g', space=self.space)
|
||||
unit_pcs = Unit.objects.create(name='pcs', base_unit='', space=self.space)
|
||||
unit_floz1 = Unit.objects.create(name='fl. oz 1', base_unit='imperial_fluid_ounce', space=self.space) # US and UK use different volume systems (US vs imperial)
|
||||
unit_floz2 = Unit.objects.create(name='fl. oz 2', base_unit='fluid_ounce', space=self.space)
|
||||
unit_fantasy = Unit.objects.create(name='Fantasy Unit', base_unit='', space=self.space)
|
||||
|
||||
food_1 = Food.objects.create(name='Food 1', space=self.space)
|
||||
food_2 = Food.objects.create(name='Food 2', space=self.space)
|
||||
|
||||
property_fat = FoodPropertyType.objects.create(name='Fat', unit='g', space=self.space)
|
||||
property_calories = FoodPropertyType.objects.create(name='Calories', unit='kcal', space=self.space)
|
||||
property_nuts = FoodPropertyType.objects.create(name='Nuts', space=self.space)
|
||||
property_price = FoodPropertyType.objects.create(name='Price', unit='€', space=self.space)
|
||||
|
||||
food_1_property_fat = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_1, property_amount=50, property_type=property_fat, space=self.space)
|
||||
food_1_property_nuts = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_1, property_amount=1, property_type=property_nuts, space=self.space)
|
||||
food_1_property_price = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_1, property_amount=7.50, property_type=property_price, space=self.space)
|
||||
|
||||
food_2_property_fat = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_2, property_amount=25, property_type=property_fat, space=self.space)
|
||||
food_2_property_nuts = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_2, property_amount=0, property_type=property_nuts, space=self.space)
|
||||
food_2_property_price = FoodProperty.objects.create(food_amount=100, food_unit=unit_gram, food=food_2, property_amount=2.50, property_type=property_price, space=self.space)
|
||||
|
||||
recipe_1 = Recipe.objects.create(name='recipe_1', waiting_time=0, working_time=0, space=self.space, created_by=self.space.created_by)
|
||||
|
||||
step_1 = Step.objects.create(instruction='instruction_step_1', space=self.space)
|
||||
step_1.ingredients.create(amount=500, unit=unit_gram, food=food_1, space=self.space)
|
||||
step_1.ingredients.create(amount=1000, unit=unit_gram, food=food_2, space=self.space)
|
||||
recipe_1.steps.add(step_1)
|
||||
|
||||
step_2 = Step.objects.create(instruction='instruction_step_1', space=self.space)
|
||||
step_2.ingredients.create(amount=50, unit=unit_gram, food=food_1, space=self.space)
|
||||
recipe_1.steps.add(step_2)
|
||||
|
@ -23,6 +23,7 @@ from oauth2_provider.models import AccessToken
|
||||
from cookbook.forms import (CommentForm, Recipe, SearchPreferenceForm, ShoppingPreferenceForm,
|
||||
SpaceCreateForm, SpaceJoinForm, User,
|
||||
UserCreateForm, UserNameForm, UserPreference, UserPreferenceForm)
|
||||
from cookbook.helper.food_property_helper import FoodPropertyHelper
|
||||
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
||||
from cookbook.models import (Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink,
|
||||
Space, ViewLog, UserSpace)
|
||||
@ -451,3 +452,4 @@ def test(request):
|
||||
def test2(request):
|
||||
if not settings.DEBUG:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
FoodPropertyHelper(request.space).generate_debug_recipe()
|
||||
|
@ -137,8 +137,9 @@
|
||||
|
||||
<div class="row" style="margin-top: 2vh; ">
|
||||
<div class="col-lg-6 offset-lg-3 col-12">
|
||||
<Nutrition-component :recipe="recipe" id="nutrition_container"
|
||||
:ingredient_factor="ingredient_factor"></Nutrition-component>
|
||||
<!-- <Nutrition-component :recipe="recipe" id="nutrition_container"-->
|
||||
<!-- :ingredient_factor="ingredient_factor"></Nutrition-component>-->
|
||||
<food-property-view-component :recipe="recipe"></food-property-view-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -185,6 +186,7 @@ import CustomInputSpinButton from "@/components/CustomInputSpinButton"
|
||||
import {ApiApiFactory} from "@/utils/openapi/api";
|
||||
import ImportTandoor from "@/components/Modals/ImportTandoor.vue";
|
||||
import BottomNavigationBar from "@/components/BottomNavigationBar.vue";
|
||||
import FoodPropertyViewComponent from "@/components/FoodPropertyViewComponent.vue";
|
||||
|
||||
Vue.prototype.moment = moment
|
||||
|
||||
@ -202,13 +204,14 @@ export default {
|
||||
IngredientsCard,
|
||||
StepComponent,
|
||||
RecipeContextMenu,
|
||||
NutritionComponent,
|
||||
// NutritionComponent,
|
||||
KeywordsComponent,
|
||||
LoadingSpinner,
|
||||
AddRecipeToBook,
|
||||
RecipeSwitcher,
|
||||
CustomInputSpinButton,
|
||||
BottomNavigationBar,
|
||||
FoodPropertyViewComponent,
|
||||
},
|
||||
computed: {
|
||||
ingredient_factor: function () {
|
||||
|
@ -6,32 +6,38 @@
|
||||
<div class="row" v-if="recipe !== undefined">
|
||||
<div class="col-6">
|
||||
<div class="card">
|
||||
<table>
|
||||
<tbody v-for="p in recipe.food_properties" v-bind:key="`id_${p.id}`">
|
||||
<tr>
|
||||
<td><b-button v-b-toggle="`id_collapse_property_${p.id}`" size="sm"><i class="fas fa-caret-right"></i></b-button></td>
|
||||
<td>{{ p.icon }}</td>
|
||||
<td>{{ p.name }}</td>
|
||||
<td>{{ p.total_value }} {{ p.unit }}</td>
|
||||
</tr>
|
||||
<b-collapse :id="`id_collapse_property_${p.id}`" class="mt-2">
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
{{p.description}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="f in p.food_values" v-bind:key="`id_${p.id}_food_${f.id}`">
|
||||
<td>{{f.food}}</td>
|
||||
<td>{{f.value}} {{ p.unit }}</td>
|
||||
</tr>
|
||||
</b-collapse>
|
||||
</tbody>
|
||||
<table class="table table-bordered table-sm">
|
||||
|
||||
<tr v-for="p in recipe.food_properties" v-bind:key="`id_${p.id}`">
|
||||
<td>
|
||||
<button class="btn btn-danger btn-sm"
|
||||
@click="selected_property = p"><i
|
||||
class="fas fa-exclamation-triangle"></i>
|
||||
</button>
|
||||
{{ p.icon }} {{ p.name }}
|
||||
</td>
|
||||
<td>{{ p.total_value }} {{ p.unit }}</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-modal id="id_modal_property_overview" title="Property Overview" v-model="show_modal" @hidden="selected_property = undefined">
|
||||
<template v-if="selected_property !== undefined">
|
||||
{{ selected_property.description }}
|
||||
<table class="table table-bordered">
|
||||
<tr v-for="f in selected_property.food_values" v-bind:key="`id_${selected_property.id}_food_${f.id}`">
|
||||
<td>{{ f.food }}</td>
|
||||
<td>{{ f.value }} {{ selected_property.unit }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
|
||||
</b-modal>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@ -57,9 +63,14 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
recipe: undefined,
|
||||
|
||||
selected_property: undefined,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
show_modal: function () {
|
||||
return this.selected_property !== undefined
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||
let apiClient = new ApiApiFactory()
|
||||
@ -74,4 +85,5 @@ export default {
|
||||
|
||||
<style>
|
||||
|
||||
|
||||
</style>
|
||||
|
73
vue/src/components/FoodPropertyViewComponent.vue
Normal file
73
vue/src/components/FoodPropertyViewComponent.vue
Normal file
@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
|
||||
<div class="card" v-if="recipe !== undefined">
|
||||
<h5>Properties</h5>
|
||||
<table class="table table-bordered table-sm">
|
||||
|
||||
<tr v-for="p in recipe.food_properties" v-bind:key="`id_${p.id}`">
|
||||
<td>
|
||||
<button class="btn btn-danger btn-sm"
|
||||
@click="selected_property = p"
|
||||
v-if="p.missing_value"><i
|
||||
class="fas fa-exclamation-triangle"></i>
|
||||
</button>
|
||||
{{ p.icon }} {{ p.name }}
|
||||
</td>
|
||||
<td>{{ p.total_value }} {{ p.unit }}</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<b-modal id="id_modal_property_overview" title="Property Overview" v-model="show_modal"
|
||||
@hidden="selected_property = undefined">
|
||||
<template v-if="selected_property !== undefined">
|
||||
{{ selected_property.description }}
|
||||
<table class="table table-bordered">
|
||||
<tr v-for="f in selected_property.food_values"
|
||||
v-bind:key="`id_${selected_property.id}_food_${f.id}`">
|
||||
<td>{{ f.food }}</td>
|
||||
<td>{{ f.value }} {{ selected_property.unit }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
|
||||
</b-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ApiMixin} from "@/utils/utils";
|
||||
|
||||
export default {
|
||||
name: "FoodPropertyViewComponent",
|
||||
mixins: [ApiMixin],
|
||||
components: {},
|
||||
props: {
|
||||
recipe: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selected_property: undefined,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
show_modal: function () {
|
||||
return this.selected_property !== undefined
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
Reference in New Issue
Block a user