diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index 80f88d9aa..7fab21795 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue index a55fd14c1..f371a27a7 100644 --- a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue +++ b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue @@ -139,7 +139,7 @@ color="secondary" density="compact" /> -
+
{ - const householdsWithFood = (ing.food?.householdsWithIngredientFood || []); - return { - checked: !householdsWithFood.includes(userHousehold.value), - ingredient: ing, - }; + const shoppingListIngredients: ShoppingListIngredient[] = []; + function flattenRecipeIngredients(ing: RecipeIngredient, parentTitle = ""): ShoppingListIngredient[] { + const householdsWithFood = ing.food?.householdsWithIngredientFood || []; + if (ing.referencedRecipe) { + // Recursively flatten all ingredients in the referenced recipe + return (ing.referencedRecipe.recipeIngredient ?? []).flatMap((subIng) => { + const calculatedQty = (ing.quantity || 1) * (subIng.quantity || 1); + // Pass the referenced recipe name as the section title + return flattenRecipeIngredients( + { ...subIng, quantity: calculatedQty }, + "", + ); + }); + } + else { + // Regular ingredient + return [{ + checked: !householdsWithFood.includes(userHousehold.value), + ingredient: { + ...ing, + title: ing.title || parentTitle, + }, + }]; + } + } + + recipe.recipeIngredient.forEach((ing) => { + const flattened = flattenRecipeIngredients(ing, ""); + shoppingListIngredients.push(...flattened); }); let currentTitle = ""; @@ -301,6 +324,9 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) { if (ing.ingredient.title) { currentTitle = ing.ingredient.title; } + else if (ing.ingredient.referencedRecipe?.name) { + currentTitle = ing.ingredient.referencedRecipe.name; + } // If this is the first item in the section, create a new section if (sections.length === 0 || currentTitle !== sections[sections.length - 1].sectionName) { @@ -316,7 +342,7 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) { } // Store the on-hand ingredients for later - const householdsWithFood = (ing.ingredient.food?.householdsWithIngredientFood || []); + const householdsWithFood = (ing.ingredient?.food?.householdsWithIngredientFood || []); if (householdsWithFood.includes(userHousehold.value)) { onHandIngs.push(ing); return sections; diff --git a/frontend/components/Domain/Recipe/RecipeDialogBulkAdd.vue b/frontend/components/Domain/Recipe/RecipeDialogBulkAdd.vue index 23020e4e0..dc6bfae76 100644 --- a/frontend/components/Domain/Recipe/RecipeDialogBulkAdd.vue +++ b/frontend/components/Domain/Recipe/RecipeDialogBulkAdd.vue @@ -141,6 +141,13 @@ function save() { dialog.value = false; } +function open() { + dialog.value = true; +} +function close() { + dialog.value = false; +} + const i18n = useI18n(); const utilities = [ @@ -160,4 +167,10 @@ const utilities = [ action: splitByNumberedLine, }, ]; + +// Expose functions to parent components +defineExpose({ + open, + close, +}); diff --git a/frontend/components/Domain/Recipe/RecipeDialogPrintPreferences.vue b/frontend/components/Domain/Recipe/RecipeDialogPrintPreferences.vue index 99f05ef9f..b20dd2bed 100644 --- a/frontend/components/Domain/Recipe/RecipeDialogPrintPreferences.vue +++ b/frontend/components/Domain/Recipe/RecipeDialogPrintPreferences.vue @@ -69,7 +69,14 @@ :label="$t('recipe.nutrition')" /> - + + + diff --git a/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue b/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue index 4c779d81e..63175ec10 100644 --- a/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue +++ b/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue @@ -41,6 +41,7 @@ + + + +