fix: Consistant Shopping List Recipe State (#6758)

This commit is contained in:
Michael Genson
2025-12-21 20:27:00 -06:00
committed by GitHub
parent cb7f46c0ad
commit 7cc2ed75e5

View File

@@ -6,7 +6,7 @@
:title="$t('recipe.add-to-list')" :title="$t('recipe.add-to-list')"
:icon="$globals.icons.cartCheck" :icon="$globals.icons.cartCheck"
> >
<v-container v-if="!shoppingListChoices.length"> <v-container v-if="!filteredShoppingLists.length">
<BasePageTitle> <BasePageTitle>
<template #title> <template #title>
{{ $t('shopping-list.no-shopping-lists-found') }} {{ $t('shopping-list.no-shopping-lists-found') }}
@@ -15,7 +15,7 @@
</v-container> </v-container>
<v-card-text> <v-card-text>
<v-card <v-card
v-for="list in shoppingListChoices" v-for="list in filteredShoppingLists"
:key="list.id" :key="list.id"
hover hover
class="my-2 left-border" class="my-2 left-border"
@@ -222,6 +222,10 @@ const api = useUserApi();
const preferences = useShoppingListPreferences(); const preferences = useShoppingListPreferences();
const ready = ref(false); const ready = ref(false);
// Capture values at initialization to avoid reactive updates
const currentHouseholdSlug = ref("");
const filteredShoppingLists = ref<ShoppingListSummary[]>([]);
const state = reactive({ const state = reactive({
shoppingListDialog: true, shoppingListDialog: true,
shoppingListIngredientDialog: false, shoppingListIngredientDialog: false,
@@ -230,31 +234,25 @@ const state = reactive({
const { shoppingListDialog, shoppingListIngredientDialog, shoppingListShowAllToggled: _shoppingListShowAllToggled } = toRefs(state); const { shoppingListDialog, shoppingListIngredientDialog, shoppingListShowAllToggled: _shoppingListShowAllToggled } = toRefs(state);
const userHousehold = computed(() => {
return $auth.user.value?.householdSlug || "";
});
const shoppingListChoices = computed(() => {
return props.shoppingLists.filter(list => preferences.value.viewAllLists || list.userId === $auth.user.value?.id);
});
const recipeIngredientSections = ref<ShoppingListRecipeIngredientSection[]>([]); const recipeIngredientSections = ref<ShoppingListRecipeIngredientSection[]>([]);
const selectedShoppingList = ref<ShoppingListSummary | null>(null); const selectedShoppingList = ref<ShoppingListSummary | null>(null);
watchEffect( watch(dialog, (newVal, oldVal) => {
() => { if (newVal && !oldVal) {
if (shoppingListChoices.value.length === 1 && !state.shoppingListShowAllToggled) { currentHouseholdSlug.value = $auth.user.value?.householdSlug || "";
selectedShoppingList.value = shoppingListChoices.value[0]; filteredShoppingLists.value = props.shoppingLists.filter(
list => preferences.value.viewAllLists || list.userId === $auth.user.value?.id,
);
if (filteredShoppingLists.value.length === 1 && !state.shoppingListShowAllToggled) {
selectedShoppingList.value = filteredShoppingLists.value[0];
openShoppingListIngredientDialog(selectedShoppingList.value); openShoppingListIngredientDialog(selectedShoppingList.value);
} }
else { else {
ready.value = true; ready.value = true;
} }
}, }
); else if (!newVal) {
watch(dialog, (val) => {
if (!val) {
initState(); initState();
} }
}); });
@@ -274,22 +272,26 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
continue; continue;
} }
if (!(recipe.id && recipe.name && recipe.recipeIngredient)) { // Create a local copy to avoid mutating props
const { data } = await api.recipes.getOne(recipe.slug); let recipeData = { ...recipe };
if (!(recipeData.id && recipeData.name && recipeData.recipeIngredient)) {
const { data } = await api.recipes.getOne(recipeData.slug);
if (!data?.recipeIngredient?.length) { if (!data?.recipeIngredient?.length) {
continue; continue;
} }
recipe.id = data.id || ""; recipeData = {
recipe.name = data.name || ""; ...recipeData,
recipe.recipeIngredient = data.recipeIngredient; id: data.id || "",
name: data.name || "",
recipeIngredient: data.recipeIngredient,
};
} }
else if (!recipe.recipeIngredient.length) { else if (!recipeData.recipeIngredient.length) {
continue; continue;
} }
const shoppingListIngredients: ShoppingListIngredient[] = []; const shoppingListIngredients: ShoppingListIngredient[] = [];
function flattenRecipeIngredients(ing: RecipeIngredient, parentTitle = ""): ShoppingListIngredient[] { function flattenRecipeIngredients(ing: RecipeIngredient, parentTitle = ""): ShoppingListIngredient[] {
const householdsWithFood = ing.food?.householdsWithIngredientFood || [];
if (ing.referencedRecipe) { if (ing.referencedRecipe) {
// Recursively flatten all ingredients in the referenced recipe // Recursively flatten all ingredients in the referenced recipe
return (ing.referencedRecipe.recipeIngredient ?? []).flatMap((subIng) => { return (ing.referencedRecipe.recipeIngredient ?? []).flatMap((subIng) => {
@@ -303,8 +305,9 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
} }
else { else {
// Regular ingredient // Regular ingredient
const householdsWithFood = ing.food?.householdsWithIngredientFood || [];
return [{ return [{
checked: !householdsWithFood.includes(userHousehold.value), checked: !householdsWithFood.includes(currentHouseholdSlug.value),
ingredient: { ingredient: {
...ing, ...ing,
title: ing.title || parentTitle, title: ing.title || parentTitle,
@@ -313,7 +316,7 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
} }
} }
recipe.recipeIngredient.forEach((ing) => { recipeData.recipeIngredient.forEach((ing) => {
const flattened = flattenRecipeIngredients(ing, ""); const flattened = flattenRecipeIngredients(ing, "");
shoppingListIngredients.push(...flattened); shoppingListIngredients.push(...flattened);
}); });
@@ -343,7 +346,7 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
// Store the on-hand ingredients for later // Store the on-hand ingredients for later
const householdsWithFood = (ing.ingredient?.food?.householdsWithIngredientFood || []); const householdsWithFood = (ing.ingredient?.food?.householdsWithIngredientFood || []);
if (householdsWithFood.includes(userHousehold.value)) { if (householdsWithFood.includes(currentHouseholdSlug.value)) {
onHandIngs.push(ing); onHandIngs.push(ing);
return sections; return sections;
} }
@@ -357,9 +360,9 @@ async function consolidateRecipesIntoSections(recipes: RecipeWithScale[]) {
shoppingListIngredientSections[shoppingListIngredientSections.length - 1].ingredients.push(...onHandIngs); shoppingListIngredientSections[shoppingListIngredientSections.length - 1].ingredients.push(...onHandIngs);
recipeSectionMap.set(recipe.slug, { recipeSectionMap.set(recipe.slug, {
recipeId: recipe.id, recipeId: recipeData.id,
recipeName: recipe.name, recipeName: recipeData.name,
recipeScale: recipe.scale, recipeScale: recipeData.scale,
ingredientSections: shoppingListIngredientSections, ingredientSections: shoppingListIngredientSections,
}); });
} }