mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
fade-enter-active
This commit is contained in:
@@ -20,7 +20,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-md-12">
|
<div class="col col-md-12">
|
||||||
<!-- TODO add spinner -->
|
<!-- TODO add spinner -->
|
||||||
<div role="tablist" v-if="items.length > 0">
|
<div role="tablist" v-if="items && items.length > 0">
|
||||||
<!-- WARNING: all data in the table should be considered read-only, don't change any data through table bindings -->
|
<!-- WARNING: all data in the table should be considered read-only, don't change any data through table bindings -->
|
||||||
<div v-for="(done, x) in Sections" :key="x">
|
<div v-for="(done, x) in Sections" :key="x">
|
||||||
<div v-if="x == 'true'">
|
<div v-if="x == 'true'">
|
||||||
@@ -52,80 +52,6 @@
|
|||||||
@open-context-menu="openContextMenu"
|
@open-context-menu="openContextMenu"
|
||||||
@toggle-checkbox="toggleChecked"
|
@toggle-checkbox="toggleChecked"
|
||||||
></ShoppingLineItem>
|
></ShoppingLineItem>
|
||||||
<!-- <div style="position: static;" class=" btn-group">
|
|
||||||
<div class="dropdown b-dropdown position-static">
|
|
||||||
<button
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="false"
|
|
||||||
type="button"
|
|
||||||
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-1 dropdown-toggle-no-caret"
|
|
||||||
@click.stop="openContextMenu($event, entries[1])"
|
|
||||||
>
|
|
||||||
<i class="fas fa-ellipsis-v fa-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<b-button
|
|
||||||
class="btn far text-body text-decoration-none"
|
|
||||||
variant="link"
|
|
||||||
@click="checkboxChanged(entries.item)"
|
|
||||||
:class="formatChecked ? 'fa-square' : 'fa-check-square'"
|
|
||||||
/>
|
|
||||||
{{ entries[0] }} {{ entries[1] }}
|
|
||||||
|
|
||||||
</div> -->
|
|
||||||
<!-- <b-table ref="table" small :items="Object.entries(s)" :fields="Fields" responsive="sm" class="w-100">
|
|
||||||
<template #cell(checked)="row">
|
|
||||||
<div style="position: static;" class=" btn-group">
|
|
||||||
<div class="dropdown b-dropdown position-static">
|
|
||||||
<button
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="false"
|
|
||||||
type="button"
|
|
||||||
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-1 dropdown-toggle-no-caret"
|
|
||||||
@click.stop="openContextMenu($event, row)"
|
|
||||||
>
|
|
||||||
<i class="fas fa-ellipsis-v fa-lg"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<b-button
|
|
||||||
class="btn far text-body text-decoration-none"
|
|
||||||
variant="link"
|
|
||||||
@click="checkboxChanged(data.item)"
|
|
||||||
:class="row.item.checked ? 'fa-check-square' : 'fa-square'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #cell(amount)="row">
|
|
||||||
{{ formatAmount(row.item) }}
|
|
||||||
</template>
|
|
||||||
<template #cell(food)="row">
|
|
||||||
{{ formatFood(row.item) }}
|
|
||||||
</template>
|
|
||||||
<template #cell(recipe)="row">
|
|
||||||
{{ formatRecipe(row.item) }}
|
|
||||||
</template>
|
|
||||||
<template #cell(unit)="row">
|
|
||||||
{{ formatUnit(row.item) }}
|
|
||||||
</template>
|
|
||||||
<template #cell(category)="row">
|
|
||||||
{{ formatCategory(row.item.food.supermarket_category) }}
|
|
||||||
</template>
|
|
||||||
<template #cell(details)="row">
|
|
||||||
<b-button size="sm" @click="row.toggleDetails" class="mr-2" variant="link">
|
|
||||||
<div class="text-nowrap">{{ row.detailsShowing ? "Hide" : "Show" }} Details</div>
|
|
||||||
</b-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #row-details="row">
|
|
||||||
notes {{ formatNotes(row.item) }} <br />
|
|
||||||
by {{ row.item.created_by.username }}<br />
|
|
||||||
at {{ formatDate(row.item.created_at) }}<br />
|
|
||||||
<div v-if="row.item.checked">completed {{ formatDate(row.item.completed_at) }}</div>
|
|
||||||
</template>
|
|
||||||
</b-table> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,7 +60,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</b-tab>
|
</b-tab>
|
||||||
<b-tab :title="$t('Settings')"> These are the settings</b-tab>
|
<b-tab :title="$t('Settings')">
|
||||||
|
These are the settings <br />-sort supermarket categories<br />
|
||||||
|
-add supermarket categories<br />
|
||||||
|
- add supermarkets autosync time<br />
|
||||||
|
autosync on/off<br />
|
||||||
|
always restrict supermarket to categories?<br />
|
||||||
|
when restricted or filterd - give visual indication<br />
|
||||||
|
how long to defer shopping - default tomorrow
|
||||||
|
</b-tab>
|
||||||
</b-tabs>
|
</b-tabs>
|
||||||
<b-popover target="id_filters_button" triggers="click" placement="bottomleft" :title="$t('Filters')">
|
<b-popover target="id_filters_button" triggers="click" placement="bottomleft" :title="$t('Filters')">
|
||||||
<div>
|
<div>
|
||||||
@@ -159,25 +93,54 @@
|
|||||||
</b-popover>
|
</b-popover>
|
||||||
<ContextMenu ref="menu">
|
<ContextMenu ref="menu">
|
||||||
<template #menu="{ contextData }">
|
<template #menu="{ contextData }">
|
||||||
<ContextMenuItem>
|
<ContextMenuItem
|
||||||
<b-form-group label-cols="6" content-cols="6" class="text-nowrap m-0 mr-2">
|
@click="
|
||||||
|
moveEntry($event, contextData)
|
||||||
|
$refs.menu.close()
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<b-form-group label-cols="10" content-cols="2" class="text-nowrap m-0 mr-2">
|
||||||
<template #label>
|
<template #label>
|
||||||
<a class="dropdown-item p-2" href="#"><i class="fas fa-cubes"></i> {{ $t("MoveCategory") }}</a>
|
<a class="dropdown-item p-2" href="#"><i class="fas fa-cubes"></i> {{ $t("MoveCategory", { category: categoryName(shopcat) }) }}</a>
|
||||||
</template>
|
</template>
|
||||||
<b-form-select
|
<div @click.prevent.stop @mouseup.prevent.stop>
|
||||||
class="mt-2"
|
<b-form-select class="mt-2 border-0" :options="shopping_categories" text-field="name" value-field="id" v-model="shopcat"></b-form-select>
|
||||||
:options="shopping_categories"
|
</div>
|
||||||
text-field="name"
|
|
||||||
value-field="id"
|
|
||||||
v-model="shopcat"
|
|
||||||
@change="
|
|
||||||
$refs.menu.close()
|
|
||||||
moveEntry($event, contextData)
|
|
||||||
"
|
|
||||||
></b-form-select>
|
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
|
|
||||||
|
<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)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<b-form-group label-cols="10" content-cols="2" class="text-nowrap m-0 mr-2">
|
||||||
|
<template #label>
|
||||||
|
<a class="dropdown-item p-2" href="#"><i class="far fa-hourglass"></i> {{ $t("DelayFor", { hours: delay }) }}</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<b-form-input class="mt-2" min="0" type="number" v-model="delay"></b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
</ContextMenuItem>
|
||||||
|
|
||||||
|
<ContextMenuItem
|
||||||
|
@click="
|
||||||
|
$refs.menu.close()
|
||||||
|
ignoreThis(contextData)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<a class="dropdown-item p-2" href="#"><i class="fas fa-ban"></i> {{ $t("IgnoreThis", { food: foodName(contextData) }) }}</a>
|
||||||
|
</ContextMenuItem>
|
||||||
|
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
@click="
|
@click="
|
||||||
$refs.menu.close()
|
$refs.menu.close()
|
||||||
@@ -200,9 +163,9 @@ import ContextMenu from "@/components/ContextMenu/ContextMenu"
|
|||||||
import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem"
|
import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem"
|
||||||
import ShoppingLineItem from "@/components/ShoppingLineItem"
|
import ShoppingLineItem from "@/components/ShoppingLineItem"
|
||||||
|
|
||||||
import { ApiMixin } from "@/utils/utils"
|
import { ApiMixin, getUserPreference } from "@/utils/utils"
|
||||||
import { ApiApiFactory } from "@/utils/openapi/api"
|
import { ApiApiFactory } from "@/utils/openapi/api"
|
||||||
import { StandardToasts } from "@/utils/utils"
|
import { StandardToasts, makeToast } from "@/utils/utils"
|
||||||
|
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
@@ -225,6 +188,7 @@ export default {
|
|||||||
show_undefined_categories: true,
|
show_undefined_categories: true,
|
||||||
supermarket_categories_only: false,
|
supermarket_categories_only: false,
|
||||||
shopcat: null,
|
shopcat: null,
|
||||||
|
delay: 0, // user default
|
||||||
show_modal: false,
|
show_modal: false,
|
||||||
fields: ["checked", "amount", "category", "unit", "food", "recipe", "details"],
|
fields: ["checked", "amount", "category", "unit", "food", "recipe", "details"],
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -293,6 +257,7 @@ export default {
|
|||||||
this.getItems()
|
this.getItems()
|
||||||
this.getSupermarkets()
|
this.getSupermarkets()
|
||||||
this.getShoppingCategories()
|
this.getShoppingCategories()
|
||||||
|
this.hours = getUserPreference("shopping_delay") || 1
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// this.genericAPI inherited from ApiMixin
|
// this.genericAPI inherited from ApiMixin
|
||||||
@@ -402,7 +367,8 @@ export default {
|
|||||||
// }
|
// }
|
||||||
// return Intl.DateTimeFormat(window.navigator.language, { dateStyle: "short", timeStyle: "short" }).format(Date.parse(datetime))
|
// return Intl.DateTimeFormat(window.navigator.language, { dateStyle: "short", timeStyle: "short" }).format(Date.parse(datetime))
|
||||||
// },
|
// },
|
||||||
toggleChecked: function(item) {
|
toggleChecked: function(item, refresh = false) {
|
||||||
|
// when checking a sub item don't refresh the screen until all entries complete but change class to cross out
|
||||||
item.checked = !item.checked
|
item.checked = !item.checked
|
||||||
if (item.checked) {
|
if (item.checked) {
|
||||||
item.completed_at = new Date().toISOString()
|
item.completed_at = new Date().toISOString()
|
||||||
@@ -418,16 +384,21 @@ export default {
|
|||||||
this.$refs.menu.open(e, value)
|
this.$refs.menu.open(e, value)
|
||||||
},
|
},
|
||||||
moveEntry: function(e, item) {
|
moveEntry: function(e, item) {
|
||||||
|
if (!e) {
|
||||||
|
makeToast(this.$t("Warning"), this.$t("NoCategory"), "warning")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO update API to warn that category is inherited
|
// TODO update API to warn that category is inherited
|
||||||
let food = {
|
let food = {
|
||||||
id: item.food.id,
|
id: item?.[0]?.food?.id ?? item?.food?.id,
|
||||||
supermarket_category: this.shopping_categories.filter((x) => x.id === e)[0],
|
supermarket_category: this.shopping_categories.filter((x) => x?.id === e)?.[0],
|
||||||
}
|
}
|
||||||
console.log("food", food, "event", e, "item", item)
|
console.log("food", food, "event", e, "item", item)
|
||||||
|
|
||||||
this.genericAPI(this.Models.FOOD, this.Actions.UPDATE, food)
|
this.genericAPI(this.Models.FOOD, this.Actions.UPDATE, food)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE)
|
StandardToasts.makeStandardToast(StandardToasts.SUCCESS_UPDATE)
|
||||||
|
// TODO this needs to change order of saved item to match category or category sort needs to be local instead of based on API
|
||||||
this.items
|
this.items
|
||||||
.filter((x) => x.food.id == food.id)
|
.filter((x) => x.food.id == food.id)
|
||||||
.forEach((y) => {
|
.forEach((y) => {
|
||||||
@@ -445,6 +416,26 @@ export default {
|
|||||||
let idx = this.items.indexOf((x) => x.id === newItem.id)
|
let idx = this.items.indexOf((x) => x.id === newItem.id)
|
||||||
Vue.set(this.items, idx, newItem)
|
Vue.set(this.items, idx, newItem)
|
||||||
},
|
},
|
||||||
|
foodName: function(value) {
|
||||||
|
console.log(value?.food?.name ?? value?.[0]?.food?.name ?? "")
|
||||||
|
return value?.food?.name ?? value?.[0]?.food?.name ?? ""
|
||||||
|
},
|
||||||
|
ignoreThis: function(item) {
|
||||||
|
return item
|
||||||
|
},
|
||||||
|
onHand: function(item) {
|
||||||
|
return item
|
||||||
|
},
|
||||||
|
delayThis: function(item) {
|
||||||
|
return item
|
||||||
|
},
|
||||||
|
categoryName: function(value) {
|
||||||
|
return this.shopping_categories.filter((x) => x.id == value)[0]?.name ?? ""
|
||||||
|
},
|
||||||
|
stop: function(e) {
|
||||||
|
e.stopPropagation() // default @click.stop not working
|
||||||
|
e.preventDefault() // default @click.stop not working
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -19,18 +19,14 @@
|
|||||||
</td>
|
</td>
|
||||||
<td @click="done">
|
<td @click="done">
|
||||||
<template v-if="ingredient.food !== null">
|
<template v-if="ingredient.food !== null">
|
||||||
<i
|
<!-- <i
|
||||||
v-if="show_shopping && !add_shopping_mode"
|
v-if="show_shopping && !add_shopping_mode"
|
||||||
class="far fa-edit fa-sm px-1"
|
class="far fa-edit fa-sm px-1"
|
||||||
@click="editFood()"
|
@click="editFood()"
|
||||||
></i>
|
></i> -->
|
||||||
<a
|
<a :href="resolveDjangoUrl('view_recipe', ingredient.food.recipe.id)" v-if="ingredient.food.recipe !== null" target="_blank" rel="noopener noreferrer">{{
|
||||||
:href="resolveDjangoUrl('view_recipe', ingredient.food.recipe.id)"
|
ingredient.food.name
|
||||||
v-if="ingredient.food.recipe !== null"
|
}}</a>
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>{{ ingredient.food.name }}</a
|
|
||||||
>
|
|
||||||
<span v-if="ingredient.food.recipe === null">{{ ingredient.food.name }}</span>
|
<span v-if="ingredient.food.recipe === null">{{ ingredient.food.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
</td>
|
</td>
|
||||||
@@ -44,9 +40,7 @@
|
|||||||
<!-- {{ ingredient.note }}-->
|
<!-- {{ ingredient.note }}-->
|
||||||
<!-- </span>-->
|
<!-- </span>-->
|
||||||
|
|
||||||
<div class="d-none d-print-block">
|
<div class="d-none d-print-block"><i class="far fa-comment-alt d-print-none"></i> {{ ingredient.note }}</div>
|
||||||
<i class="far fa-comment-alt d-print-none"></i> {{ ingredient.note }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td v-else-if="show_shopping" class="text-right text-nowrap">
|
<td v-else-if="show_shopping" class="text-right text-nowrap">
|
||||||
@@ -71,13 +65,7 @@
|
|||||||
<!-- or in shopping mode and food is ignored: Shopping Badge bypasses linking ingredient to Recipe which would get ignored -->
|
<!-- or in shopping mode and food is ignored: Shopping Badge bypasses linking ingredient to Recipe which would get ignored -->
|
||||||
<shopping-badge :item="ingredient.food" :override_ignore="true" class="px-1" />
|
<shopping-badge :item="ingredient.food" :override_ignore="true" class="px-1" />
|
||||||
<span class="px-2">
|
<span class="px-2">
|
||||||
<input
|
<input type="checkbox" class="align-middle" disabled v-b-popover.hover.click.blur :title="$t('IgnoredFood', { food: ingredient.food.name })" />
|
||||||
type="checkbox"
|
|
||||||
class="align-middle"
|
|
||||||
disabled
|
|
||||||
v-b-popover.hover.click.blur
|
|
||||||
:title="$t('IgnoredFood', { food: ingredient.food.name })"
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
<on-hand-badge :item="ingredient.food" />
|
<on-hand-badge :item="ingredient.food" />
|
||||||
</div>
|
</div>
|
||||||
@@ -158,10 +146,7 @@ export default {
|
|||||||
}
|
}
|
||||||
// if we are in add shopping mode start with all checks marked
|
// if we are in add shopping mode start with all checks marked
|
||||||
if (this.add_shopping_mode) {
|
if (this.add_shopping_mode) {
|
||||||
this.shop =
|
this.shop = !this.ingredient.food.on_hand && !this.ingredient.food.ignore_shopping && !this.ingredient.food.recipe
|
||||||
!this.ingredient.food.on_hand &&
|
|
||||||
!this.ingredient.food.ignore_shopping &&
|
|
||||||
!this.ingredient.food.recipe
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -177,9 +162,7 @@ export default {
|
|||||||
return this.$t("NotInShopping", { food: this.ingredient.food.name })
|
return this.$t("NotInShopping", { food: this.ingredient.food.name })
|
||||||
} else {
|
} else {
|
||||||
let list = this.shopping_list.filter((x) => x.food.id == this.ingredient.food.id)
|
let list = this.shopping_list.filter((x) => x.food.id == this.ingredient.food.id)
|
||||||
let category =
|
let category = this.$t("Category") + ": " + this.ingredient?.food?.supermarket_category?.name ?? this.$t("Undefined")
|
||||||
this.$t("Category") + ": " + this.ingredient?.food?.supermarket_category?.name ??
|
|
||||||
this.$t("Undefined")
|
|
||||||
let popover = []
|
let popover = []
|
||||||
|
|
||||||
list.forEach((x) => {
|
list.forEach((x) => {
|
||||||
@@ -200,9 +183,7 @@ export default {
|
|||||||
].join("")
|
].join("")
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
return (
|
return "<table class='table-small'><th colspan='4'>" + category + "</th>" + popover.join("") + "</table>"
|
||||||
"<table class='table-small'><th colspan='4'>" + category + "</th>" + popover.join("") + "</table>"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<!-- allow reordering or items -->
|
<!-- allow reordering or items -->
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="row">
|
<div class="row" :class="{ 'text-muted': formatChecked }">
|
||||||
<div class="col col-md-1">
|
<div class="col col-md-1">
|
||||||
<div style="position: static;" class=" btn-group">
|
<div style="position: static;" class=" btn-group">
|
||||||
<div class="dropdown b-dropdown position-static">
|
<div class="dropdown b-dropdown position-static">
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-1 dropdown-toggle-no-caret"
|
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-1 dropdown-toggle-no-caret"
|
||||||
@click.stop="$emit('open-context-menu', $event, entries[0])"
|
@click.stop="$emit('open-context-menu', $event, entries)"
|
||||||
>
|
>
|
||||||
<i class="fas fa-ellipsis-v fa-lg"></i>
|
<i class="fas fa-ellipsis-v fa-lg"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -25,45 +25,75 @@
|
|||||||
<div class="col col-md-1">{{ formatAmount }}</div>
|
<div class="col col-md-1">{{ formatAmount }}</div>
|
||||||
<div class="col col-md-1">{{ formatUnit }}</div>
|
<div class="col col-md-1">{{ formatUnit }}</div>
|
||||||
|
|
||||||
<div class="col col-md-4">
|
<div class="col col-md-6">
|
||||||
{{ formatFood }} <span class="text-muted">({{ formatHint }})</span>
|
{{ formatFood }} <span class="small text-muted">{{ formatHint }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-1">{{ formatNotes }}</div>
|
|
||||||
<div class="col col-md-1">
|
<div class="col col-md-1">
|
||||||
<b-button size="sm" @click="showDetails = !showDetails" class="mr-2" variant="link">
|
<b-button size="sm" @click="showDetails = !showDetails" class="mr-2" variant="link">
|
||||||
<div class="text-nowrap">{{ showDetails ? "Hide" : "Show" }} Details</div>
|
<div class="text-nowrap">{{ showDetails ? "Hide" : "Show" }} Details</div>
|
||||||
</b-button>
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" v-if="showDetails">
|
<div class="card no-body" v-if="showDetails">
|
||||||
<div class="offset-md-1">
|
<div v-for="(e, z) in entries" :key="z">
|
||||||
<div v-for="e in entries" :key="e.id">
|
<div class="row ml-2 small" v-if="formatOneMealPlan(e)">
|
||||||
<div style="position: static;" class=" btn-group">
|
<div class="col-md-4 overflow-hidden text-nowrap">
|
||||||
<div class="dropdown b-dropdown position-static">
|
<button
|
||||||
<button
|
aria-haspopup="true"
|
||||||
aria-haspopup="true"
|
aria-expanded="false"
|
||||||
aria-expanded="false"
|
type="button"
|
||||||
type="button"
|
class="btn btn-link stn-sm m-0 p-0"
|
||||||
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-1 dropdown-toggle-no-caret"
|
style="text-overflow: ellipsis;"
|
||||||
@click.stop="$emit('open-context-menu', $event, e)"
|
@click.stop="openRecipeCard($event, e)"
|
||||||
>
|
@mouseover="openRecipeCard($event, e)"
|
||||||
<i class="fas fa-ellipsis-v fa-lg"></i>
|
>
|
||||||
</button>
|
{{ formatOneRecipe(e) }}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-4 text-muted">{{ formatOneMealPlan(e) }}</div>
|
||||||
<b-button
|
<div class="col-md-4 text-muted">{{ formatOneCreatedBy(e) }}</div>
|
||||||
class="btn far text-body text-decoration-none"
|
|
||||||
variant="link"
|
|
||||||
@click="checkboxChanged()"
|
|
||||||
:class="formatChecked ? 'fa-check-square' : 'fa-square'"
|
|
||||||
/>
|
|
||||||
{{ e.amount }} - {{ e.unit }}- {{ e.recipe }}- {{ e.mealplan }}- {{ e.note }}- {{ e.unit }}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row ml-2 light">
|
||||||
|
<div class="col-sm-1 text-nowrap">
|
||||||
|
<div style="position: static;" class=" btn-group ">
|
||||||
|
<div class="dropdown b-dropdown position-static">
|
||||||
|
<button
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false"
|
||||||
|
type="button"
|
||||||
|
class="btn dropdown-toggle btn-link text-decoration-none text-body pr-1 dropdown-toggle-no-caret"
|
||||||
|
@click.stop="$emit('open-context-menu', $event, e)"
|
||||||
|
>
|
||||||
|
<i class="fas fa-ellipsis-v fa-lg"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<b-button
|
||||||
|
class="btn far text-body text-decoration-none"
|
||||||
|
variant="link"
|
||||||
|
@click="checkboxChanged(e)"
|
||||||
|
:class="formatOneChecked(e) ? 'fa-check-square' : 'fa-square'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-1">{{ formatOneAmount(e) }}</div>
|
||||||
|
<div class="col-sm-2">{{ formatOneUnit(e) }}</div>
|
||||||
|
<div class="col-sm-3">{{ formatOneFood(e) }}</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="small" v-for="(n, i) in formatOneNote(e)" :key="i">{{ n }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="w-75" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr class="m-1" />
|
<hr class="m-1" />
|
||||||
</div>
|
</div>
|
||||||
|
<ContextMenu ref="recipe_card" triggers="click, hover" :title="$t('Filters')" style="max-width:300">
|
||||||
|
<template #menu="{ contextData }">
|
||||||
|
<ContextMenuItem><RecipeCard :recipe="contextData" :detail="false" v-if="recipe"></RecipeCard></ContextMenuItem
|
||||||
|
></template>
|
||||||
|
</ContextMenu>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -71,6 +101,10 @@
|
|||||||
import Vue from "vue"
|
import Vue from "vue"
|
||||||
import { BootstrapVue } from "bootstrap-vue"
|
import { BootstrapVue } from "bootstrap-vue"
|
||||||
import "bootstrap-vue/dist/bootstrap-vue.css"
|
import "bootstrap-vue/dist/bootstrap-vue.css"
|
||||||
|
import ContextMenu from "@/components/ContextMenu/ContextMenu"
|
||||||
|
import ContextMenuItem from "@/components/ContextMenu/ContextMenuItem"
|
||||||
|
import { ApiMixin } from "@/utils/utils"
|
||||||
|
import RecipeCard from "./RecipeCard.vue"
|
||||||
|
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
@@ -78,8 +112,8 @@ export default {
|
|||||||
// TODO ApiGenerator doesn't capture and share error information - would be nice to share error details when available
|
// TODO ApiGenerator doesn't capture and share error information - would be nice to share error details when available
|
||||||
// or i'm capturing it incorrectly
|
// or i'm capturing it incorrectly
|
||||||
name: "ShoppingLineItem",
|
name: "ShoppingLineItem",
|
||||||
mixins: [],
|
mixins: [ApiMixin],
|
||||||
components: {},
|
components: { RecipeCard, ContextMenu, ContextMenuItem },
|
||||||
props: {
|
props: {
|
||||||
entries: {
|
entries: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -89,14 +123,15 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showDetails: false,
|
showDetails: false,
|
||||||
|
recipe: undefined,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
formatAmount: function() {
|
formatAmount: function() {
|
||||||
return this.entries[0].amount
|
return this.formatOneAmount(this.entries[0])
|
||||||
},
|
},
|
||||||
formatCategory: function() {
|
formatCategory: function() {
|
||||||
return this.entries[0]?.food?.supermarket_category?.name ?? this.$t("Undefined")
|
return this.formatOneCategory(this.entries[0]) || this.$t("Undefined")
|
||||||
},
|
},
|
||||||
formatChecked: function() {
|
formatChecked: function() {
|
||||||
return false
|
return false
|
||||||
@@ -109,20 +144,24 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatFood: function() {
|
formatFood: function() {
|
||||||
return this.entries[0]?.food?.name ?? this.$t("Undefined")
|
return this.formatOneFood(this.entries[0])
|
||||||
},
|
},
|
||||||
formatUnit: function() {
|
formatUnit: function() {
|
||||||
return this.entries[0]?.unit?.name ?? this.$t("Undefined")
|
return this.formatOneUnit(this.entries[0])
|
||||||
},
|
},
|
||||||
formatRecipe: function() {
|
formatRecipe: function() {
|
||||||
if (this.entries.length == 1) {
|
if (this.entries?.length == 1) {
|
||||||
return this.entries[0]?.recipe_mealplan?.name ?? this.$t("Undefined")
|
return this.formatOneMealPlan(this.entries[0]) || ""
|
||||||
} else {
|
} else {
|
||||||
return [this.entries[0]?.recipe_mealplan?.name ?? this.$t("Undefined"), this.$t("CountMore", { count: this.entries.length - 1 })].join(" ")
|
let mealplan_name = this.entries.filter((x) => x?.recipe_mealplan?.name)
|
||||||
|
return [this.formatOneMealPlan(mealplan_name?.[0]), this.$t("CountMore", { count: this.entries?.length - 1 })].join(" ")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatNotes: function() {
|
formatNotes: function() {
|
||||||
return [this.entries[0]?.recipe_mealplan?.mealplan_note, this.entries?.ingredient_note].filter(String).join("\n")
|
if (this.entries?.length == 1) {
|
||||||
|
return this.formatOneNote(this.entries[0]) || ""
|
||||||
|
}
|
||||||
|
return ""
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
@@ -146,10 +185,57 @@ export default {
|
|||||||
// this.saveThis(item, false)
|
// this.saveThis(item, false)
|
||||||
// this.$refs.table.refresh()
|
// this.$refs.table.refresh()
|
||||||
},
|
},
|
||||||
|
formatOneAmount: function(item) {
|
||||||
|
return item?.amount ?? 1
|
||||||
|
},
|
||||||
|
formatOneUnit: function(item) {
|
||||||
|
return item?.unit?.name ?? ""
|
||||||
|
},
|
||||||
|
formatOneCategory: function(item) {
|
||||||
|
return item?.food?.supermarket_category?.name
|
||||||
|
},
|
||||||
|
formatOneFood: function(item) {
|
||||||
|
return item.food.name
|
||||||
|
},
|
||||||
|
formatOneChecked: function(item) {
|
||||||
|
return item.checked
|
||||||
|
},
|
||||||
|
formatOneMealPlan: function(item) {
|
||||||
|
return item?.recipe_mealplan?.name
|
||||||
|
},
|
||||||
|
formatOneRecipe: function(item) {
|
||||||
|
return item?.recipe_mealplan?.recipe_name
|
||||||
|
},
|
||||||
|
formatOneNote: function(item) {
|
||||||
|
if (!item) {
|
||||||
|
item = this.entries[0]
|
||||||
|
}
|
||||||
|
return [item?.recipe_mealplan?.mealplan_note, item?.ingredient_note].filter(String)
|
||||||
|
},
|
||||||
|
formatOneCreatedBy: function(item) {
|
||||||
|
return [item?.created_by.username, "@", this.formatDate(item.created_at)].join(" ")
|
||||||
|
},
|
||||||
|
openRecipeCard: function(e, item) {
|
||||||
|
this.genericAPI(this.Models.RECIPE, this.Actions.FETCH, { id: item.recipe_mealplan.recipe }).then((result) => {
|
||||||
|
let recipe = result.data
|
||||||
|
recipe.steps = undefined
|
||||||
|
this.recipe = true
|
||||||
|
this.$refs.recipe_card.open(e, recipe)
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!--style src="vue-multiselect/dist/vue-multiselect.min.css"></style-->
|
<!--style src="vue-multiselect/dist/vue-multiselect.min.css"></style-->
|
||||||
|
|
||||||
<style></style>
|
<style>
|
||||||
|
/* table { border-collapse:collapse } /* Ensure no space between cells */
|
||||||
|
/* tr.strikeout td { position:relative } /* Setup a new coordinate system */
|
||||||
|
/* tr.strikeout td:before { /* Create a new element that */
|
||||||
|
/* content: " "; /* …has no text content */
|
||||||
|
/* position: absolute; /* …is absolutely positioned */
|
||||||
|
/* left: 0; top: 50%; width: 100%; /* …with the top across the middle */
|
||||||
|
/* border-bottom: 1px solid #000; /* …and with a border on the top */
|
||||||
|
/* } */
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user