munch-ease-frontend/src/components/shopping/shopping.js

151 lines
5.6 KiB
JavaScript
Raw Normal View History

function scaleFactor(mealRecipe) {
const numRecipe = mealRecipe.recipe.serves;
const numRequested = mealRecipe.servings;
return numRequested / numRecipe;
}
2024-05-12 03:32:18 +00:00
export function mealToShoppingListSources(meal) {
const sources = [];
for (const mealRecipe of meal.recipes) {
const scale = scaleFactor(mealRecipe);
for (const ingredient of mealRecipe.recipe.ingredients) {
const quantity = ingredient.quantity * scale;
sources.push({ meal, mealRecipe, recipe: mealRecipe.recipe, ingredient: { ...ingredient, quantity, }, });
2024-05-12 03:32:18 +00:00
}
}
for (const ingredient of meal.extra_ingredients) {
sources.push({ ingredient, meal, });
}
return sources;
}
2024-05-18 07:05:28 +00:00
export function requestsToSources(requests) {
const sources = [];
for (const request of requests) {
if (request.ingredient) {
sources.push(request);
}
else if (request.meal) {
sources.push(...mealToShoppingListSources(request.meal));
}
}
return sources;
}
function groupBy(groups, keyFn) {
const grouped = {};
for (const group of groups) {
const key = keyFn(group);
if (!grouped[key]) {
grouped[key] = [];
}
2024-05-12 03:32:18 +00:00
grouped[key].push(group);
}
return grouped;
}
function resultsToSources(shop) {
return shop.results.map(result => ({ shop, ingredient: { product: result.product, unit: result.unit, quantity: result.quantity, }, }));
}
function getOutstandingGroupedByMeal(currentShoppingList) {
// { meal_id: { purchased: [ sources, ], required: [ sources, ], }, }
const requestedMeals = groupBy(requestsToSources(currentShoppingList.requests), source => source.meal?.id);
for (const meal_id in requestedMeals) {
requestedMeals[meal_id] = { id: parseInt(meal_id), purchased: [], required: requestedMeals[meal_id], };
2024-05-19 11:57:28 +00:00
}
for (const shop of currentShoppingList.overlapping_previous_shops) {
const shopResults = groupBy(resultsToSources(shop), source => source.ingredient.product.id);
const purchasedSources = requestsToSources(shop.requests)
.filter(source => source.meal && requestedMeals[source.meal.id])
.filter(source => source.ingredient.product.id in shopResults);
2024-05-19 11:57:28 +00:00
for (const source of purchasedSources) {
2024-10-14 05:11:00 +00:00
requestedMeals[source.meal.id].purchased.push({ shop, ...source });
requestedMeals[source.meal.id].required = requestedMeals[source.meal.id].required.filter(required => required.ingredient.product.id !== source.ingredient.product.id);
}
}
return requestedMeals;
}
export function getCompletedRequests(currentShoppingList, results) {
const newShoppingList = { requests: currentShoppingList.requests, results };
const fakeCurrentShoppingList = { requests: currentShoppingList.requests, overlapping_previous_shops: [ newShoppingList, ...currentShoppingList.overlapping_previous_shops ], };
const requestedMealResults = Object.values(getOutstandingGroupedByMeal(fakeCurrentShoppingList));
const completedMeals = new Set(requestedMealResults.filter(mealGroup => mealGroup.required.length === 0).map(mealGroup => mealGroup.id));
const purchasedProducts = new Set(results.map(result => result.product.id));
const completedSources = currentShoppingList.requests.filter(request => {
if (request.meal) {
return completedMeals.has(request.meal.id);
2024-05-12 03:32:18 +00:00
}
return purchasedProducts.has(request.ingredient.product.id);
});
2024-05-12 03:32:18 +00:00
return sourcesToRequests(completedSources);
2024-05-19 10:21:49 +00:00
}
export function sourcesToRequests(sources) {
const uniqueMeals = sources.filter(source => source.meal)
.map(source => source.meal)
.reduce((acc, meal) => {
acc[meal.id] = { meal, meal_id: meal.id, };
return acc;
}, {});
2024-05-19 12:04:20 +00:00
const directIngredients = sources.filter(source => !source.meal);
return [ ...Object.values(uniqueMeals), ...directIngredients, ];
2024-05-19 12:04:20 +00:00
}
export function toProductsModel(currentShoppingList) {
const requestedMealResults = getOutstandingGroupedByMeal(currentShoppingList);
2024-05-19 12:04:20 +00:00
// Transform into { product_id: { product, requested: [ sources, ], purchased: [ sources, ], }, }
const grouped = {};
for (const meal_id in requestedMealResults) {
for (const source of requestedMealResults[meal_id].required) {
if (!grouped[source.ingredient.product.id]) {
grouped[source.ingredient.product.id] = { product: source.ingredient.product, requested: [], purchased: [], };
}
grouped[source.ingredient.product.id].requested.push(source);
}
for (const source of requestedMealResults[meal_id].purchased) {
if (!grouped[source.ingredient.product.id]) {
grouped[source.ingredient.product.id] = { product: source.ingredient.product, requested: [], purchased: [], };
}
grouped[source.ingredient.product.id].purchased.push(source);
2024-05-19 10:21:49 +00:00
}
}
// Only return values, array
return grouped;
2024-05-19 10:21:49 +00:00
}
export function purchasedToProductModel(shoppingList) {
const purchasedProductIds = new Set(shoppingList.results.map(r => r.product.id));
const purchasedSources = requestsToSources(shoppingList.requests).filter(r => purchasedProductIds.has(r.ingredient.product.id));
const grouped = {};
for (const source of purchasedSources) {
const product = source.ingredient.product;
if (!grouped[product.id]) {
grouped[product.id] = { product, requested: [], purchased: [], };
2024-05-19 10:21:49 +00:00
}
grouped[product.id].requested.push(source);
}
return grouped;
2024-05-12 03:32:18 +00:00
}