add recipes to shopping list

This commit is contained in:
Chris Scoggins
2022-01-21 12:01:46 -06:00
parent c5b70b94c7
commit 7916635716
3 changed files with 1427 additions and 1363 deletions

View File

@@ -4,26 +4,20 @@
<div class="row float-top pl-0 pr-0">
<div class="col-auto no-gutter ml-auto">
<b-button variant="link" class="px-1 pt-0 pb-1 d-none d-md-inline-block">
<i class="btn fas fa-plus-circle fa-lg px-0" @click="entrymode = !entrymode"
:class="entrymode ? 'text-success' : 'text-primary'"/>
<i class="btn fas fa-plus-circle fa-lg px-0" @click="entrymode = !entrymode" :class="entrymode ? 'text-success' : 'text-primary'" />
</b-button>
<b-button variant="link" class="px-1 pt-0 pb-1 d-none d-md-inline-block">
<i class="fas fa-download fa-lg nav-link dropdown-toggle text-primary px-1" id="downloadShoppingLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></i>
<i class="fas fa-download fa-lg nav-link dropdown-toggle text-primary px-1" id="downloadShoppingLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></i>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="downloadShoppingLink">
<DownloadPDF dom="#shoppinglist" name="shopping.pdf" :label="$t('download_pdf')" icon="far fa-file-pdf" />
<DownloadCSV :items="csvData" :delim="settings.csv_delim" name="shopping.csv" :label="$t('download_csv')"
icon="fas fa-file-csv"/>
<CopyToClipboard :items="csvData" :settings="settings" :label="$t('copy_to_clipboard')"
icon="fas fa-clipboard-list"/>
<CopyToClipboard :items="csvData" :settings="settings" format="table" :label="$t('copy_markdown_table')"
icon="fab fa-markdown"/>
<DownloadCSV :items="csvData" :delim="settings.csv_delim" name="shopping.csv" :label="$t('download_csv')" icon="fas fa-file-csv" />
<CopyToClipboard :items="csvData" :settings="settings" :label="$t('copy_to_clipboard')" icon="fas fa-clipboard-list" />
<CopyToClipboard :items="csvData" :settings="settings" format="table" :label="$t('copy_markdown_table')" icon="fab fa-markdown" />
</div>
</b-button>
<b-button variant="link" id="id_filters_button" class="px-1 pt-0 pb-1">
<i class="btn fas fa-filter text-decoration-none fa-lg px-1"
:class="filterApplied ? 'text-danger' : 'text-primary'"/>
<i class="btn fas fa-filter text-decoration-none fa-lg px-1" :class="filterApplied ? 'text-danger' : 'text-primary'" />
</b-button>
</div>
</div>
@@ -43,23 +37,23 @@
<b-row class="justify-content-md-center align-items-center pl-1 pr-1" v-if="entrymode">
<b-col cols="12" md="3" v-if="!entry_mode_simple" class="d-none d-md-block mt-1">
<b-form-input size="lg" min="1" type="number" :description="$t('Amount')"
<b-form-input
size="lg"
min="1"
type="number"
:description="$t('Amount')"
v-model="new_item.amount"
style="font-size: 16px;border-radius: 5px !important;border: 1px solid #e8e8e8 !important;"></b-form-input>
style="font-size: 16px; border-radius: 5px !important; border: 1px solid #e8e8e8 !important"
></b-form-input>
</b-col>
<b-col cols="12" md="4" v-if="!entry_mode_simple" class="mt-1">
<lookup-input :class_list="'mb-0'" :form="formUnit" :model="Models.UNIT"
@change="new_item.unit = $event"
:show_label="false" :clear="clear"/>
<lookup-input :class_list="'mb-0'" :form="formUnit" :model="Models.UNIT" @change="new_item.unit = $event" :show_label="false" :clear="clear" />
</b-col>
<b-col cols="12" md="4" v-if="!entry_mode_simple" class="mt-1">
<lookup-input :class_list="'mb-0'" :form="formFood" :model="Models.FOOD"
@change="new_item.food = $event"
:show_label="false" :clear="clear"/>
<lookup-input :class_list="'mb-0'" :form="formFood" :model="Models.FOOD" @change="new_item.food = $event" :show_label="false" :clear="clear" />
</b-col>
<b-col cols="12" md="11" v-if="entry_mode_simple" class="mt-1">
<b-form-input size="lg" type="text" :placeholder="$t('QuickEntry')" v-model="new_item.ingredient"
@keyup.enter="addItem"></b-form-input>
<b-form-input size="lg" type="text" :placeholder="$t('QuickEntry')" v-model="new_item.ingredient" @keyup.enter="addItem"></b-form-input>
</b-col>
<b-col cols="12" md="1" class="d-none d-md-block mt-1">
<b-button variant="link" class="px-0">
@@ -69,9 +63,14 @@
<b-col cols="12" md="3" v-if="!entry_mode_simple" class="d-block d-md-none mt-1">
<b-row>
<b-col cols="9">
<b-form-input size="lg" min="1" type="number" :description="$t('Amount')"
<b-form-input
size="lg"
min="1"
type="number"
:description="$t('Amount')"
v-model="new_item.amount"
style="font-size: 16px;border-radius: 5px !important;border: 1px solid #e8e8e8 !important;"></b-form-input>
style="font-size: 16px; border-radius: 5px !important; border: 1px solid #e8e8e8 !important"
></b-form-input>
</b-col>
<b-col cols="3" class="flex-grow-1">
<b-button variant="success" class="p-0 pt-1 w-100 h-100">
@@ -93,20 +92,19 @@
<!-- shopping list table -->
<div v-if="items && items.length > 0">
<div v-for="(done, x) in Sections" :key="x">
<div v-if="x == 'true'"
class="bg-header w-100 text-center d-flex justify-content-center align-items-center">
<div v-if="x == 'true'" class="bg-header w-100 text-center d-flex justify-content-center align-items-center">
<span class="h4 d-flex mt-1 mb-1">{{ $t("Completed") }}</span>
</div>
<div v-for="(s, i) in done" :key="i">
<div class="dropdown b-dropdown position-static inline-block" data-html2canvas-ignore="true"
v-if="Object.entries(s).length > 0">
<div class="dropdown b-dropdown position-static inline-block" data-html2canvas-ignore="true" v-if="Object.entries(s).length > 0">
<button
aria-haspopup="true"
aria-expanded="false"
type="button"
class="btn dropdown-toggle btn-link text-decoration-none text-dark pr-2 dropdown-toggle-no-caret"
@click.stop="openContextMenu($event, s, true)">
@click.stop="openContextMenu($event, s, true)"
>
<i class="fas fa-ellipsis-v fa-lg"></i>
</button>
@@ -122,14 +120,18 @@
</b-button>
</div>
<div class="collapse" :id="'section-' + sectionID(x, i)" visible role="tabpanel"
:class="{ show: x == 'false' }">
<div class="collapse" :id="'section-' + sectionID(x, i)" visible role="tabpanel" :class="{ show: x == 'false' }">
<!-- passing an array of values to the table grouped by Food -->
<transition-group name="slide-fade">
<div v-for="(entries, x) in Object.entries(s)" :key="x">
<transition name="slide-fade" mode="out-in">
<ShoppingLineItem :entries="entries[1]" :groupby="group_by" :settings="settings"
@open-context-menu="openContextMenu" @update-checkbox="updateChecked"/>
<ShoppingLineItem
:entries="entries[1]"
:groupby="group_by"
:settings="settings"
@open-context-menu="openContextMenu"
@update-checkbox="updateChecked"
/>
</transition>
</div>
</transition-group>
@@ -145,6 +147,34 @@
<!-- recipe tab -->
<b-tab :title="$t('Recipes')">
<div class="container p-0">
<b-row class="justify-content-md-center align-items-center p-1">
<b-col cols="10">
<b-input-group>
<b-input-group-prepend is-text>
{{ $t("Servings") }}
</b-input-group-prepend>
<b-input-group-prepend is-text>
<input type="number" :min="1" v-model="add_recipe_servings" style="width: 3em" />
</b-input-group-prepend>
<!-- <b-input-group-prepend is-text>
<b>{{ $t("Recipe") }}</b>
</b-input-group-prepend> -->
<generic-multiselect
class="input-group-text m-0 p-0"
@change="new_recipe = $event.val"
:label="'name'"
:model="Models.RECIPE"
style="flex-grow: 1; flex-shrink: 1; flex-basis: 0"
v-bind:placeholder="$t('Recipe')"
:limit="20"
:multiple="false"
/>
<b-input-group-append>
<b-button variant="success" @click="addRecipeToShopping" :disabled="!new_recipe.id">{{ $t("Add_to_Shopping") }}</b-button>
</b-input-group-append>
</b-input-group>
</b-col>
</b-row>
<table class="table w-100">
<thead>
<tr>
@@ -158,12 +188,10 @@
<td>{{ r.recipe_mealplan.name }}</td>
<td>{{ r.recipe_mealplan.recipe_name }}</td>
<td class="block-inline">
<b-form-input min="1" type="number" :debounce="300" :value="r.recipe_mealplan.servings"
@input="updateServings($event, r.list_recipe)"></b-form-input>
<b-form-input min="1" type="number" :debounce="300" :value="r.recipe_mealplan.servings" @input="updateServings($event, r.list_recipe)"></b-form-input>
</td>
<td>
<i class="btn text-danger fas fa-trash fa-lg px-2 border-0" variant="link" :title="$t('Delete')"
@click="deleteRecipe($event, r.list_recipe)"/>
<i class="btn text-danger fas fa-trash fa-lg px-2 border-0" variant="link" :title="$t('Delete')" @click="deleteRecipe($event, r.list_recipe)" />
</td>
</tr>
</table>
@@ -176,7 +204,8 @@
<div class="col col-md-5">
<b-card no-body>
<template #header>
<h4 class="mb-0">{{ $t("Supermarkets") }}
<h4 class="mb-0">
{{ $t("Supermarkets") }}
<b-button
variant="link"
class="p-0 m-0 float-right"
@@ -190,8 +219,7 @@
})
"
>
<i class="btn fas fa-plus-circle fa-lg px-0"
:class="new_supermarket.entrymode ? 'text-success' : 'text-primary'"/>
<i class="btn fas fa-plus-circle fa-lg px-0" :class="new_supermarket.entrymode ? 'text-success' : 'text-primary'" />
</b-button>
</h4>
</template>
@@ -202,14 +230,12 @@
header-text-variant="white"
align="center"
v-if="new_supermarket.entrymode"
:header="new_supermarket.value ? new_supermarket.value : $t('SupermarketName')">
:header="new_supermarket.value ? new_supermarket.value : $t('SupermarketName')"
>
<b-input-group>
<b-form-input type="text" class="form-control-append" :placeholder="$t('SupermarketName')"
v-model="new_supermarket.value"/>
<b-form-input type="text" class="form-control-append" :placeholder="$t('SupermarketName')" v-model="new_supermarket.value" />
<b-input-group-append>
<b-button class="input-group-append" variant="success" @click="addSupermarket"><i
class="pr-2 pt-1 fas fa-save"></i> {{ $t("Create") }}
</b-button>
<b-button class="input-group-append" variant="success" @click="addSupermarket"><i class="pr-2 pt-1 fas fa-save"></i> {{ $t("Create") }} </b-button>
</b-input-group-append>
</b-input-group>
</b-card>
@@ -221,11 +247,17 @@
<div class="col-12">
<h5 class="mt-1 mb-1">
{{ s.name }}
<b-button variant="link"
<b-button
variant="link"
class="p-0 m-0 float-right"
@click="s.editmode = !s.editmode;new_category.entrymode = false;new_supermarket.entrymode = false;editSupermarket(s)">
<i class="btn fas fa-edit fa-lg px-0"
:class="s.editmode ? 'text-success' : 'text-primary'"/>
@click="
s.editmode = !s.editmode
new_category.entrymode = false
new_supermarket.entrymode = false
editSupermarket(s)
"
>
<i class="btn fas fa-edit fa-lg px-0" :class="s.editmode ? 'text-success' : 'text-primary'" />
</b-button>
<b-button variant="link" class="p-0 m-0 float-right" @click="deleteSupermarket(s)">
<i class="btn fas fa-trash fa-lg px-2 text-danger" />
@@ -235,8 +267,7 @@
</div>
</b-card-header>
<b-card-body class="m-0 p-0">
<generic-pill :item_list="s.category_to_supermarket" label="category::name"
color="info"></generic-pill>
<generic-pill :item_list="s.category_to_supermarket" label="category::name" color="info"></generic-pill>
</b-card-body>
</b-card>
</b-card-body>
@@ -245,7 +276,8 @@
<div class="col col-md-5">
<b-card>
<template #header>
<h4 class="mb-0">{{ $t("Shopping_Categories") }}
<h4 class="mb-0">
{{ $t("Shopping_Categories") }}
<b-button
variant="link"
class="p-0 m-0 float-right"
@@ -254,8 +286,7 @@
new_supermarket.entrymode = false
"
>
<i class="btn fas fa-plus-circle fa-lg px-0"
:class="new_category.entrymode ? 'text-success' : 'text-primary'"/>
<i class="btn fas fa-plus-circle fa-lg px-0" :class="new_category.entrymode ? 'text-success' : 'text-primary'" />
</b-button>
</h4>
</template>
@@ -269,22 +300,15 @@
:header="new_category.value ? new_category.value : $t('CategoryName')"
>
<b-input-group>
<b-form-input type="text" class="form-control-append" :placeholder="$t('CategoryName')"
v-model="new_category.value"/>
<b-form-input type="text" class="form-control-append" :placeholder="$t('CategoryName')" v-model="new_category.value" />
<b-input-group-append>
<b-button class="input-group-append" variant="success" @click="addCategory"><i
class="pr-2 pt-1 fas fa-save"></i> {{ $t("Create") }}
</b-button>
<b-button class="input-group-append" variant="success" @click="addCategory"><i class="pr-2 pt-1 fas fa-save"></i> {{ $t("Create") }} </b-button>
</b-input-group-append>
</b-input-group>
</b-card>
<b-card-sub-title v-if="new_supermarket.editmode" class="pt-0 pb-3">{{
$t("CategoryInstruction")
}}
</b-card-sub-title>
<b-card v-if="new_supermarket.editmode && supermarketCategory.length === 0"
class="m-0 p-0 font-weight-bold no-body" border-variant="success" v-bind:key="-1"/>
<b-card-sub-title v-if="new_supermarket.editmode" class="pt-0 pb-3">{{ $t("CategoryInstruction") }} </b-card-sub-title>
<b-card v-if="new_supermarket.editmode && supermarketCategory.length === 0" class="m-0 p-0 font-weight-bold no-body" border-variant="success" v-bind:key="-1" />
<draggable
class="list-group"
:list="supermarketCategory"
@@ -296,17 +320,19 @@
v-bind="{ animation: 200, disabled: !new_supermarket.editmode }"
>
<transition-group type="transition" :name="!drag ? 'flip-list' : null">
<b-card no-body v-hover
<b-card
no-body
v-hover
class="mt-1 list-group-item p-2"
:style="new_supermarket.editmode ? 'cursor:move' : ''"
v-for="c in supermarketCategory"
v-bind:key="c.id"
:border-variant="new_supermarket.editmode ? 'success' : ''">
:border-variant="new_supermarket.editmode ? 'success' : ''"
>
<b-card-header class="p-2 border-0">
<div class="row">
<div class="col-2" v-if="new_supermarket.editmode">
<button type="button" class="btn btn-lg shadow-none"><i
class="fas fa-arrows-alt-v"></i></button>
<button type="button" class="btn btn-lg shadow-none"><i class="fas fa-arrows-alt-v"></i></button>
</div>
<div :class="new_supermarket.editmode ? 'col-10' : 'col-12'">
<h5 class="mt-1 mb-1">
@@ -322,8 +348,7 @@
</transition-group>
</draggable>
<hr style="height: 2px; background-color: black" v-if="new_supermarket.editmode" />
<b-card v-if="new_supermarket.editmode && notSupermarketCategory.length === 0" v-bind:key="-2"
class="m-0 p-0 font-weight-bold no-body" border-variant="danger"/>
<b-card v-if="new_supermarket.editmode && notSupermarketCategory.length === 0" v-bind:key="-2" class="m-0 p-0 font-weight-bold no-body" border-variant="danger" />
<draggable
class="list-group"
:list="notSupermarketCategory"
@@ -335,16 +360,11 @@
v-bind="{ animation: 200 }"
>
<transition-group type="transition" :name="!drag ? 'flip-list' : null">
<b-card no-body v-hover
class="mt-1 list-group-item p-2"
style="cursor: move"
v-for="c in notSupermarketCategory" v-bind:key="c.id"
:border-variant="'danger'">
<b-card no-body v-hover class="mt-1 list-group-item p-2" style="cursor: move" v-for="c in notSupermarketCategory" v-bind:key="c.id" :border-variant="'danger'">
<b-card-header class="p-2 border-0">
<div class="row">
<div class="col-2" v-if="new_supermarket.editmode">
<button type="button" class="btn btn-lg shadow-none"><i
class="fas fa-arrows-alt-v"></i></button>
<button type="button" class="btn btn-lg shadow-none"><i class="fas fa-arrows-alt-v"></i></button>
</div>
<div :class="new_supermarket.editmode ? 'col-10' : 'col-12'">
<h5 class="mt-1 mb-1">
@@ -371,9 +391,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("mealplan_autoadd_shopping") }}</div>
<div class="col col-md-6 text-right">
<input type="checkbox" class="form-control settings-checkbox"
v-model="settings.mealplan_autoadd_shopping"
@change="saveSettings"/>
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.mealplan_autoadd_shopping" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -385,9 +403,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("mealplan_autoadd_shopping") }}</div>
<div class="col col-md-6 text-right">
<input type="checkbox" class="form-control settings-checkbox"
v-model="settings.mealplan_autoexclude_onhand"
@change="saveSettings"/>
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.mealplan_autoexclude_onhand" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -400,9 +416,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("mealplan_autoinclude_related") }}</div>
<div class="col col-md-6 text-right">
<input type="checkbox" class="form-control settings-checkbox"
v-model="settings.mealplan_autoinclude_related"
@change="saveSettings"/>
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.mealplan_autoinclude_related" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -437,8 +451,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("shopping_auto_sync") }}</div>
<div class="col col-md-6 text-right">
<input type="number" class="form-control" v-model="settings.shopping_auto_sync"
@change="saveSettings"/>
<input type="number" class="form-control" v-model="settings.shopping_auto_sync" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -451,8 +464,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("shopping_add_onhand") }}</div>
<div class="col col-md-6 text-right">
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.shopping_add_onhand"
@change="saveSettings"/>
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.shopping_add_onhand" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -465,8 +477,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("shopping_recent_days") }}</div>
<div class="col col-md-6 text-right">
<input type="number" class="form-control" v-model="settings.shopping_recent_days"
@change="saveSettings"/>
<input type="number" class="form-control" v-model="settings.shopping_recent_days" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -479,9 +490,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("filter_to_supermarket") }}</div>
<div class="col col-md-6 text-right">
<input type="checkbox" class="form-control settings-checkbox"
v-model="settings.filter_to_supermarket"
@change="saveSettings"/>
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.filter_to_supermarket" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -494,8 +503,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("default_delay") }}</div>
<div class="col col-md-6 text-right">
<input type="number" class="form-control" min="1" v-model="settings.default_delay"
@change="saveSettings"/>
<input type="number" class="form-control" min="1" v-model="settings.default_delay" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -534,9 +542,7 @@
<div class="row">
<div class="col col-md-6">{{ $t("left_handed") }}</div>
<div class="col col-md-6">
<input type="checkbox" class="form-control settings-checkbox"
v-model="settings.left_handed"
@change="saveSettings"/>
<input type="checkbox" class="form-control settings-checkbox" v-model="settings.left_handed" @change="saveSettings" />
</div>
</div>
<div class="row sm mb-3">
@@ -557,66 +563,82 @@
<b-form-select v-model="group_by" :options="group_by_choices" size="sm"></b-form-select>
</b-form-group>
<b-form-group v-bind:label="$t('Supermarket')" label-for="popover-input-2" label-cols="6" class="mb-1">
<b-form-select v-model="selected_supermarket" :options="supermarkets" text-field="name" value-field="id"
size="sm"></b-form-select>
<b-form-select v-model="selected_supermarket" :options="supermarkets" text-field="name" value-field="id" size="sm"></b-form-select>
</b-form-group>
<!-- TODO: shade filters red when they are actually filtering content -->
<b-form-group v-bind:label="$t('ShowDelayed')" label-for="popover-input-3" content-cols="1" class="mb-1">
<b-form-checkbox v-model="show_delay"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('ShowUncategorizedFood')" label-for="popover-input-4" content-cols="1"
class="mb-1" v-if="!selected_supermarket">
<b-form-group v-bind:label="$t('ShowUncategorizedFood')" label-for="popover-input-4" content-cols="1" class="mb-1" v-if="!selected_supermarket">
<b-form-checkbox v-model="show_undefined_categories"></b-form-checkbox>
</b-form-group>
<b-form-group v-bind:label="$t('SupermarketCategoriesOnly')" label-for="popover-input-5" content-cols="1"
class="mb-1" v-if="selected_supermarket">
<b-form-group v-bind:label="$t('SupermarketCategoriesOnly')" label-for="popover-input-5" content-cols="1" class="mb-1" v-if="selected_supermarket">
<b-form-checkbox v-model="supermarket_categories_only"></b-form-checkbox>
</b-form-group>
</div>
<div class="row" style="margin-top: 1vh; min-width: 300px">
<div class="col-12" style="text-align: right">
<b-button size="sm" variant="primary" class="mx-1" @click="resetFilters">{{ $t("Reset") }}</b-button>
<b-button size="sm" variant="secondary" class="mr-3" @click="$root.$emit('bv::hide::popover')">{{
$t("Close")
}}
</b-button>
<b-button size="sm" variant="secondary" class="mr-3" @click="$root.$emit('bv::hide::popover')">{{ $t("Close") }} </b-button>
</div>
</div>
</b-popover>
<ContextMenu ref="menu">
<template #menu="{ contextData }">
<ContextMenuItem>
<b-input-group>
<template #prepend>
<span class="dropdown-item p-2 text-decoration-none" style="user-select: none!important;"><i class="fas fa-cubes"></i> {{ $t("MoveCategory") }}</span>
<span class="dropdown-item p-2 text-decoration-none" style="user-select: none !important"><i class="fas fa-cubes"></i> {{ $t("MoveCategory") }}</span>
</template>
<b-form-select class="form-control mt-1 mr-1" :options="shopping_categories" text-field="name"
value-field="id" v-model="shopcat"
@change="moveEntry($event, contextData);$refs.menu.close()"></b-form-select>
<b-form-select
class="form-control mt-1 mr-1"
:options="shopping_categories"
text-field="name"
value-field="id"
v-model="shopcat"
@change="
moveEntry($event, contextData)
$refs.menu.close()
"
></b-form-select>
</b-input-group>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();onHand(contextData)">
<ContextMenuItem
@click="
$refs.menu.close()
onHand(contextData)
"
>
<a class="dropdown-item p-2" href="#"><i class="fas fa-clipboard-check"></i> {{ $t("OnHand") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();delayThis(contextData)">
<a class="dropdown-item p-2" href="#"><i class="fas fa-hourglass"></i> {{
$t("DelayFor", {hours: delay})
}}</a>
<ContextMenuItem
@click="
$refs.menu.close()
delayThis(contextData)
"
>
<a class="dropdown-item p-2" href="#"><i class="fas fa-hourglass"></i> {{ $t("DelayFor", { hours: delay }) }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();updateChecked({ entries: contextData, checked: true })">
<ContextMenuItem
@click="
$refs.menu.close()
updateChecked({ entries: contextData, checked: true })
"
>
<a class="dropdown-item p-2" href="#"><i class="fas fa-check-square"></i> {{ $t("mark_complete") }}</a>
</ContextMenuItem>
<ContextMenuItem @click="$refs.menu.close();deleteThis(contextData)">
<ContextMenuItem
@click="
$refs.menu.close()
deleteThis(contextData)
"
>
<a class="dropdown-item p-2 text-danger" href="#"><i class="fas fa-trash"></i> {{ $t("Delete") }}</a>
</ContextMenuItem>
</template>
</ContextMenu>
<transition name="slided-fade">
<div class="row fixed-bottom p-2 b-1 border-top text-center d-flex d-md-none"
style="background: rgba(255, 255, 255, 0.6)"
v-if="current_tab === 0">
<div class="row fixed-bottom p-2 b-1 border-top text-center d-flex d-md-none" style="background: rgba(255, 255, 255, 0.6)" v-if="current_tab === 0">
<div class="col-6">
<a class="btn btn-block btn-success shadow-none" @click="entrymode = !entrymode"
><i class="fas fa-cart-plus"></i>
@@ -625,21 +647,16 @@
</div>
<div class="col-6">
<b-dropdown id="dropdown-dropup" block dropup variant="primary" class="shadow-none">
<template #button-content>
<i class='fas fa-download'></i> {{ $t('Export') }}
</template>
<template #button-content> <i class="fas fa-download"></i> {{ $t("Export") }} </template>
<DownloadPDF dom="#shoppinglist" name="shopping.pdf" :label="$t('download_pdf')" icon="far fa-file-pdf" />
<DownloadCSV :items="csvData" :delim="settings.csv_delim" name="shopping.csv" :label="$t('download_csv')"
icon="fas fa-file-csv"/>
<CopyToClipboard :items="csvData" :settings="settings" :label="$t('copy_to_clipboard')"
icon="fas fa-clipboard-list"/>
<CopyToClipboard :items="csvData" :settings="settings" format="table" :label="$t('copy_markdown_table')"
icon="fab fa-markdown"/>
<DownloadCSV :items="csvData" :delim="settings.csv_delim" name="shopping.csv" :label="$t('download_csv')" icon="fas fa-file-csv" />
<CopyToClipboard :items="csvData" :settings="settings" :label="$t('copy_to_clipboard')" icon="fas fa-clipboard-list" />
<CopyToClipboard :items="csvData" :settings="settings" format="table" :label="$t('copy_markdown_table')" icon="fab fa-markdown" />
</b-dropdown>
</div>
</div>
</transition>
<shopping-modal v-if="new_recipe.id" :recipe="new_recipe" :servings="parseInt(add_recipe_servings)" :modal_id="new_recipe.id" @finish="finishShopping" />
</div>
</template>
@@ -658,6 +675,7 @@ import CopyToClipboard from "@/components/Buttons/CopyToClipboard"
import GenericMultiselect from "@/components/GenericMultiselect"
import GenericPill from "@/components/GenericPill"
import LookupInput from "@/components/Modals/LookupInput"
import ShoppingModal from "@/components/Modals/ShoppingModal"
import draggable from "vuedraggable"
import { ApiMixin, getUserPreference, StandardToasts, makeToast } from "@/utils/utils"
@@ -680,7 +698,8 @@ export default {
LookupInput,
DownloadPDF,
DownloadCSV,
CopyToClipboard
CopyToClipboard,
ShoppingModal,
},
data() {
@@ -710,7 +729,7 @@ export default {
csv_delim: ",",
csv_prefix: undefined,
shopping_add_onhand: true,
left_handed: false
left_handed: false,
},
new_supermarket: { entrymode: false, value: undefined, editmode: undefined },
new_category: { entrymode: false, value: undefined },
@@ -724,6 +743,10 @@ export default {
entrymode: false,
new_item: { amount: 1, unit: undefined, food: undefined, ingredient: undefined },
online: true,
new_recipe: {
id: undefined,
},
add_recipe_servings: 1,
}
},
computed: {
@@ -822,7 +845,8 @@ export default {
return (this.itemsDelayed && !this.show_delay) || !this.show_undefined_categories || (this.supermarket_categories_only && this.selected_supermarket)
},
Recipes() {
return [...new Map(this.items.filter((x) => x.list_recipe).map((item) => [item["list_recipe"], item])).values()]
// hiding recipes associated with shopping list items that are complete
return [...new Map(this.items.filter((x) => x.list_recipe && !x.checked).map((item) => [item["list_recipe"], item])).values()]
},
supermarketCategory() {
return this.new_supermarket.editmode ? this.new_supermarket.value.category_to_supermarket : this.shopping_categories
@@ -846,7 +870,13 @@ export default {
watch: {
selected_supermarket(newVal, oldVal) {
this.supermarket_categories_only = this.settings.filter_to_supermarket
localStorage.setItem('shopping_v2_selected_supermarket', JSON.stringify(this.selected_supermarket))
localStorage.setItem("shopping_v2_selected_supermarket", JSON.stringify(this.selected_supermarket))
},
new_recipe: {
handler() {
this.add_recipe_servings = this.new_recipe.servings
},
deep: true,
},
"settings.filter_to_supermarket": function (newVal, oldVal) {
this.supermarket_categories_only = this.settings.filter_to_supermarket
@@ -875,6 +905,9 @@ export default {
entry_mode_simple(newVal) {
this.$cookies.set(SETTINGS_COOKIE_NAME, newVal)
},
// "new_recipe.servings": function () {
// return
// },
},
mounted() {
this.getShoppingList()
@@ -891,7 +924,7 @@ export default {
this.$nextTick(function () {
if (this.$cookies.isKey(SETTINGS_COOKIE_NAME)) {
this.entry_mode_simple = this.$cookies.get(SETTINGS_COOKIE_NAME)
this.selected_supermarket = localStorage.getItem('shopping_v2_selected_supermarket') || undefined
this.selected_supermarket = localStorage.getItem("shopping_v2_selected_supermarket") || undefined
}
})
},
@@ -899,12 +932,11 @@ export default {
// this.genericAPI inherited from ApiMixin
addItem: function () {
if (this.entry_mode_simple) {
if (this.new_item.ingredient !== '' && this.new_item.ingredient !== undefined) {
if (this.new_item.ingredient !== "" && this.new_item.ingredient !== undefined) {
this.genericPostAPI("api_ingredient_from_string", { text: this.new_item.ingredient }).then((result) => {
let unit = null
if (result.data.unit !== '') {
unit = {'name': result.data.unit}
if (result.data.unit !== "") {
unit = { name: result.data.unit }
}
this.new_item = {
@@ -1136,8 +1168,7 @@ export default {
})
.then((entries) => {
entries.forEach((x) => {
api.destroyShoppingListEntry(x).then((result) => {
})
api.destroyShoppingListEntry(x).then((result) => {})
})
})
},
@@ -1351,7 +1382,14 @@ export default {
window.removeEventListener("online", this.updateOnlineStatus)
window.removeEventListener("offline", this.updateOnlineStatus)
},
}, directives: {
addRecipeToShopping() {
this.$bvModal.show(`shopping_${this.new_recipe.id}`)
},
finishShopping() {
this.getShoppingList()
},
},
directives: {
hover: {
inserted: function (el) {
el.addEventListener("mouseenter", () => {
@@ -1396,13 +1434,13 @@ export default {
background: #c8ebfb;
}
.slide-fade-enter-active, .slide-fade-leave-active {
.slide-fade-enter-active,
.slide-fade-leave-active {
transition: all 0.2s ease;
}
.slide-fade-enter, .slide-fade-leave-to
/* .slider-fade-leave-active below version 2.1.8 */
{
/* .slider-fade-leave-active below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
@@ -1424,7 +1462,6 @@ export default {
}
.settings-checkbox {
font-size: 0.3rem
font-size: 0.3rem;
}
</style>

View File

@@ -7,8 +7,7 @@
</div>
<div class="col col-md-6 text-right" v-if="header">
<h4>
<i v-if="show_shopping && ShoppingRecipes.length > 0" class="fas fa-trash text-danger px-2"
@click="saveShopping(true)"></i>
<i v-if="show_shopping && ShoppingRecipes.length > 0" class="fas fa-trash text-danger px-2" @click="saveShopping(true)"></i>
<i v-if="show_shopping" class="fas fa-save text-success px-2" @click="saveShopping()"></i>
<i class="fas fa-shopping-cart px-2" @click="getShopping()"></i>
</h4>
@@ -16,8 +15,7 @@
</div>
<div class="row text-right" v-if="ShoppingRecipes.length > 1">
<div class="col col-md-6 offset-md-6 text-right">
<b-form-select v-model="selected_shoppingrecipe" :options="ShoppingRecipes"
size="sm"></b-form-select>
<b-form-select v-model="selected_shoppingrecipe" :options="ShoppingRecipes" size="sm"></b-form-select>
</div>
</div>
<br v-if="header" />
@@ -26,7 +24,7 @@
<table class="table table-sm">
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
<template v-for="s in steps">
<tr v-bind:key="s.id" v-if="s.show_as_header && s.name !== ''">
<tr v-bind:key="s.id" v-if="s.show_as_header && s.name !== '' && !add_shopping_mode">
<td colspan="5">
<b>{{ s.name }}</b>
</td>
@@ -99,7 +97,7 @@ export default {
value: x?.list_recipe,
text: x?.recipe_mealplan?.name,
recipe: x?.recipe_mealplan?.recipe ?? 0,
servings: x?.recipe_mealplan?.servings
servings: x?.recipe_mealplan?.servings,
}
})
.filter((x) => x?.recipe == this.recipe)

View File

@@ -2,7 +2,7 @@
<div>
<b-modal :id="`shopping_${this.modal_id}`" hide-footer @show="loadRecipe">
<template v-slot:modal-title
><h4>{{ $t("Add_Servings_to_Shopping", { servings: servings }) }}</h4></template
><h4>{{ $t("Add_Servings_to_Shopping", { servings: recipe_servings }) }}</h4></template
>
<loading-spinner v-if="loading"></loading-spinner>
<div class="accordion" role="tablist" v-if="!loading">
@@ -15,7 +15,7 @@
:steps="steps"
:recipe="recipe.id"
:ingredient_factor="ingredient_factor"
:servings="servings"
:servings="recipe_servings"
:show_shopping="true"
:add_shopping_mode="true"
:header="false"
@@ -33,7 +33,7 @@
:steps="r.steps"
:recipe="r.recipe.id"
:ingredient_factor="ingredient_factor"
:servings="servings"
:servings="recipe_servings"
:show_shopping="true"
:add_shopping_mode="true"
:header="false"
@@ -45,12 +45,19 @@
<!-- eslint-disable vue/no-v-for-template-key-on-child -->
</b-card>
</div>
<div class="row mt-3 mb-3">
<div class="col-12 text-right">
<b-button class="mx-2" variant="secondary" @click="$bvModal.hide(`shopping_${modal_id}`)">{{ $t("Cancel") }} </b-button>
<b-button class="mx-2" variant="success" @click="saveShopping">{{ $t("Save") }} </b-button>
</div>
</div>
<b-input-group class="my-3">
<b-input-group-prepend is-text>
{{ $t("Servings") }}
</b-input-group-prepend>
<b-form-spinbutton min="1" v-model="recipe_servings" inline style="height: 3em"></b-form-spinbutton>
<b-input-group-append>
<b-button variant="secondary" @click="$bvModal.hide(`shopping_${modal_id}`)">{{ $t("Cancel") }} </b-button>
<b-button variant="success" @click="saveShopping">{{ $t("Save") }} </b-button>
</b-input-group-append>
</b-input-group>
</b-modal>
</div>
</template>
@@ -71,25 +78,37 @@ export default {
mixins: [],
props: {
recipe: { required: true, type: Object },
servings: { type: Number },
servings: { type: Number, default: undefined },
modal_id: { required: true, type: Number },
},
data() {
return {
loading: true,
steps: [],
recipe_servings: 0,
recipe_servings: undefined,
add_shopping: [],
related_recipes: [],
}
},
mounted() {},
mounted() {
this.recipe_servings = this.servings
},
computed: {
ingredient_factor: function () {
return this.servings / this.recipe.servings || this.recipe_servings
return this.recipe_servings / this.recipe.servings
},
},
watch: {
recipe: {
handler() {
this.loadRecipe()
},
deep: true,
},
servings: function (newVal) {
this.recipe_servings = parseInt(newVal)
},
},
watch: {},
methods: {
loadRecipe: function () {
this.add_shopping = []
@@ -109,7 +128,9 @@ export default {
.filter((x) => !x?.food?.food_onhand)
.map((x) => x.id),
]
if (!this.recipe_servings) {
this.recipe_servings = result.data?.servings
}
this.loading = false
})
.then(() => {
@@ -159,19 +180,27 @@ export default {
let shopping_recipe = {
id: this.recipe.id,
ingredients: this.add_shopping,
servings: this.servings,
servings: this.recipe_servings,
}
let apiClient = new ApiApiFactory()
apiClient
.shoppingRecipe(this.recipe.id, shopping_recipe)
.then((result) => {
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_CREATE)
this.$emit("finish")
})
.catch((err) => {
StandardToasts.makeStandardToast(StandardToasts.FAIL_CREATE)
})
this.$bvModal.hide(`shopping_${this.modal_id}`)
},
},
}
</script>
<style>
.b-form-spinbutton.form-control {
background-color: #e9ecef;
border: 1px solid #ced4da;
}
</style>