Allowed for null products, move ingredient spreading server-side #2

Merged
jacob merged 6 commits from nullproduct into master 2025-07-28 23:22:59 +00:00
2 changed files with 55 additions and 21 deletions
Showing only changes of commit 6cc9f8fef7 - Show all commits

View file

@ -1,12 +1,14 @@
<template>
<h3>Purchased {{ shoppingList ? ago(shoppingList.created_date) : '' }}</h3>
<h4>Included Meals</h4>
<meal-selection-list :checked="includedMeals" :meals="includedMeals" :disabled="true" />
<div v-if="includedMeals.length > 0">
<h4>Included Meals</h4>
<meal-selection-list :checked="includedMeals" :meals="includedMeals" :disabled="true" />
</div>
<ul class="full-shopping-list">
<li v-for="item in listByProduct" :key="item.id">
<shopping-list-item :productGrouping="item" />
<shopping-list-item :shopping-list-item-group="item" />
</li>
</ul>
</template>
@ -43,17 +45,31 @@ export default {
props: {
id: [String, Number]
},
computed: {
includedMeals() {
if (!this.shoppingList) return [];
const seenMeals = new Set();
return this.shoppingList.items
.map(item => item.meal)
.filter(meal => {
if (!meal) return false;
if (seenMeals.has(meal.id)) return false;
seenMeals.add(meal.id);
return true;
});
},
listByProduct() {
return this.shoppingList ? itemsToGroups(this.shoppingList.items) : [];
}
},
data() {
return {
shoppingList: null,
includedMeals: [],
listByProduct: [],
}
},
async beforeMount() {
this.shoppingList = await data.getShoppingList(this.id);
this.includedMeals = Object.values(this.shoppingList.meal_lookup);
this.listByProduct = itemsToGroups(this.shoppingList);
},
methods: {
ago

View file

@ -3,6 +3,7 @@ const BASE_URL = window.location.href.replace(/^(https?:\/\/[^/]+).*/, "$1/api")
const datesToFix = {
Meal: { fields: [ "suggested_date", "purchase_date", "consumed_date" ] },
CurrentShoppingList: { dependants: l => ({ ShoppingListItem: [l.outstanding_items, l.requested_meals, l.purchased_items], Meal: Object.values(l.meals_lookup), Recipe: Object.values(l.recipes_lookup), Ingredient: Object.values(l.ingredients_lookup), ShoppingList: Object.values(l.shopping_list_lookup) }) },
PurchasedShoppingList: { dependants: l => ({ ShoppingListItem: l.items, Meal: Object.values(l.meals_lookup), Recipe: Object.values(l.recipes_lookup), Ingredient: Object.values(l.ingredients_lookup), ShoppingList: l.list }) },
ShoppingList: { fields: [ "created_date" ], dependants: l => ({ ShoppingListItem: l.items }) },
ShoppingListItem: { fields: [ "created_date" ], dependants: r => ({ Meal: r.meal, Recipe: r.recipe, Ingredient: r.ingredient, ShoppingList: r.list }) },
Recipe: { fields: [ "date_created", "date_hidden" ], },
@ -42,23 +43,36 @@ const fixDates = (obj, type) => {
}
}
const setShoppingListReferences = (currentShoppingList) => {
const setPurchasedShoppingListReferences = (purchasedShoppingList) => {
if (!purchasedShoppingList) return;
const { ingredients_lookup, meals_lookup, recipes_lookup, } = purchasedShoppingList;
const shopping_list_lookup = { [purchasedShoppingList.list.id]: purchasedShoppingList.list };
setShoppingListItemReferences(purchasedShoppingList.list.items, ingredients_lookup, meals_lookup, recipes_lookup, shopping_list_lookup);
}
const setCurrentShoppingListReferences = (currentShoppingList) => {
if (!currentShoppingList) return;
const { ingredients_lookup, meals_lookup, recipes_lookup, shopping_list_lookup } = currentShoppingList;
const allShoppingListItems = [...currentShoppingList.outstanding_items, ...currentShoppingList.requested_meals, ...currentShoppingList.purchased_items];
var allRequests = [...currentShoppingList.outstanding_items, ...currentShoppingList.requested_meals, ...currentShoppingList.purchased_items];
setShoppingListItemReferences(allShoppingListItems, ingredients_lookup, meals_lookup, recipes_lookup, shopping_list_lookup);
}
for (const item of allRequests) {
const setShoppingListItemReferences = (shoppingListItems, ingredients_lookup, meals_lookup, recipes_lookup, shopping_list_lookup) => {
if (!shoppingListItems) return;
for (const item of shoppingListItems) {
if (item.ingredient_id) {
item.ingredient = currentShoppingList.ingredients_lookup[item.ingredient_id];
item.ingredient = ingredients_lookup[item.ingredient_id];
}
if (item.meal_id) {
item.meal = currentShoppingList.meals_lookup[item.meal_id];
item.meal = meals_lookup[item.meal_id];
}
if (item.list_id) {
item.list = currentShoppingList.shopping_list_lookup[item.list_id];
item.list = shopping_list_lookup[item.list_id];
}
if (item.recipe_id) {
item.recipe = currentShoppingList.recipes_lookup[item.recipe_id];
item.recipe = recipes_lookup[item.recipe_id];
}
}
}
@ -255,15 +269,18 @@ export default {
async getShoppingList(id) {
const response = await fetch(BASE_URL + `/shopping/${encodeURIComponent(id)}`);
const lst = await response.json();
fixDates(lst, "ShoppingList");
return lst;
const purchasedShoppingList = await response.json();
fixDates(purchasedShoppingList, "PurchasedShoppingList");
setPurchasedShoppingListReferences(purchasedShoppingList);
return purchasedShoppingList.list;
},
async getCurrentShoppingList() {
const response = await fetch(BASE_URL + "/shopping/current");
const lst = await response.json();
fixDates(lst, "CurrentShoppingList");
setShoppingListReferences(lst);
setCurrentShoppingListReferences(lst);
return lst;
},
@ -277,10 +294,11 @@ export default {
body: JSON.stringify({ items: completed_requests }),
});
const lst = await response.json();
fixDates(lst, "ShoppingList");
const purchasedShoppingList = await response.json();
fixDates(purchasedShoppingList, "PurchasedShoppingList");
setPurchasedShoppingListReferences(purchasedShoppingList);
return lst;
return purchasedShoppingList.list;
},
async requestMeal(meal_id) {
const response = await fetch(BASE_URL + "/shopping/current/meals/me", {