shopping list item checking

This commit is contained in:
vabene1111
2020-09-21 22:55:52 +02:00
parent 4827364e37
commit 148ce2faef
3 changed files with 82 additions and 19 deletions

View File

@ -14,16 +14,17 @@
<script src="{% static 'js/Sortable.min.js' %}"></script> <script src="{% static 'js/Sortable.min.js' %}"></script>
<script src="{% static 'js/vuedraggable.umd.min.js' %}"></script> <script src="{% static 'js/vuedraggable.umd.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/pretty-checkbox.min.css' %}">
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col col-9"> <div class="col col-md-9">
<h2>{% trans 'Shopping List' %}</h2> <h2>{% trans 'Shopping List' %}</h2>
</div> </div>
<!--TODO proper alignment --> <div class="col col-mdd-3 text-right">
<div class="col col-3 text-right">
<b-form-checkbox switch size="lg" v-model="edit_mode">{% trans 'Edit' %}</b-form-checkbox> <b-form-checkbox switch size="lg" v-model="edit_mode">{% trans 'Edit' %}</b-form-checkbox>
</div> </div>
</div> </div>
@ -47,7 +48,10 @@
<ul class="list-group" style="margin-top: 8px"> <ul class="list-group" style="margin-top: 8px">
<li class="list-group-item" v-for="x in recipes"> <li class="list-group-item" v-for="x in recipes">
<div class="row flex-row" style="padding-left: 0.5vw; padding-right: 0.5vw"> <div class="row flex-row" style="padding-left: 0.5vw; padding-right: 0.5vw">
<div class="flex-column flex-fill my-auto">[[x.name]]</div> <div class="flex-column flex-fill my-auto"><a v-bind:href="getRecipeUrl(x.id)"
target="_blank"
rel="nofollow norefferer">[[x.name]]</a>
</div>
<div class="flex-column align-self-end"> <div class="flex-column align-self-end">
<button class="btn btn-outline-primary shadow-none" <button class="btn btn-outline-primary shadow-none"
@click="addRecipeToList(x)"><i @click="addRecipeToList(x)"><i
@ -72,7 +76,10 @@
<template v-else> <template v-else>
<div class="row flex-row my-auto" v-for="x in shopping_list.recipes" <div class="row flex-row my-auto" v-for="x in shopping_list.recipes"
style="margin-top: 0.5vh!important;"> style="margin-top: 0.5vh!important;">
<div class="flex-grow-1 flex-column my-auto">[[x.recipe_name]]</div> <div class="flex-grow-1 flex-column my-auto"><a v-bind:href="getRecipeUrl(x.recipe)"
target="_blank"
rel="nofollow norefferer">[[x.recipe_name]]</a>
</div>
<div class="flex-column align-self-end "> <div class="flex-column align-self-end ">
<div class="input-group input-group-sm my-auto"> <div class="input-group input-group-sm my-auto">
<div class="input-group-prepend"> <div class="input-group-prepend">
@ -159,12 +166,12 @@
@search-change="searchFoods"> @search-change="searchFoods">
</multiselect> </multiselect>
</div> </div>
<div class="col col-md-1 my-auto text-right"> <div class="col col-md-1 my-auto text-right">
<button class="btn btn-success btn-lg" @click="addEntry()"><i class="fa fa-plus"></i> <button class="btn btn-success btn-lg" @click="addEntry()"><i class="fa fa-plus"></i>
</button> </button>
</div> </div>
</div> </div>
</div>
<div class="row" style="margin-top: 4vh"> <div class="row" style="margin-top: 4vh">
<div class="col col-12 text-right"> <div class="col col-12 text-right">
@ -174,8 +181,21 @@
</div> </div>
</div> </div>
</div> </div>
<div v-else=""> <div v-else>
Non Edit
<div class="row" style="margin-top: 8px">
<div class="col col-md-12">
<table class="table table table-striped">
<tr v-for="x in display_entries">
<td><input type="checkbox" style="zoom:1.4;" v-model="x.checked" @change="entryChecked(x)">
</td>
<td>[[x.amount]]</td>
<td>[[x.unit.name]]</td>
<td>[[x.food.name]]</td>
</tr>
</table>
</div>
</div>
</div> </div>
@ -199,7 +219,7 @@
data: { data: {
shopping_list_id: {% if shopping_list_id %}{{ shopping_list_id }}{% else %}null{% endif %}, shopping_list_id: {% if shopping_list_id %}{{ shopping_list_id }}{% else %}null{% endif %},
loading: true, loading: true,
edit_mode: true, edit_mode: false,
recipe_query: '', recipe_query: '',
recipes: [], recipes: [],
shopping_list: undefined, shopping_list: undefined,
@ -353,6 +373,26 @@
}) })
},
entryChecked: function (entry) {
this.shopping_list.entries.forEach((item) => {
if (item.id === entry.id) { //TODO unwrap once same entries are merged
item.checked = entry.checked
console.log('updating ', item)
this.$http.put("{% url 'api:shoppinglistentry-detail' 123456 %}".replace('123456', item.id), item, {}).then((response) => {
console.log("YEHAA", response)
}).catch((err) => {
console.log(err)
this.makeToast('{% trans 'Error' %}', '{% trans 'There was an error updating a resource!' %}' + err.bodyText, 'danger')
this.loading = false
})
}
})
}, },
addEntry: function () { addEntry: function () {
this.shopping_list.entries.push({ this.shopping_list.entries.push({
@ -360,7 +400,8 @@
'food': this.new_entry.food, 'food': this.new_entry.food,
'unit': ((this.new_entry.unit !== undefined) ? this.new_entry.unit : {'name': ''}), 'unit': ((this.new_entry.unit !== undefined) ? this.new_entry.unit : {'name': ''}),
'amount': parseFloat(this.new_entry.amount), 'amount': parseFloat(this.new_entry.amount),
'order': 0 'order': 0,
'checked': false
}) })
this.new_entry = { this.new_entry = {
@ -373,9 +414,12 @@
}, },
getRecipes: function () { getRecipes: function () {
let url = "{% url 'api:recipe-list' %}?limit=5" let url = "{% url 'api:recipe-list' %}?limit=5&internal=true"
if (this.recipe_query !== '') { if (this.recipe_query !== '') {
url += '&query=' + this.recipe_query; url += '&query=' + this.recipe_query;
} else {
this.recipes = []
return
} }
this.$http.get(url).then((response) => { this.$http.get(url).then((response) => {
@ -385,6 +429,9 @@
this.makeToast('{% trans 'Error' %}', '{% trans 'There was an error loading a resource!' %}' + err.bodyText, 'danger') this.makeToast('{% trans 'Error' %}', '{% trans 'There was an error loading a resource!' %}' + err.bodyText, 'danger')
}) })
}, },
getRecipeUrl: function (id) { //TODO generic function that can be reused else were
return '{% url 'view_recipe' 123456 %}'.replace('123456', id)
},
addRecipeToList: function (recipe) { addRecipeToList: function (recipe) {
console.log(this.shopping_list) console.log(this.shopping_list)

View File

@ -24,6 +24,7 @@ router.register(r'ingredient', api.IngredientViewSet)
router.register(r'meal-plan', api.MealPlanViewSet) router.register(r'meal-plan', api.MealPlanViewSet)
router.register(r'meal-type', api.MealTypeViewSet) router.register(r'meal-type', api.MealTypeViewSet)
router.register(r'shopping-list', api.ShoppingListViewSet) router.register(r'shopping-list', api.ShoppingListViewSet)
router.register(r'shopping-list-entry', api.ShoppingListEntryViewSet)
router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet) router.register(r'shopping-list-recipe', api.ShoppingListRecipeViewSet)
router.register(r'view-log', api.ViewLogViewSet) router.register(r'view-log', api.ViewLogViewSet)

View File

@ -28,11 +28,11 @@ from rest_framework.viewsets import ViewSetMixin
from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser, CustomIsGuest, CustomIsShare from cookbook.helper.permission_helper import group_required, CustomIsOwner, CustomIsAdmin, CustomIsUser, CustomIsGuest, CustomIsShare
from cookbook.helper.recipe_url_import import get_from_html from cookbook.helper.recipe_url_import import get_from_html
from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference, RecipeBook, Ingredient, Food, Step, Keyword, Unit, SyncLog, ShoppingListRecipe, ShoppingList from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference, RecipeBook, Ingredient, Food, Step, Keyword, Unit, SyncLog, ShoppingListRecipe, ShoppingList, ShoppingListEntry
from cookbook.provider.dropbox import Dropbox from cookbook.provider.dropbox import Dropbox
from cookbook.provider.nextcloud import Nextcloud from cookbook.provider.nextcloud import Nextcloud
from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \ from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer, RecipeBookSerializer, IngredientSerializer, FoodSerializer, StepSerializer, \
KeywordSerializer, RecipeImageSerializer, StorageSerializer, SyncSerializer, SyncLogSerializer, UnitSerializer, ShoppingListSerializer, ShoppingListRecipeSerializer KeywordSerializer, RecipeImageSerializer, StorageSerializer, SyncSerializer, SyncLogSerializer, UnitSerializer, ShoppingListSerializer, ShoppingListRecipeSerializer, ShoppingListEntrySerializer
class UserNameViewSet(viewsets.ReadOnlyModelViewSet): class UserNameViewSet(viewsets.ReadOnlyModelViewSet):
@ -203,6 +203,13 @@ class RecipeViewSet(viewsets.ModelViewSet, StandardFilterMixin):
serializer_class = RecipeSerializer serializer_class = RecipeSerializer
permission_classes = [CustomIsShare | CustomIsGuest] # TODO split read and write permission for meal plan guest permission_classes = [CustomIsShare | CustomIsGuest] # TODO split read and write permission for meal plan guest
def get_queryset(self):
internal = self.request.query_params.get('internal', None)
if internal:
self.queryset = self.queryset.filter(internal=True)
return super(RecipeViewSet, self).get_queryset()
# TODO write extensive tests for permissions # TODO write extensive tests for permissions
@decorators.action( @decorators.action(
@ -241,6 +248,14 @@ class ShoppingListRecipeViewSet(viewsets.ModelViewSet):
# TODO custom get qs # TODO custom get qs
class ShoppingListEntryViewSet(viewsets.ModelViewSet):
queryset = ShoppingListEntry.objects.all()
serializer_class = ShoppingListEntrySerializer
permission_classes = [CustomIsUser] # TODO add custom validation
# TODO custom get qs
class ShoppingListViewSet(viewsets.ModelViewSet): class ShoppingListViewSet(viewsets.ModelViewSet):
queryset = ShoppingList.objects.all() queryset = ShoppingList.objects.all()
serializer_class = ShoppingListSerializer serializer_class = ShoppingListSerializer