diff --git a/src/components/LoginPage.vue b/src/components/LoginPage.vue index 80edb80..39b1427 100644 --- a/src/components/LoginPage.vue +++ b/src/components/LoginPage.vue @@ -33,7 +33,7 @@ export default { methods: { async login() { const person = await data.login(this.username); - if (person?.id) { + if (person?.id >= 0) { this.$router.push(this.redirect); return; } diff --git a/src/components/meals/EditMealPage.vue b/src/components/meals/EditMealPage.vue index 75fecaf..bf00c5a 100644 --- a/src/components/meals/EditMealPage.vue +++ b/src/components/meals/EditMealPage.vue @@ -55,7 +55,7 @@ export default { data() { return { meal: { - id: 0, + id: -1, meal_date: new Date(), recipes: [], extra_ingredients: [], @@ -66,7 +66,7 @@ export default { }; }, async beforeMount() { - if (this.id) { + if (this.id >= 0) { this.meal = await data.getMeal(this.id); } }, @@ -109,7 +109,7 @@ export default { }, async saveMeal() { const meal = await data.saveMeal(this.meal); - if (meal?.id) { + if (meal?.id >= 0) { this.$router.push(`/meals/${meal.id}`); return; } diff --git a/src/components/meals/PersonList.vue b/src/components/meals/PersonList.vue index 62a7c5d..793f6ec 100644 --- a/src/components/meals/PersonList.vue +++ b/src/components/meals/PersonList.vue @@ -148,12 +148,12 @@ export default { this.searchResults = results.filter(p => !idSet.has(p.id)); }, addPerson(person) { - if (!person?.id && this.searchResults.length > 0) + if (!person?.id >= 0 && this.searchResults.length > 0) { person = this.searchResults[0]; } - if (person?.id && !this.people.find(p => p.id === person.id)) + if (person?.id >= 0 && !this.people.find(p => p.id === person.id)) { this.$emit('add-person', person); } diff --git a/src/components/recipes/EditRecipePage.vue b/src/components/recipes/EditRecipePage.vue index ed9bbfc..fe61278 100644 --- a/src/components/recipes/EditRecipePage.vue +++ b/src/components/recipes/EditRecipePage.vue @@ -99,7 +99,7 @@ export default { this.refreshRecipe(); }, async refreshRecipe() { - if (this.id) { + if (this.id >= 0) { this.recipe = await data.getRecipe(this.id); this.link = this.recipe.link; return; @@ -120,7 +120,7 @@ export default { }, async saveRecipe() { const recipe = await data.saveRecipe(this.recipe); - if (recipe?.id) { + if (recipe?.id >= 0) { this.$router.push(`/recipes/${recipe.id}`); return; } @@ -129,8 +129,9 @@ export default { }, async createFromScratch() { this.recipe = { - id: 0, + id: -1, name: 'My new recipe', + created_by_id: -1, link: '', ingredients: [], image_urls: [] diff --git a/src/components/shopping/FullShoppingListPage.vue b/src/components/shopping/CurrentShoppingListPage.vue similarity index 88% rename from src/components/shopping/FullShoppingListPage.vue rename to src/components/shopping/CurrentShoppingListPage.vue index 63d1b7b..41cec6f 100644 --- a/src/components/shopping/FullShoppingListPage.vue +++ b/src/components/shopping/CurrentShoppingListPage.vue @@ -16,6 +16,8 @@ + + + + \ No newline at end of file diff --git a/src/components/shopping/shopping.js b/src/components/shopping/shopping.js index 62ed9a7..b1d7b5a 100644 --- a/src/components/shopping/shopping.js +++ b/src/components/shopping/shopping.js @@ -46,7 +46,7 @@ export function groupingToIngredients(grouping) { const product = grouping.product; const totals = []; for (const total of grouping.totals) { - totals.push({ id: 0, line: `${total.quantity} ${total.unit} of ${product.name}`, preparation: '', name: product.name, product, ...total }); + totals.push({ id: -1, line: `${total.quantity} ${total.unit} of ${product.name}`, preparation: '', name: product.name, product, ...total }); } return totals; } diff --git a/src/data.js b/src/data.js index 9a5d1db..f36dd2b 100644 --- a/src/data.js +++ b/src/data.js @@ -1,46 +1,89 @@ const BASE_URL = window.location.href.replace(/^(http:\/\/[^/:]+).*/, "$1:8000") -function fixDates(obj, ...fields) { - for (const field of fields) { +const datesToFix = { + Meal: { fields: [ "meal_date" ] }, + ShoppingList: { fields: [ "created_date", "purchased_date" ], dependants: l => ({ ShoppingListResult: l.results, ShoppingListRequest: l.requests }) }, + ShoppingListResult: { fields: [ "found_date", "created_date" ], }, + ShoppingListRequest: { fields: [ "created_date" ], dependants: r => ({ Meal: r.meal }) }, + Recipe: { fields: [ "date_created", "date_hidden" ], }, +}; + +const fixDates = (obj, type) => { + if (!obj) return; + + if (Array.isArray(obj)) { + for (const item of obj) { + fixDates(item, type); + } + } + + const toFix = datesToFix[type]; + if (!toFix) return; + + for (const field of toFix.fields) { if (obj[field]) { obj[field] = new Date(obj[field]); } } + + if (toFix.dependants) { + for (const [key, value] of Object.entries(toFix.dependants(obj))) { + if (Array.isArray(value)) { + for (const item of value) { + fixDates(item, key); + } + } + else { + fixDates(value, key); + } + } + } } -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) { const response = await fetch(BASE_URL + "/meals?from=" + from.toISOString() + "&to=" + to.toISOString()); const meals = await response.json(); - fixMealDates(meals); + fixDates(meals, "Meal"); return meals.sort((a, b) => a.meal_date - b.meal_date); }, async getMeal(id) { var response = await fetch(BASE_URL + `/meals/${encodeURIComponent(id)}`); - return await response.json(); + const meal = await response.json(); + fixDates(meal, "Meal"); + + return meal; }, async deleteMeal(id) { var response = await fetch(BASE_URL + `/meals/${encodeURIComponent(id)}`, { method: "DELETE", }); + return await response.json(); }, async searchRecipes(query) { const response = await fetch(BASE_URL + "/recipes?q=" + encodeURIComponent(query)); - return await response.json(); + const recipes = await response.json(); + fixDates(recipes, "Recipe"); + + return recipes; }, async parseRecipe(url) { const response = await fetch(BASE_URL + `/recipes/parse?url=${encodeURIComponent(url)}`, { credentials: "include" }); - return await response.json(); + const recipe = await response.json(); + fixDates(recipe, "Recipe"); + + return recipe; }, async getRecipe(id) { const response = await fetch(BASE_URL + `/recipes/${encodeURIComponent(id)}`); - return await response.json(); + const recipe = await response.json(); + fixDates(recipe, "Recipe"); + + return recipe; }, async parseProduct(ingredient, url) { const body = { @@ -73,11 +116,15 @@ export default { body: JSON.stringify(recipe), }); - return await response.json(); + const saved = await response.json(); + fixDates(saved, "Recipe"); + + return saved; }, async saveMeal(meal) { - if (meal.id) { - const response = await fetch(BASE_URL + `/meals/${encodeURIComponent(meal.id)}`, { + let response = null; + if (meal.id >= 0) { + response = await fetch(BASE_URL + `/meals/${encodeURIComponent(meal.id)}`, { method: "PUT", credentials: "include", headers: { @@ -85,19 +132,21 @@ export default { }, body: JSON.stringify(meal), }); - return await response.json(); + } else { + response = await fetch(BASE_URL + "/meals", { + method: "POST", + credentials: "include", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(meal), + }); } - const response = await fetch(BASE_URL + "/meals", { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(meal), - }); - - return await response.json(); + const saved = await response.json(); + fixDates(saved, "Meal"); + + return saved; }, async currentUser() { if (user) { @@ -139,7 +188,10 @@ export default { method: "DELETE", credentials: "include", }); - return await response.json(); + + const recipe = await response.json(); + fixDates(recipe, "Recipe"); + return recipe; }, async searchPerson(name) { const response = await fetch(BASE_URL + "/persons?q=" + encodeURIComponent(name)); @@ -147,7 +199,10 @@ export default { }, async getMyShoppingList() { const response = await fetch(BASE_URL + "/shopping/current/me/ingredients", { credentials: "include" }); - return await response.json(); + const requests = await response.json(); + fixDates(requests, "ShoppingListRequest"); + + return requests; }, async saveMyShoppingList(list) { const response = await fetch(BASE_URL + "/shopping/current/me/ingredients", { @@ -159,18 +214,22 @@ export default { body: JSON.stringify(list), }); - return await response.json(); + const requests = await response.json(); + fixDates(requests, "ShoppingListRequest"); + + return requests; }, async getShoppingList(id) { const response = await fetch(BASE_URL + `/shopping/${encodeURIComponent(id)}`); - return await response.json(); + + const lst = await response.json(); + fixDates(lst, "ShoppingList"); + return lst; }, async getCurrentShoppingList() { 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"); + fixDates(lst, "ShoppingList"); return lst; }, @@ -184,9 +243,10 @@ export default { body: JSON.stringify({ meal_id }), }); - const result = await response.json(); - fixMealDates([result.meal]); - return result; + const requests = await response.json(); + fixDates(requests, "ShoppingListRequest"); + + return requests; }, async unrequestMeal(meal_id) { const response = await fetch(BASE_URL + `/shopping/current/meals/${encodeURIComponent(meal_id)}`, { @@ -194,7 +254,8 @@ export default { credentials: "include", }); - return await response.json(); + const requests = await response.json(); + fixDates(requests, "ShoppingListRequest"); }, async markFound(ingredients) { const response = await fetch(BASE_URL + "/shopping/current/found", { @@ -207,8 +268,9 @@ export default { }); const results = await response.json(); - fixResultDates(results.created); - fixResultDates(results.removed); + fixDates(results.created, "ShoppingListResult"); + fixDates(results.removed, "ShoppingListResult"); + return results; }, async markNotFound(product_id) { @@ -217,8 +279,20 @@ export default { credentials: "include", }); - const results = await response.json(); - fixResultDates(results); - return results; + const removedResults = await response.json(); + fixDates(removedResults, "ShoppingListResult"); + + return removedResults; + }, + async markCurrentShoppingListPurchased() { + const response = await fetch(BASE_URL + "/shopping/current/purchased", { + method: "POST", + credentials: "include", + }); + + const lst = await response.json(); + fixDates(lst, "ShoppingList"); + + return lst; } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index 4d692de..11fadfb 100644 --- a/src/main.js +++ b/src/main.js @@ -7,7 +7,8 @@ import LoginPage from './components/LoginPage.vue' import RecipesPage from './components/recipes/RecipesPage.vue' import MealPlanPage from './components/meals/MealPlanPage.vue' import MyShoppingPage from './components/shopping/MyShoppingPage.vue' -import FullShoppingListPage from './components/shopping/FullShoppingListPage.vue' +import PurchasedShoppingListPage from './components/shopping/PurchasedShoppingListPage.vue' +import CurrentShoppingListPage from './components/shopping/CurrentShoppingListPage.vue' import EditMealPage from './components/meals/EditMealPage.vue' import EditRecipePage from './components/recipes/EditRecipePage.vue' @@ -19,7 +20,8 @@ const routes = [ { path: '/mealplan', component: MealPlanPage }, { path: '/login', component: LoginPage }, { path: '/shopping', component: MyShoppingPage }, - { path: '/shopping/:id', component: FullShoppingListPage, props : true }, + { path: '/shopping/current', component: CurrentShoppingListPage }, + { path: '/shopping/:id', component: PurchasedShoppingListPage, props : true }, { path: '/recipes', component: RecipesPage }, { path: '/recipes/add', component: EditRecipePage }, { path: '/recipes/:id', component: EditRecipePage, props: true },