diff --git a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue
index c3bdf3956..649e39d23 100644
--- a/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue
+++ b/frontend/components/Domain/Recipe/RecipeDialogAddToShoppingList.vue
@@ -86,6 +86,19 @@
class="text-center"
>
{{ recipeSection.recipeName }}
+
+
+
+ {{ $globals.icons.potSteam }}
+
+
+ {{ $t("shopping-list.ingredient-of-recipe", { recipe: recipeSection.parentRecipe.name }) }}
+
preferences.value.viewAllLists], () => {
}
});
+function buildIngredientSections(ingredients: ShoppingListIngredient[]): ShoppingListIngredientSection[] {
+ let currentTitle = "";
+ const onHandIngs: ShoppingListIngredient[] = [];
+ const sections = ingredients.reduce((acc, ing) => {
+ if (ing.ingredient.title) {
+ currentTitle = ing.ingredient.title;
+ }
+
+ if (!acc.length || currentTitle !== acc[acc.length - 1].sectionName) {
+ if (acc.length) {
+ acc[acc.length - 1].ingredients.push(...onHandIngs);
+ onHandIngs.length = 0;
+ }
+ acc.push({ sectionName: currentTitle, ingredients: [] });
+ }
+
+ const householdsWithFood = ing.ingredient?.food?.householdsWithIngredientFood || [];
+ if (householdsWithFood.includes(currentHouseholdSlug.value)) {
+ onHandIngs.push(ing);
+ return acc;
+ }
+
+ acc[acc.length - 1].ingredients.push(ing);
+ return acc;
+ }, [] as ShoppingListIngredientSection[]);
+
+ if (sections.length) {
+ sections[sections.length - 1].ingredients.push(...onHandIngs);
+ }
+ return sections;
+}
+
async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
const recipeSectionMap = new Map();
+
+ function addSubRecipeToMap(ing: RecipeIngredient, parentQuantity: number, parentScale: number, parentRecipe: Recipe) {
+ const ref = ing.referencedRecipe!;
+ const key = ref.id || ref.slug || "";
+ const ownIngs: ShoppingListIngredient[] = [];
+ const subRefIngs: RecipeIngredient[] = [];
+
+ for (const subIng of ref.recipeIngredient ?? []) {
+ if (subIng.referencedRecipe) {
+ subRefIngs.push(subIng);
+ }
+ else {
+ const householdsWithFood = subIng.food?.householdsWithIngredientFood || [];
+ ownIngs.push({
+ checked: !householdsWithFood.includes(currentHouseholdSlug.value),
+ ingredient: { ...subIng, quantity: (ing.quantity || 1) * (subIng.quantity || 1) },
+ });
+ }
+ }
+
+ recipeSectionMap.set(key, {
+ recipeId: ref.id || "",
+ recipeName: ref.name || "",
+ recipeScale: parentQuantity * parentScale,
+ ingredientSections: buildIngredientSections(ownIngs),
+ parentRecipe,
+ });
+
+ subRefIngs.forEach(subIng => addSubRecipeToMap(subIng, (ing.quantity || 1) * (subIng.quantity || 1), parentScale, ref));
+ }
+
for (const recipe of recipes) {
if (!recipe.slug) {
continue;
@@ -291,81 +368,29 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
continue;
}
- const shoppingListIngredients: ShoppingListIngredient[] = [];
- function flattenRecipeIngredients(ing: RecipeIngredient, parentTitle = ""): ShoppingListIngredient[] {
+ const ownIngs: ShoppingListIngredient[] = [];
+ const subRefIngs: RecipeIngredient[] = [];
+ recipeData.recipeIngredient.forEach((ing) => {
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 },
- "",
- );
- });
+ subRefIngs.push(ing);
}
else {
- // Regular ingredient
const householdsWithFood = ing.food?.householdsWithIngredientFood || [];
- return [{
+ ownIngs.push({
checked: !householdsWithFood.includes(currentHouseholdSlug.value),
- ingredient: {
- ...ing,
- title: ing.title || parentTitle,
- },
- }];
- }
- }
-
- recipeData.recipeIngredient.forEach((ing) => {
- const flattened = flattenRecipeIngredients(ing, "");
- shoppingListIngredients.push(...flattened);
- });
-
- let currentTitle = "";
- const onHandIngs: ShoppingListIngredient[] = [];
- const shoppingListIngredientSections = shoppingListIngredients.reduce((sections, ing) => {
- 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) {
- if (sections.length) {
- // Add the on-hand ingredients to the previous section
- sections[sections.length - 1].ingredients.push(...onHandIngs);
- onHandIngs.length = 0;
- }
- sections.push({
- sectionName: currentTitle,
- ingredients: [],
+ ingredient: ing,
});
}
-
- // Store the on-hand ingredients for later
- const householdsWithFood = (ing.ingredient?.food?.householdsWithIngredientFood || []);
- if (householdsWithFood.includes(currentHouseholdSlug.value)) {
- onHandIngs.push(ing);
- return sections;
- }
-
- // Add the ingredient to previous section
- sections[sections.length - 1].ingredients.push(ing);
- return sections;
- }, [] as ShoppingListIngredientSection[]);
-
- // Add remaining on-hand ingredients to the previous section
- shoppingListIngredientSections[shoppingListIngredientSections.length - 1].ingredients.push(...onHandIngs);
+ });
recipeSectionMap.set(recipe.slug, {
recipeId: recipeData.id,
recipeName: recipeData.name,
recipeScale: recipeData.scale,
- ingredientSections: shoppingListIngredientSections,
+ ingredientSections: buildIngredientSections(ownIngs),
});
+
+ subRefIngs.forEach(ing => addSubRecipeToMap(ing, ing.quantity || 1, recipeData.scale, recipeData));
}
recipeIngredientSections.value = Array.from(recipeSectionMap.values());
diff --git a/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue b/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue
index 2707f7c63..22a0617fc 100644
--- a/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue
+++ b/frontend/components/Domain/Recipe/RecipeIngredientEditor.vue
@@ -44,9 +44,8 @@
@@ -162,7 +161,7 @@
diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json
index 41ca7705f..330f0ed3d 100644
--- a/frontend/lang/messages/en-US.json
+++ b/frontend/lang/messages/en-US.json
@@ -904,6 +904,7 @@
"all-lists": "All Lists",
"create-shopping-list": "Create Shopping List",
"from-recipe": "From Recipe",
+ "ingredient-of-recipe": "Ingredient of {recipe}",
"list-name": "List Name",
"new-list": "New List",
"quantity": "Quantity: {0}",