File size: 7,127 Bytes
d97b8f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { API_BASE_URL } from '../../config';
import { getSystemHealth } from './health';

// Mobile platform detection (simpler approach without Capacitor dependency)
const isMobileApp = () => {
  return typeof window !== 'undefined' && 
    (window.location.href.includes('capacitor://') || 
     window.location.href.includes('ionic://') ||
     /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
};

const isNative = isMobileApp();

// Create a custom axios instance
const apiClient = axios.create({
  baseURL: API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
    // Add additional headers for mobile apps
    ...(isNative && {
      'X-Requested-With': 'XMLHttpRequest',
      'X-Mobile-App': 'true'
    })
  },
  timeout: 30000, // 30 seconds timeout
  withCredentials: false // Disable withCredentials which can cause CORS issues
});

// Request interceptor to handle authentication for all requests
apiClient.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // Get token from user_session in localStorage
    const userSession = localStorage.getItem('user_session');
    
    // Add detailed debugging
    console.log(`API Request to: ${config.url}`);
    console.log(`Method: ${config.method?.toUpperCase()}`);
    console.log(`Running on platform: ${isNative ? 'Mobile' : 'Web'}`);
    
    // If session exists, parse it and add token to headers
    if (userSession) {
      try {
        const userData = JSON.parse(userSession);
        console.log(`User session found: ${userData.firstName} ${userData.lastName} (${userData.email})`);
        
        if (userData && userData.token) {
          // Set Authorization header for all requests
          config.headers.Authorization = `Bearer ${userData.token}`;
          console.log(`Token applied: ${userData.token.substring(0, 15)}...`);
        } else {
          console.warn('Token missing in user session! Session data:', JSON.stringify(userData, null, 2));
        }
      } catch (error) {
        console.error('Error parsing user session:', error);
      }
    } else {
      console.warn('No user_session found in localStorage - request will be unauthorized');
    }
    
    // Log final headers for debugging
    // console.log('Request headers:', JSON.stringify(config.headers, null, 2));
    // console.log('Request URL (full):', `${config.baseURL}${config.url}`);
    
    return config;
  },
  (error: AxiosError) => {
    // Handle request errors
    console.error('Request error:', error);
    return Promise.reject(error);
  }
);

// Special interceptor for the health endpoint
apiClient.interceptors.response.use(
  (response: AxiosResponse) => {
    const url = response.config.url;
    
    // Check if this is a health endpoint request
    if (url && (url === '/health' || url.endsWith('/health') || url === '/api/health' || url.endsWith('/api/health'))) {
      console.log('Health endpoint detected, returning custom health response');
      
      // Use the shared health implementation from health.ts
      response.data = getSystemHealth();
    }
    
    return response;
  },
  (error) => Promise.reject(error)
);

// Response interceptor to handle authentication-related responses
apiClient.interceptors.response.use(
  (response: AxiosResponse) => {
    // Any status code within the range of 2xx causes this function to trigger
    return response;
  },
  async (error: AxiosError) => {
    const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
    
    // Handle 401 Unauthorized errors
    if (error.response?.status === 401 && !originalRequest._retry) {
      // Since we're using user_session, update refresh token logic accordingly
      const userSession = localStorage.getItem('user_session');
      
      if (userSession) {
        originalRequest._retry = true;
        
        try {
          // Here you could implement token refresh logic
          // Example (commented out):
          /*

          const userData = JSON.parse(userSession);

          // Call your refresh token API

          const response = await apiClient.post(

            `${API_BASE_URL}/auth/refresh-token`,

            { 

              userId: userData.userId,

              // Include any other required fields

            },

            { 

              headers: { 

                'Content-Type': 'application/json'

              }

            }

          );

          

          if (response.data && response.data.token) {

            // Update the token in localStorage

            userData.token = response.data.token;

            localStorage.setItem('user_session', JSON.stringify(userData));

            

            // Retry the original request with new token

            originalRequest.headers.Authorization = `Bearer ${response.data.token}`;

            return apiClient(originalRequest);

          }

          */
          
          // For now, just clear the session and redirect to login
          localStorage.removeItem('user_session');
          
          // Redirect to login page
          window.location.href = '/login';
          
          return Promise.reject(error);
        } catch (refreshError) {
          // If any error during this process, clear session and redirect
          localStorage.removeItem('user_session');
          
          // Redirect to login page
          window.location.href = '/login';
          
          return Promise.reject(refreshError);
        }
      } else {
        // No session available, redirect to login
        window.location.href = '/login';
      }
    }
    
    // Handle 403 Forbidden errors (permissions issue)
    if (error.response?.status === 403) {
      console.error('Forbidden resource:', error.config?.url);
      // You can implement specific handling for forbidden resources
      // For example, show an access denied notification or redirect
      // window.location.href = '/access-denied';
    }
    
    // Handle 404 Not Found errors
    if (error.response?.status === 404) {
      console.error('Resource not found:', error.config?.url);
    }
    
    // Handle 500 and other server errors
    if (error.response?.status && error.response.status >= 500) {
      console.error('Server error:', error.response.status, error.config?.url);
      // Optionally show a server error notification
    }
    
    // Network errors
    if (error.message === 'Network Error') {
      console.error('Network error - check internet connection');
      // Optionally show a network error notification
    }
    
    // Timeout errors
    if (error.code === 'ECONNABORTED') {
      console.error('Request timeout');
      // Optionally show a timeout error notification
    }
    
    return Promise.reject(error);
  }
);

export default apiClient;