107 lines
2.9 KiB
TypeScript
107 lines
2.9 KiB
TypeScript
import axios from 'axios';
|
|
import { API_URLS, BASE_URL } from './URLs';
|
|
|
|
import { getToken } from '@/hooks/storage.native';
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
import { router } from 'expo-router';
|
|
|
|
const httpClient = axios.create({
|
|
baseURL: BASE_URL,
|
|
timeout: 60000,
|
|
});
|
|
|
|
httpClient.interceptors.request.use(async (config) => {
|
|
const token = await getToken();
|
|
const lang = await AsyncStorage.getItem('lang');
|
|
|
|
config.headers['Accept-Language'] = lang;
|
|
|
|
if (token) {
|
|
config.headers.Authorization = `Bearer ${token}`;
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
let isRefreshing = false;
|
|
let failedQueue: Array<{ resolve: (value: any) => void; reject: (reason?: any) => void }> = [];
|
|
|
|
const processQueue = (error: any = null) => {
|
|
failedQueue.forEach((prom) => {
|
|
if (error) {
|
|
prom.reject(error);
|
|
} else {
|
|
prom.resolve(null);
|
|
}
|
|
});
|
|
failedQueue = [];
|
|
};
|
|
|
|
httpClient.interceptors.response.use(
|
|
(response) => response,
|
|
|
|
async (error) => {
|
|
const originalRequest = error.config;
|
|
|
|
// Agar 401 bo'lsa va bu refresh so'rovi bo'lmasa
|
|
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
if (isRefreshing) {
|
|
// Agar allaqachon refresh ketayotgan bo'lsa → kutamiz
|
|
return new Promise((resolve, reject) => {
|
|
failedQueue.push({ resolve, reject });
|
|
})
|
|
.then(() => httpClient(originalRequest))
|
|
.catch((err) => Promise.reject(err));
|
|
}
|
|
|
|
originalRequest._retry = true;
|
|
isRefreshing = true;
|
|
|
|
try {
|
|
const refresh = await AsyncStorage.getItem('refresh_token');
|
|
|
|
if (!refresh) {
|
|
throw new Error('Refresh token mavjud emas');
|
|
}
|
|
|
|
// Refresh token so'rovi
|
|
const { data } = await axios.post(`${BASE_URL}${API_URLS.REFRESH}`, {
|
|
refresh, // backend odatda { refresh } body kutadi
|
|
});
|
|
|
|
// Yangi tokenlarni saqlaymiz
|
|
await AsyncStorage.setItem('access_token', data.access);
|
|
await AsyncStorage.setItem('refresh_token', data.refresh || refresh); // agar yangi refresh kelmasa, eskisini saqlab qolamiz
|
|
|
|
// Headerni yangilaymiz
|
|
originalRequest.headers.Authorization = `Bearer ${data.access}`;
|
|
|
|
// Kutgan so'rovlarni qayta yuboramiz
|
|
processQueue();
|
|
|
|
// Original so'rovni qayta yuboramiz
|
|
return httpClient(originalRequest);
|
|
} catch (refreshError) {
|
|
console.error('Refresh token xatosi:', refreshError);
|
|
|
|
// Refresh muvaffaqiyatsiz bo'lsa
|
|
processQueue(refreshError);
|
|
|
|
// Tokenlarni o'chirib, logout qilamiz
|
|
await AsyncStorage.removeItem('access_token');
|
|
await AsyncStorage.removeItem('refresh_token');
|
|
|
|
// Foydalanuvchini login sahifasiga yo'naltiramiz
|
|
router.replace('/');
|
|
} finally {
|
|
isRefreshing = false;
|
|
}
|
|
}
|
|
|
|
// Boshqa xatolar uchun oddiy reject
|
|
return Promise.reject(error);
|
|
}
|
|
);
|
|
|
|
export default httpClient;
|