Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 36x 36x 70x 70x 1x 36x 70x 70x 47x 70x 70x 4x 70x 70x 2x 70x 36x 48x 22x 22x 12x 12x 12x 12x 7x 4x 4x 4x 4x 4x 4x 3x 3x 3x 3x 3x 3x 3x 3x 3x 15x | /**
* API Client
* Axios instance configured for SmoothSchedule API
*/
import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios';
import { API_BASE_URL, getSubdomain } from './config';
import { getCookie } from '../utils/cookies';
// Create axios instance
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json',
},
withCredentials: true, // For CORS with credentials
});
/**
* Get sandbox mode from localStorage
* This is set by the SandboxContext when mode changes
*/
const getSandboxMode = (): boolean => {
try {
return localStorage.getItem('sandbox_mode') === 'true';
} catch {
return false;
}
};
// Request interceptor - add auth token, business subdomain, and sandbox mode
apiClient.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// Add business subdomain header if on business site
const subdomain = getSubdomain();
if (subdomain && subdomain !== 'platform') {
config.headers['X-Business-Subdomain'] = subdomain;
}
// Add auth token if available (from cookie)
const token = getCookie('access_token');
if (token) {
// Use 'Token' prefix for Django REST Framework Token Authentication
config.headers['Authorization'] = `Token ${token}`;
}
// Add sandbox mode header if in test mode
const isSandbox = getSandboxMode();
if (isSandbox) {
config.headers['X-Sandbox-Mode'] = 'true';
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Response interceptor - handle errors and token refresh
apiClient.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
// Handle 401 Unauthorized - token expired
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
// Try to refresh token (from cookie)
const refreshToken = getCookie('refresh_token');
if (refreshToken) {
const response = await axios.post(`${API_BASE_URL}/auth/refresh/`, {
refresh: refreshToken,
});
const { access } = response.data;
// Import setCookie dynamically to avoid circular dependency
const { setCookie } = await import('../utils/cookies');
setCookie('access_token', access, 7);
// Retry original request with new token
Eif (originalRequest.headers) {
originalRequest.headers['Authorization'] = `Bearer ${access}`;
}
return apiClient(originalRequest);
}
} catch (refreshError) {
// Refresh failed - clear tokens and redirect to login on root domain
const { deleteCookie } = await import('../utils/cookies');
const { getBaseDomain } = await import('../utils/domain');
deleteCookie('access_token');
deleteCookie('refresh_token');
const protocol = window.location.protocol;
const baseDomain = getBaseDomain();
const port = window.location.port ? `:${window.location.port}` : '';
window.location.href = `${protocol}//${baseDomain}${port}/login`;
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default apiClient;
|