import { defineBoot } from "#q-app/wrappers"; import { Cookies, Notify } from "quasar"; import axios from "axios"; import { useRouter } from "vue-router"; import { useAuth } from "src/composables/useAuth"; import { userStore } from "src/stores/user"; const api = axios.create({ baseURL: process.env.API_URL + "/api", withCredentials: true, }); api.interceptors.request.use( async (config) => { const accessToken = userStore().accessToken; const savedLanguage = Cookies.get("locale"); const language = savedLanguage || window.navigator.language; config.headers["Accept-Language"] = language; if (accessToken) { config.headers.Authorization = `Bearer ${accessToken}`; } return config; }, (error) => { return Promise.reject(error); }, ); let isRefreshing = false; let failedQueue = []; const processQueue = (error, token = null) => { failedQueue.forEach((prom) => { if (error) { prom.reject(error); } else { prom.config.headers["Authorization"] = "Bearer " + token; prom.resolve(api(prom.config)); } }); failedQueue = []; }; const errorInterceptor = async (error, router) => { const originalRequest = error.config; const user_store = userStore(); if (error.response?.status === 422) { if (error.response?.data?.error === "missing_payment_data") { Notify.create({ message: error.response.data.message, type: "negative", }); router.push({ name: "ProfilePage" }); } return Promise.reject(error); } if ( error.response?.status !== 401 || originalRequest.url.includes("/refresh") ) { Notify.create({ message: error?.response?.data?.message ?? error.message, type: "negative", }); return Promise.reject(error); } if (error?.config?.url === "/login") { Notify.create({ message: error.response.data.message, type: "negative", }); return Promise.reject(error); } if (isRefreshing) { return new Promise((resolve, reject) => { failedQueue.push({ resolve, reject, config: originalRequest }); }); } isRefreshing = true; try { const response = await useAuth().refresh(); const newAccessToken = response.data.payload.access_token; user_store.accessToken = newAccessToken; originalRequest.headers["Authorization"] = `Bearer ${newAccessToken}`; processQueue(null, newAccessToken); return api(originalRequest); } catch (err) { processQueue(err, null); await useAuth().clearAuthData(); router.push("/login"); return Promise.reject(err); } finally { isRefreshing = false; } }; const successInterceptor = (response) => { if (response.data.message) { Notify.create({ message: response.data.message, type: "positive", }); } return response; }; export default defineBoot(({ app }) => { const router = useRouter(); api.interceptors.response.use( (response) => successInterceptor(response), (error) => errorInterceptor(error, router), ); // for use inside Vue files (Options API) through this.$axios and this.$api app.config.globalProperties.$axios = axios; // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) // so you won't necessarily have to import axios in each vue file app.config.globalProperties.$api = api; // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) // so you can easily perform requests against your app's API }); export { api };