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 they clicked on 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 addAccount: async (request) => { const authStore = useAuthStore(); 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) => { 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) => { 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) => { 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. "); }) }, //returns fridgeItem of specific id getFridgeItem: async (id) =>{ const authStore = useAuthStore(); axios.get(`${import.meta.env.VITE_BACKEND_URL}/fridge/${id}`, { headers: { Authorization: `Bearer ${authStore.token}` }, }) .then((response) => { return response.data; }) .catch(() => { throw new Error("Could not fetch fridge item"); }); }, }