visual indicator meal plan in shopping
This commit is contained in:
parent
24b0643765
commit
2af7b64d4f
@ -610,10 +610,14 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
note_markdown = serializers.SerializerMethodField('get_note_markdown')
|
||||
servings = CustomDecimalField()
|
||||
shared = UserNameSerializer(many=True, required=False, allow_null=True)
|
||||
shopping = serializers.SerializerMethodField('in_shopping')
|
||||
|
||||
def get_note_markdown(self, obj):
|
||||
return markdown(obj.note)
|
||||
|
||||
def in_shopping(self, obj):
|
||||
return ShoppingListRecipe.objects.filter(mealplan=obj.id).exists()
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['created_by'] = self.context['request'].user
|
||||
mealplan = super().create(validated_data)
|
||||
@ -626,7 +630,7 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer):
|
||||
fields = (
|
||||
'id', 'title', 'recipe', 'servings', 'note', 'note_markdown',
|
||||
'date', 'meal_type', 'created_by', 'shared', 'recipe_name',
|
||||
'meal_type_name'
|
||||
'meal_type_name', 'shopping'
|
||||
)
|
||||
read_only_fields = ('created_by',)
|
||||
|
||||
|
@ -1,128 +1,132 @@
|
||||
<template>
|
||||
<div v-hover class="card cv-item meal-plan-card p-0" :key="value.id" :draggable="true"
|
||||
:style="`top:${top};max-height:${item_height}`"
|
||||
@dragstart="onDragItemStart(value, $event)"
|
||||
@click="onClickItem(value, $event)"
|
||||
:aria-grabbed="value == currentDragItem"
|
||||
:class="value.classes"
|
||||
@contextmenu.prevent="$emit('open-context-menu', $event, value)">
|
||||
<div class="card-header p-1 text-center text-primary border-bottom-0" v-if="detailed"
|
||||
:style="`background-color: ${background_color}`">
|
||||
<span class="font-light text-center" v-if="entry.entry.meal_type.icon != null">{{
|
||||
entry.entry.meal_type.icon
|
||||
}}</span>
|
||||
<span class="font-light d-none d-md-inline">{{ entry.entry.meal_type.name }}</span>
|
||||
</div>
|
||||
<div class="card-img-overlay h-100 d-flex flex-column justify-content-right float-right text-right p-0"
|
||||
v-if="detailed">
|
||||
<a>
|
||||
<div style="position: static;">
|
||||
<div class="dropdown b-dropdown position-static btn-group">
|
||||
<button aria-haspopup="true" aria-expanded="false" type="button"
|
||||
class="btn btn-link text-decoration-none text-body pr-2 dropdown-toggle-no-caret"
|
||||
@click.stop="$emit('open-context-menu', $event, value)"><i class="fas fa-ellipsis-v fa-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-hover
|
||||
class="card cv-item meal-plan-card p-0"
|
||||
:key="value.id"
|
||||
:draggable="true"
|
||||
:style="`top:${top};max-height:${item_height}`"
|
||||
@dragstart="onDragItemStart(value, $event)"
|
||||
@click="onClickItem(value, $event)"
|
||||
:aria-grabbed="value == currentDragItem"
|
||||
:class="value.classes"
|
||||
@contextmenu.prevent="$emit('open-context-menu', $event, value)"
|
||||
>
|
||||
<div class="card-header p-1 text-center text-primary border-bottom-0" v-if="detailed" :style="`background-color: ${background_color}`">
|
||||
<span class="font-light text-center" v-if="entry.entry.meal_type.icon != null">{{ entry.entry.meal_type.icon }}</span>
|
||||
<span class="font-light d-none d-md-inline">{{ entry.entry.meal_type.name }}</span>
|
||||
<span v-if="entry.entry.shopping" class="font-light"><i class="fas fa-shopping-cart fa-xs float-left" v-b-tooltip.hover.top :title="$t('in_shopping')" /></span>
|
||||
</div>
|
||||
<div class="card-img-overlay h-100 d-flex flex-column justify-content-right float-right text-right p-0" v-if="detailed">
|
||||
<a>
|
||||
<div style="position: static">
|
||||
<div class="dropdown b-dropdown position-static btn-group">
|
||||
<button
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
type="button"
|
||||
class="btn btn-link text-decoration-none text-body pr-2 dropdown-toggle-no-caret"
|
||||
@click.stop="$emit('open-context-menu', $event, value)"
|
||||
>
|
||||
<i class="fas fa-ellipsis-v fa-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-header p-1 text-center" v-if="detailed" :style="`background-color: ${background_color}`">
|
||||
<span class="font-light">{{ title }}</span>
|
||||
</div>
|
||||
<b-img fluid class="card-img-bottom" :src="entry.entry.recipe.image" v-if="hasRecipe && detailed"></b-img>
|
||||
<b-img fluid class="card-img-bottom" :src="image_placeholder" v-if="detailed && ((!hasRecipe && entry.entry.note === '') || (hasRecipe && entry.entry.recipe.image === null))"></b-img>
|
||||
<div class="card-body p-1" v-if="detailed && entry.entry.recipe == null" :style="`background-color: ${background_color}`">
|
||||
<p>{{ entry.entry.note }}</p>
|
||||
</div>
|
||||
<div class="row p-1 flex-nowrap" v-if="!detailed" :style="`background-color: ${background_color}`">
|
||||
<div class="col-2">
|
||||
<span class="font-light text-center" v-if="entry.entry.meal_type.icon != null" v-b-tooltip.hover.left :title="entry.entry.meal_type.name">{{ entry.entry.meal_type.icon }}</span>
|
||||
<span class="font-light text-center" v-if="entry.entry.meal_type.icon == null" v-b-tooltip.hover.left :title="entry.entry.meal_type.name">❓</span>
|
||||
</div>
|
||||
<div class="col-10 d-inline-block text-truncate" :style="`max-height:${item_height}`">
|
||||
<span class="font-light">{{ title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-header p-1 text-center" v-if="detailed" :style="`background-color: ${background_color}`">
|
||||
<span class="font-light">{{ title }}</span>
|
||||
</div>
|
||||
<b-img fluid class="card-img-bottom" :src="entry.entry.recipe.image" v-if="hasRecipe && detailed" ></b-img>
|
||||
<b-img fluid class="card-img-bottom" :src="image_placeholder"
|
||||
v-if="detailed && ((!hasRecipe && entry.entry.note === '') || (hasRecipe && entry.entry.recipe.image === null))"></b-img>
|
||||
<div class="card-body p-1" v-if="detailed && entry.entry.recipe == null"
|
||||
:style="`background-color: ${background_color}`">
|
||||
<p>{{ entry.entry.note }}</p>
|
||||
</div>
|
||||
<div class="row p-1 flex-nowrap" v-if="!detailed" :style="`background-color: ${background_color}`">
|
||||
<div class="col-2">
|
||||
<span class="font-light text-center" v-if="entry.entry.meal_type.icon != null" v-b-tooltip.hover.left
|
||||
:title=" entry.entry.meal_type.name">{{
|
||||
entry.entry.meal_type.icon
|
||||
}}</span>
|
||||
<span class="font-light text-center" v-if="entry.entry.meal_type.icon == null" v-b-tooltip.hover.left
|
||||
:title=" entry.entry.meal_type.name">❓</span>
|
||||
</div>
|
||||
<div class="col-10 d-inline-block text-truncate" :style="`max-height:${item_height}`">
|
||||
<span class="font-light">{{ title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MealPlanCard.vue",
|
||||
components: {},
|
||||
props: {
|
||||
value: Object,
|
||||
weekStartDate: Date,
|
||||
top: String,
|
||||
detailed: Boolean,
|
||||
item_height: String
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
dateSelectionOrigin: null,
|
||||
currentDragItem: null,
|
||||
image_placeholder: window.IMAGE_PLACEHOLDER
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
entry: function () {
|
||||
return this.value.originalItem
|
||||
name: "MealPlanCard.vue",
|
||||
components: {},
|
||||
props: {
|
||||
value: Object,
|
||||
weekStartDate: Date,
|
||||
top: String,
|
||||
detailed: Boolean,
|
||||
item_height: String,
|
||||
},
|
||||
title: function () {
|
||||
if (this.entry.entry.title != null && this.entry.entry.title !== '') {
|
||||
return this.entry.entry.title
|
||||
} else {
|
||||
return this.entry.entry.recipe_name
|
||||
}
|
||||
data: function () {
|
||||
return {
|
||||
dateSelectionOrigin: null,
|
||||
currentDragItem: null,
|
||||
image_placeholder: window.IMAGE_PLACEHOLDER,
|
||||
}
|
||||
},
|
||||
hasRecipe: function () {
|
||||
return this.entry.entry.recipe != null;
|
||||
mounted() {
|
||||
console.log(this.value)
|
||||
},
|
||||
background_color: function () {
|
||||
if (this.entry.entry.meal_type.color != null && this.entry.entry.meal_type.color !== '') {
|
||||
return this.entry.entry.meal_type.color
|
||||
} else {
|
||||
return "#fff"
|
||||
}
|
||||
computed: {
|
||||
entry: function () {
|
||||
return this.value.originalItem
|
||||
},
|
||||
title: function () {
|
||||
if (this.entry.entry.title != null && this.entry.entry.title !== "") {
|
||||
return this.entry.entry.title
|
||||
} else {
|
||||
return this.entry.entry.recipe_name
|
||||
}
|
||||
},
|
||||
hasRecipe: function () {
|
||||
return this.entry.entry.recipe != null
|
||||
},
|
||||
background_color: function () {
|
||||
if (this.entry.entry.meal_type.color != null && this.entry.entry.meal_type.color !== "") {
|
||||
return this.entry.entry.meal_type.color
|
||||
} else {
|
||||
return "#fff"
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onDragItemStart(calendarItem, windowEvent) {
|
||||
this.$emit("dragstart", calendarItem, windowEvent)
|
||||
return true
|
||||
methods: {
|
||||
onDragItemStart(calendarItem, windowEvent) {
|
||||
this.$emit("dragstart", calendarItem, windowEvent)
|
||||
return true
|
||||
},
|
||||
onContextMenuOpen(calendarItem, windowEvent) {
|
||||
this.$emit("dragstart", calendarItem, windowEvent)
|
||||
return true
|
||||
},
|
||||
onClickItem(calendarItem, windowEvent) {
|
||||
this.$emit("click-item", calendarItem)
|
||||
return true
|
||||
},
|
||||
},
|
||||
onContextMenuOpen(calendarItem, windowEvent) {
|
||||
this.$emit("dragstart", calendarItem, windowEvent)
|
||||
return true
|
||||
directives: {
|
||||
hover: {
|
||||
inserted: (el) => {
|
||||
el.addEventListener("mouseenter", () => {
|
||||
el.classList.add("shadow")
|
||||
})
|
||||
el.addEventListener("mouseleave", () => {
|
||||
el.classList.remove("shadow")
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
onClickItem(calendarItem, windowEvent) {
|
||||
this.$emit("click-item", calendarItem)
|
||||
return true
|
||||
},
|
||||
},
|
||||
directives: {
|
||||
hover: {
|
||||
inserted: (el) => {
|
||||
el.addEventListener('mouseenter', () => {
|
||||
el.classList.add("shadow")
|
||||
});
|
||||
el.addEventListener('mouseleave', () => {
|
||||
el.classList.remove("shadow")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.meal-plan-card {
|
||||
background-color: #fff;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<a class="dropdown-item" :href="`${resolveDjangoUrl('view_shopping')}?r=[${recipe.id},${servings_value}]`" v-if="recipe.internal" target="_blank" rel="noopener noreferrer">
|
||||
<i class="fas fa-shopping-cart fa-fw"></i> {{ $t("Add_to_Shopping") }}
|
||||
</a>
|
||||
<a class="dropdown-item" v-if="recipe.internal" @click="addToShopping" href="#"> <i class="fas fa-shopping-cart fa-fw"></i> New {{ $t("create_shopping_new") }} </a>
|
||||
<a class="dropdown-item" v-if="recipe.internal" @click="addToShopping" href="#"> <i class="fas fa-shopping-cart fa-fw"></i> {{ $t("create_shopping_new") }} </a>
|
||||
|
||||
<a class="dropdown-item" @click="createMealPlan" href="javascript:void(0);"><i class="fas fa-calendar fa-fw"></i> {{ $t("Add_to_Plan") }} </a>
|
||||
|
||||
|
@ -265,7 +265,7 @@
|
||||
"CategoryInstruction": "Drag categories to change the order categories appear in shopping list.",
|
||||
"shopping_recent_days_desc": "Days of recent shopping list entries to display.",
|
||||
"shopping_recent_days": "Recent Days",
|
||||
"create_shopping_new": "NEW: Add to Shopping List",
|
||||
"create_shopping_new": "Add to NEW Shopping List",
|
||||
"download_pdf": "Download PDF",
|
||||
"download_csv": "Download CSV",
|
||||
"csv_delim_help": "Delimiter to use for CSV exports.",
|
||||
@ -274,5 +274,6 @@
|
||||
"copy_to_clipboard": "Copy to Clipboard",
|
||||
"csv_prefix_help": "Prefix to add when copying list to the clipboard.",
|
||||
"csv_prefix_label": "List Prefix",
|
||||
"copy_markdown_table": "Copy as Markdown Table"
|
||||
"copy_markdown_table": "Copy as Markdown Table",
|
||||
"in_shopping": "In Shopping List"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user