diff --git a/src/components/shopping/FullShoppingListPage.vue b/src/components/shopping/FullShoppingListPage.vue
index 2aa2110..77b5b6a 100644
--- a/src/components/shopping/FullShoppingListPage.vue
+++ b/src/components/shopping/FullShoppingListPage.vue
@@ -5,8 +5,8 @@
@@ -31,7 +31,7 @@
\ No newline at end of file
diff --git a/src/components/shopping/shopping.js b/src/components/shopping/shopping.js
index 1ecc848..4488666 100644
--- a/src/components/shopping/shopping.js
+++ b/src/components/shopping/shopping.js
@@ -44,50 +44,78 @@ export function groupingToIngredients(grouping) {
function calculateTotals(sources) {
const totals = {};
- for (const source of sources) {
- const { unit, factor } = units.getConversionFactor(source.ingredient.unit) ?? { unit: source.ingredient.unit, factor: 1 };
+ for (const { quantity, unit } of sources) {
+ const conversion = units.getConversionFactor(unit) ?? { unit, factor: 1 };
- const quantity = source.ingredient.quantity / factor;
- if (!totals[unit]) {
- totals[unit] = quantity;
+ const quantityInBase = quantity / conversion.factor;
+ if (!totals[conversion.unit]) {
+ totals[conversion.unit] = quantityInBase;
}
else {
- totals[unit] += quantity;
+ totals[conversion.unit] += quantityInBase;
}
}
- const result = [];
- for (const unit in totals) {
- result.push({ unit, quantity: totals[unit] });
- }
-
- return result;
+ return totals;
}
-export function groupByProduct(sources) {
- const noProductKey = "no-product";
- const noProduct = { name: "No product", };
-
+function groupBy(groups, keyFn) {
const grouped = {};
- for (const source of sources) {
- const key = source.ingredient?.product?.id ?? noProductKey;
- if (!key) {
- continue;
- }
-
+ for (const group of groups) {
+ const key = keyFn(group);
if (!grouped[key]) {
- grouped[key] = {
- product: source.ingredient.product ?? noProduct,
- sources: [],
- };
+ grouped[key] = [];
}
- grouped[key].sources.push(source);
+ grouped[key].push(group);
}
- for (const key in grouped) {
- grouped[key].totals = calculateTotals(grouped[key].sources);
+ return grouped;
+}
+
+function getRemainingIngredients(requiredTotals, foundTotals) {
+ const remaining = {};
+ for (const unit in requiredTotals) {
+ const required = requiredTotals[unit];
+ const found = foundTotals[unit] ?? 0;
+ const remainingQuantity = required - found;
+ if (remainingQuantity > 0) {
+ remaining[unit] = remainingQuantity;
+ }
}
- return Object.values(grouped);
+ return remaining;
+}
+
+export function toProductsModel(shoppingList) {
+ const flattenedIngredients = requestsToSources(shoppingList.requests);
+ const foundIngredientsByProduct = groupBy(shoppingList.results.filter(f => f.found_date), found => found.product_id);
+ const requiredIngredientsByProduct = groupBy(flattenedIngredients, source => source.ingredient?.product?.id ?? "no-product");
+
+ const results = [];
+ for (const product_id in requiredIngredientsByProduct) {
+ const sources = requiredIngredientsByProduct[product_id];
+ const requiredIngredients = sources.map(source => source.ingredient);
+
+ const requiredTotals = calculateTotals(requiredIngredients);
+ const foundTotals = calculateTotals(foundIngredientsByProduct[product_id] ?? []);
+
+ let fullyFound = null, foundDate = null;
+ if (Object.keys(foundTotals).length === 0) {
+ foundDate = null;
+ fullyFound = false;
+ }
+ else {
+ foundDate = foundIngredientsByProduct[product_id][0].found_date;
+ fullyFound = Object.keys(getRemainingIngredients(requiredTotals, foundTotals)).length === 0;
+ }
+
+ results.push({
+ product: requiredIngredients[0].product,
+ totals: Object.entries(requiredTotals).map(([unit, quantity]) => ({ unit, quantity, })),
+ fullyFound, foundDate, sources,
+ });
+ }
+
+ return results;
}
\ No newline at end of file
diff --git a/src/data.js b/src/data.js
index cf40b51..873f1d7 100644
--- a/src/data.js
+++ b/src/data.js
@@ -1,11 +1,16 @@
const BASE_URL = window.location.href.replace(/^(http:\/\/[^/:]+).*/, "$1:8000")
-function fixMealDates(meals) {
- for (const meal of meals) {
- meal.meal_date = new Date(meal.meal_date);
+function fixDates(obj, ...fields) {
+ for (const field of fields) {
+ if (obj[field]) {
+ obj[field] = new Date(obj[field]);
+ }
}
}
+const fixMealDates = meals => meals.forEach(meal => fixDates(meal, "meal_date"));
+const fixResultDates = results => results.forEach(result => fixDates(result, "found_date"));
+
let user = null;
export default {
async getMeals(from, to) {
@@ -164,6 +169,9 @@ export default {
const response = await fetch(BASE_URL + "/shopping/current");
const lst = await response.json();
fixMealDates(lst.requests.map(request => request.meal).filter(meal => meal));
+ fixResultDates(lst.results);
+ fixDates(lst, "created_date");
+
return lst;
},
async requestMeal(meal_id) {
@@ -198,7 +206,10 @@ export default {
body: JSON.stringify(ingredients),
});
- return await response.json();
+ const results = await response.json();
+ fixResultDates(results.created);
+ fixResultDates(results.removed);
+ return results;
},
async markNotFound(product_id) {
const response = await fetch(BASE_URL + `/shopping/current/found/${product_id}`, {
@@ -206,6 +217,8 @@ export default {
credentials: "include",
});
- return await response.json();
+ const results = await response.json();
+ fixResultDates(results);
+ return results;
}
}
\ No newline at end of file
diff --git a/src/units.js b/src/units.js
index 73bdf77..cc979ad 100644
--- a/src/units.js
+++ b/src/units.js
@@ -96,19 +96,31 @@ function getBaseUnit(unit) {
export default {
getConversionFactor(unit) {
- let baseUnit = getBaseUnit(unit);
- if (!baseUnit) {
- unit = unit.toLowerCase();
- baseUnit = getBaseUnit(unit);
+ if (unit in equivalentUnits) {
+ return { unit, factor: 1 };
}
- if (!baseUnit) {
- return null;
+ const unitLower = unit.toLowerCase();
+ if (unitLower in equivalentUnits) {
+ return { unit: unitLower, factor: 1 };
+ }
+
+ const baseUnit = getBaseUnit(unit);
+ if (baseUnit) {
+ return {
+ unit: baseUnit,
+ factor: equivalentUnits[baseUnit][unit],
+ };
}
- return {
- unit: baseUnit,
- factor: equivalentUnits[baseUnit][unit],
- };
+ const baseUnitLower = getBaseUnit(unitLower);
+ if (baseUnitLower) {
+ return {
+ unit: baseUnitLower,
+ factor: equivalentUnits[baseUnitLower][unitLower],
+ };
+ }
+
+ return null;
},
}
\ No newline at end of file