recipe book context menu

This commit is contained in:
vabene1111
2021-07-29 16:32:15 +02:00
parent 45454eb27b
commit 8642298eda
14 changed files with 157 additions and 47 deletions

View File

@@ -1,21 +1,32 @@
<template>
<div>
<b-modal class="modal" :id="`id_modal_add_book_${modal_id}`" :title="$t('Add_to_Book')" :ok-title="$t('Add')"
:cancel-title="$t('Close')" @ok="addToBook()">
<b-modal class="modal" :id="`id_modal_add_book_${modal_id}`" :title="$t('Manage_Books')" :ok-title="$t('Add')"
:cancel-title="$t('Close')" @ok="addToBook()" @shown="loadBookEntries">
<table>
<tr v-for="be in this.recipe_book_list" v-bind:key="be.id">
<td>
<button class="btn btn-sm btn-danger" @click="removeFromBook(be)"><i class="fa fa-trash-alt"></i></button>
</td>
<td> {{ be.book_content.name }}</td>
</tr>
</table>
<multiselect
style="margin-top: 1vh"
v-model="selected_book"
:options="books"
:preserve-search="true"
:options="books_filtered"
:taggable="true"
@tag="createBook"
v-bind:tag-placeholder="$t('Create')"
:placeholder="$t('Select_Book')"
label="name"
track-by="id"
id="id_books"
:multiple="false"
@search-change="loadBook">
:loading="books_loading"
@search-change="loadBooks">
</multiselect>
</b-modal>
</div>
@@ -31,7 +42,8 @@ Vue.prototype.moment = moment
import Vue from "vue";
import {BootstrapVue} from "bootstrap-vue";
import {apiAddRecipeBookEntry, apiLoadCookBooks, apiLogCooking} from "@/utils/api";
import {ApiApiFactory} from "@/utils/openapi/api";
import {makeStandardToast, StandardToasts} from "@/utils/utils";
Vue.use(BootstrapVue)
@@ -47,21 +59,66 @@ export default {
data() {
return {
books: [],
books_loading: false,
recipe_book_list: [],
selected_book: null,
}
},
computed: {
books_filtered: function () {
let books_filtered = []
this.books.forEach(b => {
if (this.recipe_book_list.filter(e => e.book === b.id).length === 0) {
books_filtered.push(b)
}
})
return books_filtered
}
},
mounted() {
this.loadBook('')
},
methods: {
loadBook: function (query) {
apiLoadCookBooks(query).then(results => {
this.books = results
loadBooks: function (query) {
this.books_loading = true
let apiFactory = new ApiApiFactory()
apiFactory.listRecipeBooks({query: {query: query}}).then(results => {
this.books = results.data.filter(e => this.recipe_book_list.indexOf(e) === -1)
this.books_loading = false
})
},
addToBook() {
apiAddRecipeBookEntry({'recipe': this.recipe.id, 'book': this.selected_book.id})
createBook: function (name) {
let apiFactory = new ApiApiFactory()
apiFactory.createRecipeBook({name: name}).then(r => {
this.books.push(r.data)
this.selected_book = r.data
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
})
},
addToBook: function () {
let apiFactory = new ApiApiFactory()
apiFactory.createRecipeBookEntry({book: this.selected_book.id, recipe: this.recipe.id}).then(r => {
this.recipe_book_list.push(r.data)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
})
},
removeFromBook: function (book_entry) {
let apiFactory = new ApiApiFactory()
apiFactory.destroyRecipeBookEntry(book_entry.id).then(r => {
this.recipe_book_list = this.recipe_book_list.filter(e => e.id !== book_entry.id)
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_DELETE)
})
},
loadBookEntries: function () {
let apiFactory = new ApiApiFactory()
apiFactory.listRecipeBookEntrys({query: {recipe: this.recipe.id}}).then(r => {
this.recipe_book_list = r.data
this.loadBooks('')
})
}
}
}
</script>

View File

@@ -17,7 +17,7 @@
<a href="#">
<button class="dropdown-item" @click="$bvModal.show(`id_modal_add_book_${modal_id}`)">
<i class="fas fa-bookmark fa-fw"></i> {{ $t('Add_to_Book') }}
<i class="fas fa-bookmark fa-fw"></i> {{ $t('Manage_Books') }}
</button>
</a>

View File

@@ -13,17 +13,15 @@
"convert_internal": "Convert to internal recipe",
"show_only_internal": "Show only internal recipes",
"Log_Recipe_Cooking": "Log Recipe Cooking",
"External_Recipe_Image": "External Recipe Image",
"Add_to_Book": "Add to Book",
"Add_to_Shopping": "Add to Shopping",
"Add_to_Plan": "Add to Plan",
"Step_start_time": "Step start time",
"Sort_by_new": "Sort by new",
"Recipes_per_page": "Recipes per Page",
"Manage_Books": "Manage Books",
"Meal_Plan": "Meal Plan",
"Select_Book": "Select Book",
"Recipe_Image": "Recipe Image",
@@ -53,6 +51,7 @@
"Add": "Add",
"New": "New",
"Success": "Success",
"Failure": "Failure",
"Ingredients": "Ingredients",
"Supermarket": "Supermarket",
"Categories": "Categories",
@@ -80,5 +79,6 @@
"or": "or",
"and": "and",
"Information": "Information",
"Download": "Download"
"Download": "Download",
"Create": "Create"
}

View File

@@ -37,23 +37,6 @@ export function apiLogCooking(cook_log) {
})
}
export function apiLoadCookBooks(query) {
return axios.get(resolveDjangoUrl('api:recipebook-list') + '?query=' + query).then((response) => {
return response.data
}).catch((err) => {
//handleError(err, 'There was an error loading a resource!', 'danger')
})
}
export function apiAddRecipeBookEntry(entry) {
return axios.post(resolveDjangoUrl('api:recipebookentry-list',), entry).then((response) => {
makeToast('Saved', 'Recipe Book entry saved!', 'success')
}).catch((err) => {
handleError(err, 'There was an error creating a resource!', 'danger')
})
}
function handleError(error, message) {
if ('response' in error) {
console.log(error.response)

View File

@@ -2,6 +2,7 @@
* Utility functions to call bootstrap toasts
* */
import {BToast} from 'bootstrap-vue'
import i18n from "@/i18n";
export const ToastMixin = {
methods: {
@@ -21,6 +22,49 @@ export function makeToast(title, message, variant = null) {
})
}
export class StandardToasts {
static SUCCESS_CREATE = 'SUCCESS_CREATE'
static SUCCESS_FETCH = 'SUCCESS_FETCH'
static SUCCESS_UPDATE = 'SUCCESS_UPDATE'
static SUCCESS_DELETE = 'SUCCESS_DELETE'
static FAIL_CREATE = 'FAIL_CREATE'
static FAIL_FETCH = 'FAIL_FETCH'
static FAIL_UPDATE = 'FAIL_UPDATE'
static FAIL_DELETE = 'FAIL_DELETE'
static makeStandardToast(toast) {
switch (toast) {
case StandardToasts.SUCCESS_CREATE:
makeToast(i18n.tc('Success'), i18n.tc('success_creating_resource'), 'success')
break;
case StandardToasts.SUCCESS_FETCH:
makeToast(i18n.tc('Success'), i18n.tc('success_fetching_resource'), 'success')
break;
case StandardToasts.SUCCESS_UPDATE:
makeToast(i18n.tc('Success'), i18n.tc('success_updating_resource'), 'success')
break;
case StandardToasts.SUCCESS_DELETE:
makeToast(i18n.tc('Success'), i18n.tc('success_deleting_resource'), 'success')
break;
case StandardToasts.FAIL_CREATE:
makeToast(i18n.tc('Failure'), i18n.tc('success_creating_resource'), 'danger')
break;
case StandardToasts.FAIL_FETCH:
makeToast(i18n.tc('Failure'), i18n.tc('err_fetching_resource'), 'danger')
break;
case StandardToasts.FAIL_UPDATE:
makeToast(i18n.tc('Failure'), i18n.tc('err_updating_resource'), 'danger')
break;
case StandardToasts.FAIL_DELETE:
makeToast(i18n.tc('Failure'), i18n.tc('err_deleting_resource'), 'danger')
break;
}
}
}
/*
* Utility functions to use djangos gettext
* */