const BASE_URL = window.location.href.replace(/^(https?:\/\/[^/]+).*/, "$1/api"); const datesToFix = { Meal: { fields: [ "suggested_date", "purchase_date", "consumed_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); } } } } let user = null; export default { async markMealConsumed(meal_id) { const response = await fetch(BASE_URL + `/meals/${encodeURIComponent(meal_id)}/consumed`, { method: "POST", credentials: "include", }); const meal = await response.json(); fixDates(meal, "Meal"); return meal; }, async getUpcomingMeals(from, to) { const response = await fetch(BASE_URL + "/meals/upcoming?from=" + from.toISOString() + "&to=" + to.toISOString()); const meals = await response.json(); fixDates(meals, "Meal"); return meals.sort((a, b) => a.suggested_date - b.suggested_date); }, async getMeal(id) { var response = await fetch(BASE_URL + `/meals/${encodeURIComponent(id)}`); 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)); 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" }); const recipe = await response.json(); fixDates(recipe, "Recipe"); return recipe; }, async getRecipe(id) { const response = await fetch(BASE_URL + `/recipes/${encodeURIComponent(id)}`); const recipe = await response.json(); fixDates(recipe, "Recipe"); return recipe; }, async parseProduct(ingredient, url) { const body = { url, tags: [ingredient.name, ingredient.line], }; const response = await fetch(BASE_URL + "/products", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); return await response.json(); }, async parseIngredients(lines) { const params = lines.map(line => "ingredients=" + encodeURIComponent(line)).join("&"); const response = await fetch(BASE_URL + "/recipes/ingredients/parse?" + params); return await response.json(); }, async saveRecipe(recipe) { const response = await fetch(BASE_URL + "/recipes", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(recipe), }); const saved = await response.json(); fixDates(saved, "Recipe"); return saved; }, async saveMeal(meal) { let response = null; if (meal.id >= 0) { response = await fetch(BASE_URL + `/meals/${encodeURIComponent(meal.id)}`, { method: "PUT", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(meal), }); } else { response = await fetch(BASE_URL + "/meals", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(meal), }); } const saved = await response.json(); fixDates(saved, "Meal"); return saved; }, async currentUser() { if (user) { return user; } var cookie = decodeURIComponent(document.cookie).split(";").find(cookie => cookie.trimStart().startsWith("user_id=")); if (cookie) { const response = await fetch(BASE_URL + "/auth/refresh", { method: "POST", credentials: "include", }); if (response.ok) { user = await response.json(); } } return user; }, async login(username) { const response = await fetch(BASE_URL + "/auth/login", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username }), }); if (response.ok) { user = await response.json(); } return user; }, async deleteRecipe(id) { var response = await fetch(BASE_URL + `/recipes/${encodeURIComponent(id)}`, { method: "DELETE", credentials: "include", }); const recipe = await response.json(); fixDates(recipe, "Recipe"); return recipe; }, async searchPerson(name) { const response = await fetch(BASE_URL + "/persons?q=" + encodeURIComponent(name)); return await response.json(); }, async getMyShoppingList() { const response = await fetch(BASE_URL + "/shopping/current/me/ingredients", { credentials: "include" }); const requests = await response.json(); fixDates(requests, "ShoppingListRequest"); return requests; }, async saveMyShoppingList(list) { const response = await fetch(BASE_URL + "/shopping/current/me/ingredients", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(list), }); const requests = await response.json(); fixDates(requests, "ShoppingListRequest"); return requests; }, async getShoppingList(id) { const response = await fetch(BASE_URL + `/shopping/${encodeURIComponent(id)}`); 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(); fixDates(lst, "ShoppingList"); return lst; }, async requestMeal(meal_id) { const response = await fetch(BASE_URL + `/shopping/current/meals/me`, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ meal_id }), }); 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)}`, { method: "DELETE", credentials: "include", }); const requests = await response.json(); fixDates(requests, "ShoppingListRequest"); }, async markFound(ingredients) { const response = await fetch(BASE_URL + "/shopping/current/found", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(ingredients), }); const results = await response.json(); fixDates(results.created, "ShoppingListResult"); fixDates(results.removed, "ShoppingListResult"); return results; }, async markNotFound(product_id) { const response = await fetch(BASE_URL + `/shopping/current/found/${product_id}`, { method: "DELETE", credentials: "include", }); 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; }, async getPersonsInHome() { const response = await fetch(BASE_URL + "/persons"); return await response.json(); } }