added unit conversion editor to food editor

This commit is contained in:
vabene1111 2023-05-29 17:16:22 +02:00
parent c0577abb89
commit 326549568f
3 changed files with 278 additions and 4160 deletions

View File

@ -816,30 +816,30 @@ class RecipeViewSet(viewsets.ModelViewSet):
if self.detail: # if detail request and not list, private condition is verified by permission class
if not share: # filter for space only if not shared
self.queryset = self.queryset.filter(space=self.request.space).prefetch_related(
'keywords',
'shared',
'properties',
'properties__property_type',
'steps',
'steps__ingredients',
'steps__ingredients__step_set',
'steps__ingredients__step_set__recipe_set',
'steps__ingredients__food',
'steps__ingredients__food__properties',
'steps__ingredients__food__properties__property_type',
'steps__ingredients__food__inherit_fields',
'steps__ingredients__food__supermarket_category',
'steps__ingredients__food__onhand_users',
'steps__ingredients__food__substitute',
'steps__ingredients__food__child_inherit_fields',
'steps__ingredients__unit',
'steps__ingredients__unit__unit_conversion_base_relation',
'steps__ingredients__unit__unit_conversion_base_relation__base_unit',
'steps__ingredients__unit__unit_conversion_converted_relation',
'steps__ingredients__unit__unit_conversion_converted_relation__converted_unit',
'cooklog_set',
).select_related('nutrition')
'keywords',
'shared',
'properties',
'properties__property_type',
'steps',
'steps__ingredients',
'steps__ingredients__step_set',
'steps__ingredients__step_set__recipe_set',
'steps__ingredients__food',
'steps__ingredients__food__properties',
'steps__ingredients__food__properties__property_type',
'steps__ingredients__food__inherit_fields',
'steps__ingredients__food__supermarket_category',
'steps__ingredients__food__onhand_users',
'steps__ingredients__food__substitute',
'steps__ingredients__food__child_inherit_fields',
'steps__ingredients__unit',
'steps__ingredients__unit__unit_conversion_base_relation',
'steps__ingredients__unit__unit_conversion_base_relation__base_unit',
'steps__ingredients__unit__unit_conversion_converted_relation',
'steps__ingredients__unit__unit_conversion_converted_relation__converted_unit',
'cooklog_set',
).select_related('nutrition')
return super().get_queryset()
@ -973,8 +973,16 @@ class UnitConversionViewSet(viewsets.ModelViewSet):
queryset = UnitConversion.objects
serializer_class = UnitConversionSerializer
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]
query_params = [
QueryParam(name='food_id', description='ID of food to filter for', qtype='int'),
]
schema = QueryParamAutoSchema()
def get_queryset(self):
food_id = self.request.query_params.get('food_id', None)
if food_id is not None:
self.queryset = self.queryset.filter(food_id=food_id)
return self.queryset.filter(space=self.request.space)

View File

@ -2,7 +2,7 @@
<div>
<b-modal :id="id" size="xl" @hidden="cancelAction">
<b-modal :id="id" size="xl" @hidden="cancelAction" :body-class="`pr-3 pl-3`">
<template v-slot:modal-title>
<div class="row" v-if="food">
@ -15,95 +15,147 @@
</div>
</template>
<div class="row">
<div class="col-12">
<b-form v-if="food">
<b-form-group :label="$t('Name')" description="">
<b-form-input v-model="food.name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Plural')" description="">
<b-form-input v-model="food.plural_name"></b-form-input>
</b-form-group>
<div>
<b-tabs content-class="mt-3" v-if="food">
<b-tab title="General" active>
<b-form>
<b-form-group :label="$t('Name')" description="">
<b-form-input v-model="food.name"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Plural')" description="">
<b-form-input v-model="food.plural_name"></b-form-input>
</b-form-group>
<!-- Food properties -->
<!-- Food properties -->
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
<h5><i class="fas fa-database"></i> {{ $t('Properties') }}</h5>
<b-form-group :label="$t('Properties Food Amount')" description=""> <!-- TODO localize -->
<b-form-input v-model="food.properties_food_amount"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Properties Food Amount')" description=""> <!-- TODO localize -->
<b-form-input v-model="food.properties_food_amount"></b-form-input>
</b-form-group>
<b-form-group :label="$t('Properties Food Unit')" description=""> <!-- TODO localize -->
<generic-multiselect
@change="food.properties_food_unit = $event.val;"
:model="Models.UNIT"
:initial_single_selection="food.properties_food_unit"
label="name"
:multiple="false"
:placeholder="$t('Unit')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('Properties Food Unit')" description=""> <!-- TODO localize -->
<generic-multiselect
@change="food.properties_food_unit = $event.val;"
:model="Models.UNIT"
:initial_single_selection="food.properties_food_unit"
label="name"
:multiple="false"
:placeholder="$t('Unit')"
></generic-multiselect>
</b-form-group>
<table class="table table-bordered">
<thead>
<tr>
<th> {{ $t('Property Amount') }}</th> <!-- TODO localize -->
<th> {{ $t('Property Type') }}</th> <!-- TODO localize -->
<th></th>
<th></th>
</tr>
</thead>
<tr v-for="fp in food.properties" v-bind:key="fp.id">
<td><input v-model="fp.property_amount" type="number"> <span
v-if="fp.property_type">{{ fp.property_type.unit }}</span></td>
<td>
<generic-multiselect
@change="fp.property_type = $event.val"
:initial_single_selection="fp.property_type"
label="name" :model="Models.PROPERTY_TYPE"
:multiple="false"/>
</td>
<td> / <span>{{ food.properties_food_amount }} <span
v-if="food.properties_food_unit !== null">{{
food.properties_food_unit.name
}}</span></span>
</td>
<td>
<button class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
class="fas fa-trash-alt"></i></button>
</td>
</tr>
</table>
<table class="table table-bordered">
<thead>
<tr>
<th> {{ $t('Property Amount') }}</th> <!-- TODO localize -->
<th> {{ $t('Property Type') }}</th> <!-- TODO localize -->
<th></th>
<th></th>
</tr>
</thead>
<tr v-for="fp in food.properties" v-bind:key="fp.id">
<td><input v-model="fp.property_amount" type="number"> <span
v-if="fp.property_type">{{ fp.property_type.unit }}</span></td>
<td>
<generic-multiselect
@change="fp.property_type = $event.val"
:initial_single_selection="fp.property_type"
label="name" :model="Models.PROPERTY_TYPE"
:multiple="false"/>
</td>
<td> / <span>{{ food.properties_food_amount }} <span
v-if="food.properties_food_unit !== null">{{
food.properties_food_unit.name
}}</span></span>
</td>
<td>
<button class="btn btn-danger btn-small" @click="deleteProperty(fp)"><i
class="fas fa-trash-alt"></i></button>
</td>
</tr>
</table>
<div class="text-center">
<b-button-group>
<b-btn class="btn btn-success shadow-none" @click="addProperty()"><i
class="fa fa-plus"></i>
</b-btn>
<b-btn class="btn btn-secondary shadow-none" @click="addAllProperties()"><i
class="fa fa-plus"> <i class="ml-1 fas fa-list"></i></i>
</b-btn>
</b-button-group>
<div class="text-center">
<b-button-group>
<b-btn class="btn btn-success shadow-none" @click="addProperty()"><i
class="fa fa-plus"></i>
</b-btn>
<b-btn class="btn btn-secondary shadow-none" @click="addAllProperties()"><i
class="fa fa-plus"> <i class="ml-1 fas fa-list"></i></i>
</b-btn>
</b-button-group>
</div>
</div>
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
<generic-multiselect
@change="food.supermarket_category = $event.val;"
:model="Models.SHOPPING_CATEGORY"
:initial_single_selection="food.supermarket_category"
label="name"
:multiple="false"
:allow_create="true"
:placeholder="$t('Shopping_Category')"
></generic-multiselect>
</b-form-group>
<b-form-group :label="$t('Shopping_Category')" :description="$t('shopping_category_help')">
<generic-multiselect
@change="food.supermarket_category = $event.val;"
:model="Models.SHOPPING_CATEGORY"
:initial_single_selection="food.supermarket_category"
label="name"
:multiple="false"
:allow_create="true"
:placeholder="$t('Shopping_Category')"
></generic-multiselect>
</b-form-group>
</b-form>
</b-tab>
<b-tab title="Conversions" @click="loadUnitConversions" v-if="this.food.id !== undefined">
<b-row v-for="uc in unit_conversions" :key="uc">
<b-col>
<span v-if="uc.id">
<b-btn class="btn btn-sm" variant="danger" @click="deleteUnitConversion(uc)"><i class="fas fa-trash-alt"></i></b-btn>
{{uc.base_amount}}
{{uc.base_unit.name}}
=
{{uc.converted_amount}}
{{uc.converted_unit.name}}
</span>
<b-form class="mt-1">
<b-input-group>
<b-input v-model="uc.base_amount" @change="uc.changed = true"></b-input>
<b-input-group-append>
<generic-multiselect
@change="uc.base_unit = $event.val; uc.changed = true"
:initial_single_selection="uc.base_unit"
label="name" :model="Models.UNIT"
:multiple="false"/>
</b-input-group-append>
</b-input-group>
<b-input-group>
<b-input v-model="uc.converted_amount" @change="uc.changed = true"></b-input>
<b-input-group-append>
<generic-multiselect
@change="uc.converted_unit = $event.val; uc.changed = true"
:initial_single_selection="uc.converted_unit"
label="name" :model="Models.UNIT"
:multiple="false"/>
</b-input-group-append>
</b-input-group>
</b-form>
</b-col>
<hr style="height: 1px"/>
</b-row>
<b-row>
<b-col class="text-center">
<b-btn variant="success" @click="addUnitConversion"><i class="fa fa-plus"></i></b-btn>
</b-col>
</b-row>
</b-tab>
<b-tab title="More">
<b-form>
<!-- Unit conversion -->
<!-- ADVANCED FEATURES somehow hide this stuff -->
<b-collapse id="collapse-advanced">
<b-form-group :label="$t('Recipe')" :description="$t('food_recipe_help')">
<generic-multiselect
@change="food.recipe = $event.val;"
@ -176,16 +228,15 @@
}}
</b-form-checkbox>
</b-form-group>
</b-collapse>
</b-form>
</div>
</b-form>
</b-tab>
</b-tabs>
</div>
<template v-slot:modal-footer>
<b-button variant="primary" @click="updateFood">{{ $t('Save') }}</b-button>
<b-button v-b-toggle.collapse-advanced class="m-1">{{ $t('Advanced') }}</b-button>
</template>
</b-modal>
</div>
@ -231,6 +282,7 @@ export default {
data() {
return {
food: undefined,
unit_conversions: []
}
},
mounted() {
@ -286,6 +338,24 @@ export default {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err)
})
}
this.unit_conversions.forEach(uc => {
if (uc.changed === true) {
if (uc.id === undefined) {
apiClient.createUnitConversion(uc).then(r => {
uc = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_CREATE, err, true)
})
} else {
apiClient.updateUnitConversion(uc.id, uc).then(r => {
uc = r.data
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err, true)
})
}
}
})
},
addProperty: function () {
this.food.properties.push({property_type: null, property_amount: 0})
@ -306,6 +376,32 @@ export default {
cancelAction: function () {
this.$emit("hidden", "")
},
loadUnitConversions: function () {
let apiClient = new ApiApiFactory()
apiClient.listUnitConversions(this.food.id).then(r => {
this.unit_conversions = r.data
})
},
addUnitConversion: function () {
this.unit_conversions.push(
{
food: this.food,
base_amount: 1,
base_unit: null,
converted_amount: 0,
converted_unit: null,
}
)
},
deleteUnitConversion: function (uc){
this.unit_conversions = this.unit_conversions.filter(u => u !== uc)
let apiClient = new ApiApiFactory()
apiClient.destroyUnitConversion(uc.id).then(r => {
StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_DELETE)
}).catch(err => {
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_DELETE, err)
})
}
},
}
</script>

File diff suppressed because it is too large Load Diff