import axios from "axios"; import { useAuthStore } from "@/stores/authStore.js"; import jwt_decode from "jwt-decode"; import router from "@/router/index"; export const API = { /** * API method to send a login request. * If login succeeds, the logged in User and their token * is saved to the Pinia AuthStore * * @param email email address of the user to log in as * @param password password to log in with * @returns a Result with whether the login attempt succeeded */ login: async (request) => { const authStore = useAuthStore(); let token; authStore.logout(); //in case someone for some reason is logged in return axios.post( `${import.meta.env.VITE_BACKEND_URL}/login`, request, ) .then(async (response) => { token = response.data; const id = (jwt_decode(token)).id; return API.getAccount(id, token) .then((user) => { authStore.setAccount(user); authStore.setToken(token); API.getProfiles() .then(response => { authStore.setProfiles(response) }) .catch(() => { throw new Error() }) return; }) .catch(() => { throw new Error(); }); }) .catch(() => { throw new Error(); }); }, /** * API method to get a account by their ID * @param id ID number of the account to retrieve * @returns A promise that resolves to a User if the API call succeeds, * or is rejected if the API call fails */ getAccount: async (id, token) => { return axios.get(`${import.meta.env.VITE_BACKEND_URL}/account/${id}`, { headers: { Authorization: `Bearer ${token}` }, }) .then((response) => { return response.data; }) .catch(() => { throw new Error("Account not found or not accessible"); }); }, /** * Sends the user into the home page logged in as the profile specified * @param id ID of the profile that the user will log in as */ selectProfile: async (id) => { const authStore = useAuthStore() return axios.get(`${import.meta.env.VITE_BACKEND_URL}/profile/${id}`, { headers: { Authorization: `Bearer ${authStore.token}` }, }) .then((response) => { authStore.setProfile(response.data) if (!response.data.restricted) { router.push('pincode') } else { router.push("/") } }) .catch(() => { throw new Error("Profile not found or not accessible") }) }, /** * Upload profile image * * @param {Blob} image - the image file contents to upload. Must be a JPEG no bigger than 512kB * @param {Number} profileId - the ID of the profile to upload this image to * @returns {Promise<String>} A Promise that resolves to the URL of the uploaded image */ uploadProfileImage: async (image, profileId) => { const authStore = useAuthStore(); let fd = new FormData(); fd.append("file", image); fd.append("profileId", profileId); return axios.post(`${import.meta.env.VITE_BACKEND_URL}/img`, fd, { headers: { Authorization: `Bearer ${authStore.token}`, } }) .then((response) => { return response.data; }) .catch(() => { throw new Error(); }) }, /** * Sends a request to create a new profile on the currently logged in account * * @typedef {{name: string, id?: number, accountId?: number, profileImageUrl: string, isRestricted: boolean}} ProfileType * @param {ProfileType} profile - the partial data of profile to create * @returns {Promise<ProfileType>} the full profile after saving, with id and account ID set */ addProfile: async (profile) => { const authStore = useAuthStore(); if (!authStore.isLoggedIn) { throw new Error(); } return axios.post(import.meta.env.VITE_BACKEND_URL + '/profile', profile, { headers: { Authorization: "Bearer " + authStore.token }, }) .then((response) => { return response.data; }).catch(() => { throw new Error(); }) }, /** * @returns all profiles to the logged in user */ getProfiles: async () => { const authStore = useAuthStore(); if (!authStore.isLoggedIn) { throw new Error(); } return axios.get(import.meta.env.VITE_BACKEND_URL + '/profile', { headers: { Authorization: "Bearer " + authStore.token }, }, ) .then(response => { return response.data }).catch(() => { throw new Error(); }); }, /** * Registers a new account and logs into it * @param email the email of the new account * @param password the password of the new account */ addAccount: async (request) => { axios.post(import.meta.env.VITE_BACKEND_URL + '/account', request) .then(() => { API.login({email: request.email, password: request.password}) .catch(err => {console.log(err)}) }) .catch(() => {throw new Error()}) }, /** * fetches all fridge items belonging to the user that is currently logged in * @returns {Promise<*>} */ getFridgeItems: async () =>{ const authStore = useAuthStore(); return axios.get(`${import.meta.env.VITE_BACKEND_URL}/fridge`, { headers: { Authorization: `Bearer ${authStore.token}` }, }) .then((response) => { authStore.setFridge(response.data) return response.data; }).catch(() => { throw new Error("Could not fetch fridge items"); }); }, /** * Adds item(s) to the fridge * @param request List<Ingredient> listOfIngredients * @returns {Promise<void>} */ addToFridge: async(request) =>{ const authStore = useAuthStore(); axios.post(`${import.meta.env.VITE_BACKEND_URL}/fridge/items`, request,{ headers: { Authorization: `Bearer ${authStore.token}` }, }).then((response) => { authStore.setFridge(response.data) return response.data; }).catch(()=> { throw new Error("Could not add item to fridge: "); }) }, /** * Searches for registered items. * @param searchPhrase Name of the item that one is looking for (e.g: "purre") * @returns {Promise<*>} list containing items that match the search phrase */ searchItems: async(searchPhrase)=> { return axios.get(`${import.meta.env.VITE_BACKEND_URL}/item/search?name=${searchPhrase}`, { }).then((response) => { console.log(response.data.content); return response.data.content; }).catch(()=> { throw new Error("Error when searching for item "); }) }, /** * Removes an amount of an ingredient from the frodge, and the action is then logged * @param request Log.Action action, Map<Integer, Amount> * Action available: CONSUMED, DISCARDED,ADDED_TO_FRIDGE * @returns {Promise<void>} */ updateFridge: async(request) => { const authStore = useAuthStore(); axios.put(`${import.meta.env.VITE_BACKEND_URL}/fridge/ingredientsAmount`, request,{ headers: { Authorization: `Bearer ${authStore.token}` }, }).then((response) => { authStore.setFridge(response.data); return response.data; }).catch(()=> { throw new Error("Could modify ingredient. "); }) }, /** * Changes the expiration date of an ingredient. * @param request ingredientId: id of the ingredient, newExpDate: the new expiration date of the ingredient * @returns {Promise<void>} */ changeExpirationOfIngredient: async(request) => { const authStore = useAuthStore(); axios.put(`${import.meta.env.VITE_BACKEND_URL}/fridge/ingredient`, request,{ headers: { Authorization: `Bearer ${authStore.token}` }, }).then((response) => { return response.data; }).catch(()=> { throw new Error("Could modify ingredient. "); }) }, /** * Getter for the shopping list of a logged in account * @returns a promise that resolves to an array of Ingredient objects representing the shopping list, or an error if it fails */ getShoppingList: async () => { const authStore = useAuthStore(); return axios.get(import.meta.env.VITE_BACKEND_URL + '/shoppinglist', { headers: { Authorization: "Bearer " + authStore.token }, }) .then((response) => { authStore.setItems(response.data) return response.data }) .catch(() => {throw new Error()}) }, /** * Adds an item to the logged in account's shopping list * @param itemId the id of the item that will be added * @param amount the amount of the specified item that will be added */ addItemToShoppingList: async (itemId, amount) => { const authStore = useAuthStore(); return axios.put(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/items/' + itemId + '/' + amount, "", { headers: { Authorization: "Bearer " + authStore.token } }, ) .then(response => { return response.data }) .catch(err => {console.log(err)}) }, /** * Deletes an ingredient(item with amount) from the logged in account's shopping list * @param ingredientId the id of the ingredient that will be removed */ deleteItemFromShoppingList: async (ingredientId) => { const authStore = useAuthStore(); return axios.delete(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/items/' + ingredientId, { headers: {Authorization: "Bearer " + authStore.token } }) .then(response => { return response.data; }) .catch(err => {console.log(err)}) }, /** * Adds a suggestion to the logged in account's shopping list * @param itemId the id of the item that will be suggested * @param amount the amount of the specified item that will be suggested */ addSuggestion: async (itemId, amount) => { const authStore = useAuthStore(); return axios.put(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/suggestions/' + itemId + '/' + amount, "", { headers: { Authorization: "Bearer " + authStore.token } }) .then(response => { return response.data; }) .catch(err => {console.log(err)}) }, /** * Accepts a suggestion and adds it to the shopping list, removing it from the suggestions list * @param id the id of the ingredient that will be added to the list */ acceptSuggestion: async (id) => { const authStore = useAuthStore(); return axios.put(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/suggestions/accept/' + id, "", { headers: { Authorization: "Bearer " + authStore.token } }) .then(response => { return response.data; }) .catch(err => {console.log(err)}) }, /** * Declines a suggestion and removes it from the suggestions list * @param id the id of the ingredient that will be declined */ declineSuggestion: async (id) => { const authStore = useAuthStore(); return axios.delete(import.meta.env.VITE_BACKEND_URL + '/shoppinglist/suggestions/' + id, { headers: { Authorization: "Bearer " + authStore.token } }) .then(response => { return response.data; }) .catch(err => {console.log(err)}) }, // addIngredientsToFridge: async (ingredientIds) => { // const authStore = useAuthStore(); // return axios.delete(`${import.meta.env.VITE_BACKEND_URL}/shoppinglist/purchased`, { // headers: { Authorization: `Bearer ${authStore.token}`}, // data: { ingredientIds } // }) // .then((response) => {return response.data}) // .catch(err => {console.log(err)}) // }, addIngredientsToFridge: async (ingredients) => { const authStore = useAuthStore(); return axios.put(`${import.meta.env.VITE_BACKEND_URL}/shoppinglist/purchased`, ingredients, { headers: { Authorization: `Bearer ${authStore.token}`} }) .then((response) => {return response.data}) .catch(err => {console.log(err)}) }, /** * Get recipe based on id * @param id * @returns {Promise<*>} */ getRecipe: async (id) => { return axios.get(`${import.meta.env.VITE_BACKEND_URL}/recipe/${id}`) .then((response) => { console.log(response.data); return response.data; }) .catch((error) => { throw new Error(error); }) } }