Files
road-monitoring-ui/src/services/axios/axios.ts

118 lines
2.8 KiB
TypeScript

import { ENV_CONSTANT } from '@/constants/secrect.constant';
import { useAppStore } from '@/store/app.store';
import { useAuthStore } from '@/store/auth.store';
import axios from 'axios';
const BASE_URL = ENV_CONSTANT.BASE_API_URL;
const axiosClient = axios.create({
baseURL: BASE_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
});
export const axiosAuth = axios.create({
baseURL: BASE_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
});
let refreshPromise: Promise<string> | null = null;
const isInvalidSessionResponse = (error: unknown) => {
if (!axios.isAxiosError(error)) return false;
return error.response?.status === 401 || error.response?.status === 403;
};
const refreshAccessToken = () => {
if (!refreshPromise) {
refreshPromise = axiosAuth
.post('api/auth/refresh', {})
.then((response) => {
const accessToken = response.data?.access_token;
if (!accessToken) {
throw new Error('Refresh failed: no access token');
}
useAuthStore.getState().setAccessToken(accessToken);
return accessToken;
})
.catch((error: unknown) => {
if (isInvalidSessionResponse(error)) {
useAuthStore.getState().logout();
useAppStore.getState().clear();
if (typeof window !== 'undefined') {
window.location.href = '/login';
}
}
throw error;
})
.finally(() => {
refreshPromise = null;
});
}
return refreshPromise;
};
axiosClient.interceptors.request.use(
(config) => {
const token = useAuthStore.getState().accessToken;
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
axiosClient.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error?.config;
const status = error?.response?.status;
const requestUrl = originalRequest?.url ?? '';
const isAuthRoute =
requestUrl.includes('api/auth/login') ||
requestUrl.includes('api/auth/refresh') ||
requestUrl.includes('api/auth/forget-password') ||
requestUrl.includes('api/auth/reset-password') ||
requestUrl.includes('api/auth/set-password');
if (
status === 401 &&
originalRequest &&
!originalRequest._retry &&
!isAuthRoute
) {
originalRequest._retry = true;
try {
const accessToken = await refreshAccessToken();
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
return axiosClient(originalRequest);
} catch (refreshError) {
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
},
);
export default axiosClient;