From 0693d31550b27f3e37e0ff6be58df01b65d8227c Mon Sep 17 00:00:00 2001 From: smilerz Date: Mon, 29 Nov 2021 13:13:01 -0600 Subject: [PATCH] WIP --- cookbook/helper/permission_helper.py | 3 +- cookbook/serializer.py | 4 +- cookbook/views/api.py | 1 - vue/src/apps/MealPlanView/MealPlanView.vue | 459 +++++++++++++-------- vue/src/apps/RecipeView/RecipeView.vue | 2 +- vue/src/components/RecipeCard.vue | 22 +- vue/src/components/RecipeContextMenu.vue | 2 +- 7 files changed, 292 insertions(+), 201 deletions(-) diff --git a/cookbook/helper/permission_helper.py b/cookbook/helper/permission_helper.py index b5230d0d..c0a357e7 100644 --- a/cookbook/helper/permission_helper.py +++ b/cookbook/helper/permission_helper.py @@ -79,8 +79,7 @@ def is_object_shared(user, obj): # share checks for relevant objects if not user.is_authenticated: return False - else: - return user in obj.get_shared() + return user in obj.get_shared() def share_link_valid(recipe, share): diff --git a/cookbook/serializer.py b/cookbook/serializer.py index bf89d48e..3fffdea7 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -62,7 +62,7 @@ class ExtendedRecipeMixin(serializers.ModelSerializer): # probably not a tree pass if recipes.count() != 0: - return recipes.order_by('?')[:1][0].image.url + return random.choice(recipes).image.url else: return None @@ -96,7 +96,7 @@ class CustomDecimalField(serializers.Field): class SpaceFilterSerializer(serializers.ListSerializer): def to_representation(self, data): - if (type(data) == QuerySet and data.query.is_sliced): + if (type(data) == QuerySet and data.query.is_sliced) or not self.context.get('request', None): # if query is sliced it came from api request not nested serializer return super().to_representation(data) if self.child.Meta.model == User: diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 129068b5..68e3cea9 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -675,7 +675,6 @@ class RecipeViewSet(viewsets.ModelViewSet): return Response(self.serializer_class(qs, many=True).data) -# TODO deprecate class ShoppingListRecipeViewSet(viewsets.ModelViewSet): queryset = ShoppingListRecipe.objects serializer_class = ShoppingListRecipeSerializer diff --git a/vue/src/apps/MealPlanView/MealPlanView.vue b/vue/src/apps/MealPlanView/MealPlanView.vue index d58b2159..a6fd2b12 100644 --- a/vue/src/apps/MealPlanView/MealPlanView.vue +++ b/vue/src/apps/MealPlanView/MealPlanView.vue @@ -84,12 +84,7 @@
{{ meal_type.icon }} {{ meal_type.name }}
@@ -132,7 +127,7 @@ openEntryEdit(contextData.originalItem.entry) " > - {{ $t("Edit") }} + {{ $t("Edit") }} - {{ $t("Move") }} + {{ $t("Move") }} - {{ $t("Move") }} + {{ $t("Move") }} - {{ $t("Clone") }} + {{ $t("Clone") }} - {{ $t("Add_to_Shopping") }} + {{ $t("Add_to_Shopping") }} - {{ $t("Delete") }} + {{ $t("Delete") }} @@ -210,61 +205,7 @@ - - {{ $t('Default') }} - - - - - - - - - - - - - - - - - @@ -315,7 +256,7 @@ import "bootstrap-vue/dist/bootstrap-vue.css" import ContextMenu from "@/components/ContextMenu/ContextMenu" import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem" import MealPlanCard from "@/components/MealPlanCard" -import MealPlanEditModal from "@/components/Modals/MealPlanEditModal" +import MealPlanEditModal from "@/components/MealPlanEditModal" import MealPlanCalenderHeader from "@/components/MealPlanCalenderHeader" import EmojiInput from "@/components/Modals/EmojiInput" @@ -458,124 +399,280 @@ export default { this.settings = Object.assign({}, this.settings, this.$cookies.get(SETTINGS_COOKIE_NAME)) } }) - } else { - this.createEntry(edit_entry) - } + this.$root.$on("change", this.updateEmoji) + this.$i18n.locale = window.CUSTOM_LOCALE }, - setShowDate(d) { - this.showDate = d; + watch: { + settings: { + handler() { + this.$cookies.set(SETTINGS_COOKIE_NAME, this.settings, "360d") + }, + deep: true, + }, }, - createEntryClick(data) { - this.entryEditing = this.options.entryEditing - this.entryEditing.date = moment(data).format('YYYY-MM-DD') - this.$bvModal.show(`edit-modal`) - }, - findEntry(id) { - return this.plan_entries.filter(entry => { - return entry.id === id - })[0] - }, - moveEntry(null_object, target_date, drag_event) { - this.plan_entries.forEach((entry) => { - if (entry.id === this.dragged_item.id) { - if (drag_event.ctrlKey) { - let new_entry = Object.assign({}, entry) - new_entry.date = target_date - this.createEntry(new_entry) - } else { - entry.date = target_date - this.saveEntry(entry) - } - } - }) - }, - moveEntryLeft(data) { - this.plan_entries.forEach((entry) => { - if (entry.id === data.id) { - entry.date = moment(entry.date).subtract(1, 'd') - this.saveEntry(entry) - } - }) - }, - moveEntryRight(data) { - this.plan_entries.forEach((entry) => { - if (entry.id === data.id) { - entry.date = moment(entry.date).add(1, 'd') - this.saveEntry(entry) - } - }) - }, - deleteEntry(data) { - this.plan_entries.forEach((entry, index, list) => { - if (entry.id === data.id) { - let apiClient = new ApiApiFactory() + methods: { + addToShopping(entry) { + if (entry.originalItem.entry.recipe !== null) { + this.shopping_list.push(entry.originalItem.entry) + makeToast(this.$t("Success"), this.$t("Added_To_Shopping_List"), "success") + } else { + makeToast(this.$t("Failure"), this.$t("Cannot_Add_Notes_To_Shopping"), "danger") + } + }, + saveShoppingList() { + let url = window.SHOPPING_URL + let first = true + for (let se of this.shopping_list) { + if (first) { + url += `?r=[${se.recipe.id},${se.servings}]` + first = false + } else { + url += `&r=[${se.recipe.id},${se.servings}]` + } + } + window.open(url) + }, + setStartingDay(days) { + if (this.settings.startingDayOfWeek + days < 0) { + this.settings.startingDayOfWeek = 6 + } else if (this.settings.startingDayOfWeek + days > 6) { + this.settings.startingDayOfWeek = 0 + } else { + this.settings.startingDayOfWeek = this.settings.startingDayOfWeek + days + } + }, + newMealType() { + let apiClient = new ApiApiFactory() - apiClient.destroyMealPlan(entry.id).then(e => { - list.splice(index, 1) - }).catch(error => { - StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) - }) - } - }) - }, - entryClick(data) { - let entry = this.findEntry(data.id) - this.openEntryEdit(entry) - }, - openContextMenu($event, value) { - this.$refs.menu.open($event, value) - }, - openEntryEdit(entry) { - this.$bvModal.show(`edit-modal`) - this.entryEditing = entry - this.entryEditing.date = moment(entry.date).format('YYYY-MM-DD') - if (this.entryEditing.recipe != null) { - this.entryEditing.title_placeholder = this.entryEditing.recipe.name - } - }, - periodChangedCallback(date) { - this.current_period = date - let apiClient = new ApiApiFactory() + apiClient + .createMealType({ name: this.$t("Meal_Type") }) + .then((e) => { + this.periodChangedCallback(this.current_period) + }) + .catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) + }) - apiClient.listMealPlans({ - query: { - from_date: moment(date.periodStart).format('YYYY-MM-DD'), - to_date: moment(date.periodEnd).format('YYYY-MM-DD') - } - }).then(result => { - this.plan_entries = result.data - }) - this.refreshMealTypes() + this.refreshMealTypes() + }, + sortMealTypes() { + this.meal_types.forEach(function (element, index) { + element.order = index + }) + let updated = 0 + this.meal_types.forEach((meal_type) => { + let apiClient = new ApiApiFactory() + + apiClient + .updateMealType(meal_type.id, meal_type) + .then((e) => { + if (updated === this.meal_types.length - 1) { + this.periodChangedCallback(this.current_period) + } else { + updated++ + } + }) + .catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) + }) + }) + }, + editOrSaveMealType(index) { + let meal_type = this.meal_types[index] + if (meal_type.editing) { + this.$set(this.meal_types[index], "editing", false) + let apiClient = new ApiApiFactory() + + apiClient + .updateMealType(this.meal_types[index].id, this.meal_types[index]) + .then((e) => { + this.periodChangedCallback(this.current_period) + StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE) + }) + .catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) + }) + } else { + this.$set(this.meal_types[index], "editing", true) + } + }, + deleteMealType(index) { + let apiClient = new ApiApiFactory() + + apiClient + .destroyMealType(this.meal_types[index].id) + .then((e) => { + this.periodChangedCallback(this.current_period) + StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE) + }) + .catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_DELETE) + }) + }, + updateEmoji: function (field, value) { + this.meal_types.forEach((meal_type) => { + if (meal_type.editing) { + meal_type.icon = value + } + }) + }, + editEntry(edit_entry) { + if (edit_entry.id !== -1) { + this.plan_entries.forEach((entry, index) => { + if (entry.id === edit_entry.id) { + this.$set(this.plan_entries, index, edit_entry) + this.saveEntry(this.plan_entries[index]) + } + }) + } else { + this.createEntry(edit_entry) + } + }, + setShowDate(d) { + this.showDate = d + }, + createEntryClick(data) { + this.entryEditing = this.options.entryEditing + this.entryEditing.date = moment(data).format("YYYY-MM-DD") + this.$bvModal.show(`edit-modal`) + }, + findEntry(id) { + return this.plan_entries.filter((entry) => { + return entry.id === id + })[0] + }, + moveEntry(null_object, target_date, drag_event) { + this.plan_entries.forEach((entry) => { + if (entry.id === this.dragged_item.id) { + if (drag_event.ctrlKey) { + let new_entry = Object.assign({}, entry) + new_entry.date = target_date + this.createEntry(new_entry) + } else { + entry.date = target_date + this.saveEntry(entry) + } + } + }) + }, + moveEntryLeft(data) { + this.plan_entries.forEach((entry) => { + if (entry.id === data.id) { + entry.date = moment(entry.date).subtract(1, "d") + this.saveEntry(entry) + } + }) + }, + moveEntryRight(data) { + this.plan_entries.forEach((entry) => { + if (entry.id === data.id) { + entry.date = moment(entry.date).add(1, "d") + this.saveEntry(entry) + } + }) + }, + deleteEntry(data) { + this.plan_entries.forEach((entry, index, list) => { + if (entry.id === data.id) { + let apiClient = new ApiApiFactory() + + apiClient + .destroyMealPlan(entry.id) + .then((e) => { + list.splice(index, 1) + }) + .catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) + }) + } + }) + }, + entryClick(data) { + let entry = this.findEntry(data.id) + this.openEntryEdit(entry) + }, + openContextMenu($event, value) { + this.$refs.menu.open($event, value) + }, + openEntryEdit(entry) { + this.$bvModal.show(`edit-modal`) + this.entryEditing = entry + this.entryEditing.date = moment(entry.date).format("YYYY-MM-DD") + if (this.entryEditing.recipe != null) { + this.entryEditing.title_placeholder = this.entryEditing.recipe.name + } + }, + periodChangedCallback(date) { + this.current_period = date + let apiClient = new ApiApiFactory() + + apiClient + .listMealPlans({ + query: { + from_date: moment(date.periodStart).format("YYYY-MM-DD"), + to_date: moment(date.periodEnd).format("YYYY-MM-DD"), + }, + }) + .then((result) => { + this.plan_entries = result.data + }) + this.refreshMealTypes() + }, + refreshMealTypes() { + let apiClient = new ApiApiFactory() + + apiClient.listMealTypes().then((result) => { + result.data.forEach((meal_type) => { + meal_type.editing = false + }) + this.meal_types = result.data + }) + }, + saveEntry(entry) { + entry.date = moment(entry.date).format("YYYY-MM-DD") + + let apiClient = new ApiApiFactory() + + apiClient.updateMealPlan(entry.id, entry).catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) + }) + }, + createEntry(entry) { + entry.date = moment(entry.date).format("YYYY-MM-DD") + + let apiClient = new ApiApiFactory() + + apiClient + .createMealPlan(entry) + .catch((error) => { + StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) + }) + .then((entry_result) => { + this.plan_entries.push(entry_result.data) + }) + }, + buildItem(plan_entry) { + //dirty hack to order items within a day + let date = moment(plan_entry.date).add(plan_entry.meal_type.order, "m") + return { + id: plan_entry.id, + startDate: date, + endDate: date, + entry: plan_entry, + } + }, }, - refreshMealTypes() { - let apiClient = new ApiApiFactory() - - apiClient.listMealTypes().then(result => { - result.data.forEach((meal_type) => { - meal_type.editing = false - }) - this.meal_types = result.data - }) - }, - saveEntry(entry) { - entry.date = moment(entry.date).format("YYYY-MM-DD") - - let apiClient = new ApiApiFactory() - - apiClient.updateMealPlan(entry.id, entry).catch(error => { - StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) - }) - }, - createEntry(entry) { - entry.date = moment(entry.date).format("YYYY-MM-DD") - - let apiClient = new ApiApiFactory() - - apiClient.createMealPlan(entry).catch(error => { - StandardToasts.makeStandardToast(StandardToasts.FAIL_UPDATE) - }).then((entry_result) => { - this.plan_entries.push(entry_result.data) - }) + directives: { + hover: { + inserted: function (el) { + el.addEventListener("mouseenter", () => { + el.classList.add("shadow") + }) + el.addEventListener("mouseleave", () => { + el.classList.remove("shadow") + }) + }, + }, }, } diff --git a/vue/src/apps/RecipeView/RecipeView.vue b/vue/src/apps/RecipeView/RecipeView.vue index cb5d2c69..0425e65b 100644 --- a/vue/src/apps/RecipeView/RecipeView.vue +++ b/vue/src/apps/RecipeView/RecipeView.vue @@ -140,7 +140,7 @@ import "bootstrap-vue/dist/bootstrap-vue.css" import { apiLoadRecipe } from "@/utils/api" import StepComponent from "@/components/StepComponent" -import RecipeContextMenu from "@/components/ContextMenu/RecipeContextMenu" +import RecipeContextMenu from "@/components/RecipeContextMenu" import { ResolveUrlMixin, ToastMixin } from "@/utils/utils" import PdfViewer from "@/components/PdfViewer" diff --git a/vue/src/components/RecipeCard.vue b/vue/src/components/RecipeCard.vue index d504e828..a871c25c 100755 --- a/vue/src/components/RecipeCard.vue +++ b/vue/src/components/RecipeCard.vue @@ -8,12 +8,8 @@
- {{ recipe.working_time }} {{ $t("min") }} - - {{ recipe.waiting_time }} {{ $t("min") }} - + {{ recipe.working_time }} {{ $t("min") }} + {{ recipe.waiting_time }} {{ $t("min") }}
@@ -25,7 +21,7 @@ - +