File size: 4,932 Bytes
25f22bf
 
 
 
baaf93b
 
 
 
74728f5
 
baaf93b
 
 
25f22bf
baaf93b
25f22bf
 
 
 
 
 
 
 
 
 
baaf93b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74728f5
baaf93b
 
 
 
 
 
 
 
 
25f22bf
baaf93b
25f22bf
 
 
baaf93b
25f22bf
 
 
 
baaf93b
25f22bf
 
baaf93b
 
 
 
 
 
 
 
 
 
25f22bf
 
 
baaf93b
25f22bf
 
baaf93b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25f22bf
baaf93b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25f22bf
 
 
baaf93b
 
 
 
 
 
 
 
 
 
 
 
 
 
25f22bf
 
 
 
 
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import axios from 'axios';
import cookieService from '../services/cookieService';

// Create axios instance with default config
const API_BASE_URL = import.meta.env.VITE_API_URL ||
  (import.meta.env.VITE_NODE_ENV === 'production' ?
    'https://zelyanoth-lin-cbfcff2.hf.space' :
    'http://localhost:5000');
console.log('API_BASE_URL:', API_BASE_URL);

// Ensure API_BASE_URL ends with /api for consistency
const normalizedBaseUrl = API_BASE_URL.endsWith('/api') ? API_BASE_URL : `${API_BASE_URL}/api`;

const apiClient = axios.create({
  baseURL: normalizedBaseUrl,
  timeout: 30000,
  headers: {
    'Content-Type': 'application/json',
  },
  withCredentials: true, // Send cookies with requests
});

// Request interceptor to add auth token
apiClient.interceptors.request.use(
  async (config) => {
    // Enhanced logging for debugging
    const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development';
    if (isDevelopment) {
      console.log('πŸš€ [API Request]', {
        method: config.method?.toUpperCase(),
        url: config.baseURL + config.url,
        headers: config.headers,
        data: config.data
      });
    }
    
    // Get token from cookie service with fallback to localStorage
    let token = null;
    try {
      const tokens = await cookieService.getAuthTokens();
      token = tokens?.accessToken;
    } catch (error) {
      console.warn('πŸͺ [Cookie] Error getting auth tokens, trying localStorage:', error.message);
      token = localStorage.getItem('token');
    }
    
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
      if (isDevelopment) {
        console.log('πŸ”‘ [Token] Added token to request headers');
      }
    } else {
      if (isDevelopment) {
        console.log('πŸ”‘ [Token] No token found for request');
      }
    }
    
    return config;
  },
  (error) => {
    console.error('❌ [API Request Error]', error);
    return Promise.reject(error);
  }
);

// Response interceptor to handle token refresh and errors
apiClient.interceptors.response.use(
  (response) => {
    // Enhanced logging for debugging
    const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development';
    if (isDevelopment) {
      console.log('βœ… [API Response]', {
        status: response.status,
        method: response.config.method?.toUpperCase(),
        url: response.config.baseURL + response.config.url,
        data: response.data
      });
    }
    return response;
  },
  async (error) => {
    const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development';
    const originalRequest = error.config;
    
    // Enhanced error logging
    if (isDevelopment) {
      console.error('❌ [API Response Error]', {
        status: error.response?.status,
        method: originalRequest?.method?.toUpperCase(),
        url: originalRequest ? originalRequest.baseURL + originalRequest.url : 'unknown',
        message: error.message,
        response: error.response?.data,
        headers: error.response?.headers
      });
    }
    
    // Handle 401 Unauthorized errors
    if (error.response?.status === 401) {
      if (isDevelopment) {
        console.log('πŸ” [Auth] 401 error detected, attempting token refresh');
      }
      
      // If we haven't retried this request yet
      if (!originalRequest._retry) {
        originalRequest._retry = true;
        
        try {
          // Clear all authentication data
          await cookieService.clearAuthTokens();
          localStorage.removeItem('token');
          
          if (isDevelopment) {
            console.log('πŸ” [Auth] Cleared all authentication data');
          }
          
          // Redirect to login page
          const currentPath = window.location.pathname;
          if (currentPath !== '/login' && currentPath !== '/register') {
            if (isDevelopment) {
              console.log('πŸ” [Auth] Redirecting to login page');
            }
            window.location.href = '/login';
          }
          
        } catch (refreshError) {
          if (isDevelopment) {
            console.error('πŸ” [Auth] Error during token refresh:', refreshError);
          }
          
          // Even if refresh fails, clear auth data
          await cookieService.clearAuthTokens();
          localStorage.removeItem('token');
          window.location.href = '/login';
          
          return Promise.reject(refreshError);
        }
      }
    }
    
    // Handle network errors
    if (!error.response) {
      if (isDevelopment) {
        console.error('🌐 [Network] No response received:', {
          url: originalRequest?.baseURL + originalRequest?.url,
          message: error.message
        });
      }
      
      // You might want to implement offline mode here
      // For now, just reject the error
      return Promise.reject(error);
    }
    
    return Promise.reject(error);
  }
);

export default apiClient;