mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2025-12-23 18:29:23 -05:00
open meal plan recipe with given servings
Fix https://github.com/TandoorRecipes/recipes/issues/3787 Adds a '?servings=42' query param to RecipeViewPage, and propagates it to child views via a prop. The ingredientFactor is computed based on this param if it is present, and defaults to recipe servings otherwise. This query param is set when comming from: * Home page's HorizontalRecipeWindow * MealPlanEditor This commit also makes the RecipeView's Activity form reactive on the number of servings, before creating a comment.
This commit is contained in:
@@ -146,7 +146,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
function clickMealPlan(plan: MealPlan) {
|
function clickMealPlan(plan: MealPlan) {
|
||||||
if (plan.recipe) {
|
if (plan.recipe) {
|
||||||
router.push({name: 'RecipeViewPage', params: {id: plan.recipe.id}})
|
router.push({
|
||||||
|
name: 'RecipeViewPage',
|
||||||
|
params: { id: String(plan.recipe.id) }, // keep id in params
|
||||||
|
query: { servings: String(plan.servings ?? '') } // pass servings as query
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
import {onMounted, PropType, ref} from "vue";
|
import {onMounted, PropType, ref, watch} from "vue";
|
||||||
import {ApiApi, CookLog, Recipe} from "@/openapi";
|
import {ApiApi, CookLog, Recipe} from "@/openapi";
|
||||||
import {DateTime} from "luxon";
|
import {DateTime} from "luxon";
|
||||||
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
|
||||||
@@ -82,6 +82,10 @@ const props = defineProps({
|
|||||||
type: Object as PropType<Recipe>,
|
type: Object as PropType<Recipe>,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
servings: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const newCookLog = ref({} as CookLog);
|
const newCookLog = ref({} as CookLog);
|
||||||
@@ -121,7 +125,7 @@ function recLoadCookLog(recipeId: number, page: number = 1) {
|
|||||||
*/
|
*/
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
newCookLog.value = {} as CookLog
|
newCookLog.value = {} as CookLog
|
||||||
newCookLog.value.servings = props.recipe.servings
|
newCookLog.value.servings = props.servings
|
||||||
newCookLog.value.createdAt = new Date()
|
newCookLog.value.createdAt = new Date()
|
||||||
newCookLog.value.recipe = props.recipe.id!
|
newCookLog.value.recipe = props.recipe.id!
|
||||||
}
|
}
|
||||||
@@ -140,6 +144,13 @@ function saveCookLog() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* watch for changes in servings prop and update the servings input field
|
||||||
|
*/
|
||||||
|
watch(() => props.servings, (newVal) => {
|
||||||
|
newCookLog.value.servings = newVal
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<template v-if="!props.loading">
|
<template v-if="!props.loading">
|
||||||
|
|
||||||
<router-link :to="{name: 'RecipeViewPage', params: {id: props.recipe.id}}" :target="linkTarget">
|
<router-link :to="dest" :target="linkTarget">
|
||||||
<recipe-image :style="{height: props.height}" :recipe="props.recipe" rounded="lg" class="mr-3 ml-3">
|
<recipe-image :style="{height: props.height}" :recipe="props.recipe" rounded="lg" class="mr-3 ml-3">
|
||||||
|
|
||||||
</recipe-image>
|
</recipe-image>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<v-card :to="{name: 'RecipeViewPage', params: {id: props.recipe.id}}" :style="{'height': props.height}" v-if="false">
|
<v-card :to="dest" :style="{'height': props.height}" v-if="false">
|
||||||
<v-tooltip
|
<v-tooltip
|
||||||
class="align-center justify-center"
|
class="align-center justify-center"
|
||||||
location="top center" origin="overlap"
|
location="top center" origin="overlap"
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {PropType} from 'vue'
|
import {computed, PropType} from 'vue'
|
||||||
import KeywordsComponent from "@/components/display/KeywordsBar.vue";
|
import KeywordsComponent from "@/components/display/KeywordsBar.vue";
|
||||||
import {Recipe, RecipeOverview} from "@/openapi";
|
import {Recipe, RecipeOverview} from "@/openapi";
|
||||||
|
|
||||||
@@ -113,20 +113,29 @@ const props = defineProps({
|
|||||||
show_description: {type: Boolean, required: false},
|
show_description: {type: Boolean, required: false},
|
||||||
height: {type: String, required: false, default: '15vh'},
|
height: {type: String, required: false, default: '15vh'},
|
||||||
linkTarget: {type: String, required: false, default: ''},
|
linkTarget: {type: String, required: false, default: ''},
|
||||||
showMenu: {type: Boolean, default: true, required: false}
|
showMenu: {type: Boolean, default: true, required: false},
|
||||||
|
servings: {type: Number, required: false},
|
||||||
})
|
})
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const dest = computed(() => {
|
||||||
|
const route: any = { name: 'RecipeViewPage', params: { id: props.recipe.id } };
|
||||||
|
if (props.servings !== undefined) {
|
||||||
|
route.query = { servings: String(props.servings) };
|
||||||
|
}
|
||||||
|
return route;
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* open the recipe either in the same tab or in a new tab depending on the link target prop
|
* open the recipe either in the same tab or in a new tab depending on the link target prop
|
||||||
*/
|
*/
|
||||||
function openRecipe() {
|
function openRecipe() {
|
||||||
if (props.linkTarget != '') {
|
if (props.linkTarget != '') {
|
||||||
const routeData = router.resolve({name: 'RecipeViewPage', params: {id: props.recipe.id}});
|
const routeData = router.resolve(dest.value);
|
||||||
window.open(routeData.href, props.linkTarget);
|
window.open(routeData.href, props.linkTarget);
|
||||||
} else {
|
} else {
|
||||||
router.push({name: 'RecipeViewPage', params: {id: props.recipe.id}})
|
router.push(dest.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<recipe-activity :recipe="recipe" v-if="useUserPreferenceStore().userSettings.comments"></recipe-activity>
|
<recipe-activity :recipe="recipe" :servings="servings" v-if="useUserPreferenceStore().userSettings.comments"></recipe-activity>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -219,8 +219,11 @@ const {doAiImport, fileApiLoading} = useFileApi()
|
|||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const recipe = defineModel<Recipe>({required: true})
|
const recipe = defineModel<Recipe>({required: true})
|
||||||
|
const props = defineProps<{
|
||||||
|
servings: {type: Number, required: false},
|
||||||
|
}>()
|
||||||
|
|
||||||
const servings = ref(1)
|
const servings = ref(props.servings ?? recipe.value.servings ?? 1)
|
||||||
const showFullRecipeName = ref(false)
|
const showFullRecipeName = ref(false)
|
||||||
|
|
||||||
const selectedAiProvider = ref<undefined | AiProvider>(useUserPreferenceStore().activeSpace.aiDefaultProvider)
|
const selectedAiProvider = ref<undefined | AiProvider>(useUserPreferenceStore().activeSpace.aiDefaultProvider)
|
||||||
@@ -235,11 +238,13 @@ const ingredientFactor = computed(() => {
|
|||||||
/**
|
/**
|
||||||
* change servings when recipe servings are changed
|
* change servings when recipe servings are changed
|
||||||
*/
|
*/
|
||||||
watch(() => recipe.value.servings, () => {
|
if (props.servings === undefined) {
|
||||||
if (recipe.value.servings) {
|
watch(() => recipe.value.servings, () => {
|
||||||
servings.value = recipe.value.servings
|
if (recipe.value.servings) {
|
||||||
}
|
servings.value = recipe.value.servings
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
//keep screen on while viewing a recipe
|
//keep screen on while viewing a recipe
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
@update:modelValue="editingObj.servings = editingObj.recipe ? editingObj.recipe.servings : 1"></ModelSelect>
|
@update:modelValue="editingObj.servings = editingObj.recipe ? editingObj.recipe.servings : 1"></ModelSelect>
|
||||||
<!-- <v-number-input label="Days" control-variant="split" :min="1"></v-number-input>-->
|
<!-- <v-number-input label="Days" control-variant="split" :min="1"></v-number-input>-->
|
||||||
<!--TODO create days input with +/- synced to date -->
|
<!--TODO create days input with +/- synced to date -->
|
||||||
<recipe-card :recipe="editingObj.recipe" v-if="editingObj && editingObj.recipe" link-target="_blank"></recipe-card>
|
<recipe-card :recipe="editingObj.recipe" :servings="editingObj.servings" v-if="editingObj && editingObj.recipe" link-target="_blank"></recipe-card>
|
||||||
<v-btn prepend-icon="$shopping" color="create" class="mt-1" v-if="!editingObj.shopping && editingObj.recipe && isUpdate()">
|
<v-btn prepend-icon="$shopping" color="create" class="mt-1" v-if="!editingObj.shopping && editingObj.recipe && isUpdate()">
|
||||||
{{$t('Add')}}
|
{{$t('Add')}}
|
||||||
<add-to-shopping-dialog :recipe="editingObj.recipe" :meal-plan="editingObj" @created="loadShoppingListEntries(); editingObj.shopping = true;"></add-to-shopping-dialog>
|
<add-to-shopping-dialog :recipe="editingObj.recipe" :meal-plan="editingObj" @created="loadShoppingListEntries(); editingObj.shopping = true;"></add-to-shopping-dialog>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container :class="{'ps-0 pe-0 pt-0': mobile}">
|
<v-container :class="{'ps-0 pe-0 pt-0': mobile}">
|
||||||
<recipe-view v-model="recipe"></recipe-view>
|
<recipe-view v-model="recipe" :servings="servings"></recipe-view>
|
||||||
|
|
||||||
<div class="mt-2" v-if="isShared && Object.keys(recipe).length > 0">
|
<div class="mt-2" v-if="isShared && Object.keys(recipe).length > 0">
|
||||||
<import-tandoor-dialog></import-tandoor-dialog>
|
<import-tandoor-dialog></import-tandoor-dialog>
|
||||||
@@ -33,6 +33,13 @@ const isShared = computed(() => {
|
|||||||
return params.share && typeof params.share == "string"
|
return params.share && typeof params.share == "string"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const servings = computed(() => {
|
||||||
|
const value = params.servings
|
||||||
|
if (!value) return undefined
|
||||||
|
const parsed = parseInt(value as string, 10)
|
||||||
|
return parsed > 0 ? parsed : undefined
|
||||||
|
})
|
||||||
|
|
||||||
const recipe = ref({} as Recipe)
|
const recipe = ref({} as Recipe)
|
||||||
|
|
||||||
watch(() => props.id, () => {
|
watch(() => props.id, () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user