Skip to content

Commit 0d6c9f9

Browse files
Revert "Phase2_Day1"
This reverts commit 51b954e.
1 parent 8a867ac commit 0d6c9f9

4 files changed

Lines changed: 49 additions & 81 deletions

File tree

frontend/src/api/auth.ts

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
import apiClient, { ApiResponse, handleApiError } from './index';
22

3-
// Types for login request payload
3+
// Types for auth requests/responses
44
export interface LoginRequest {
55
email: string;
66
password: string;
77
}
88

9-
// Types for registration request payload
109
export interface RegisterRequest {
1110
user_name: string;
1211
user_email: string;
1312
user_password: string;
14-
organizationId?: string; // Optional field
13+
organizationId?: string;
1514
}
1615

17-
// Types for authentication response from backend
1816
export interface AuthResponse {
1917
user: {
2018
id: string;
@@ -26,86 +24,67 @@ export interface AuthResponse {
2624
}
2725

2826
/**
29-
* User login function
30-
* @param credentials - LoginRequest containing email and password
31-
* @returns Promise resolving to AuthResponse containing user info and token
32-
* Stores token in localStorage for subsequent requests
27+
* User login
3328
*/
3429
export const login = async (credentials: LoginRequest): Promise<AuthResponse> => {
3530
try {
36-
// Call login API endpoint with user credentials
3731
const response = await apiClient.post<ApiResponse<AuthResponse>>('/auth/login', credentials);
3832
const { token, user } = response.data.data;
3933

40-
// Save token in localStorage for auth persistence
34+
// Store token for future requests
4135
localStorage.setItem('accessToken', token);
4236

4337
return { token, user };
4438
} catch (error) {
45-
// Handle errors gracefully with helper function
4639
throw new Error(handleApiError(error));
4740
}
4841
};
4942

5043
/**
51-
* User registration function
52-
* @param userData - RegisterRequest containing registration details
53-
* @returns Promise resolving to AuthResponse containing user info and token
54-
* Stores token in localStorage for subsequent requests
44+
* User registration
5545
*/
5646
export const register = async (userData: RegisterRequest): Promise<AuthResponse> => {
5747
try {
58-
// Call register API endpoint with user data
5948
const response = await apiClient.post<ApiResponse<AuthResponse>>('/auth/register', userData);
6049
const { token, user } = response.data.data;
6150

62-
// Save token in localStorage for auth persistence
51+
// Store token for future requests
6352
localStorage.setItem('accessToken', token);
6453

6554
return { token, user };
6655
} catch (error) {
67-
// Handle errors gracefully with helper function
6856
throw new Error(handleApiError(error));
6957
}
7058
};
7159

7260
/**
73-
* User logout function
74-
* Calls logout API endpoint and removes token from localStorage
61+
* User logout
7562
*/
7663
export const logout = async (): Promise<void> => {
7764
try {
78-
// Notify backend about logout
7965
await apiClient.post('/auth/logout');
80-
81-
// Remove token to clear authentication state on client
8266
localStorage.removeItem('accessToken');
8367
} catch (error) {
8468
throw new Error(handleApiError(error));
8569
}
8670
};
8771

8872
/**
89-
* Request password reset email
90-
* @param email - User email to send reset link
73+
* Request password reset
9174
*/
9275
export const forgotPassword = async (email: string): Promise<void> => {
9376
try {
94-
// Call forgot-password API with user email
9577
await apiClient.post('/auth/forgot-password', { email });
9678
} catch (error) {
9779
throw new Error(handleApiError(error));
9880
}
9981
};
10082

10183
/**
102-
* Reset password with reset token and new password
103-
* @param token - Password reset token received via email
104-
* @param newPassword - New password string
84+
* Reset password with token
10585
*/
10686
export const resetPassword = async (token: string, newPassword: string): Promise<void> => {
10787
try {
108-
// Call reset-password API with token and new password
10988
await apiClient.post('/auth/reset-password', { token, newPassword });
11089
} catch (error) {
11190
throw new Error(handleApiError(error));

frontend/src/api/index.ts

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
1+
/**
2+
* Ensures all Promise rejections use proper Error objects
3+
*
4+
* This fix addresses a TypeScript error where Promise rejections were not
5+
* guaranteed to be Error objects. The code now checks if the rejection reason
6+
* is an Error instance and, if not, converts it to an Error object.
7+
*
8+
* Fixed in:
9+
* - Request interceptor error handler
10+
* - Response interceptor error handler
11+
*
12+
* This ensures type safety and better error handling throughout the application.
13+
*/
14+
/**
15+
* TypeScript type declarations for Vite's import.meta.env
16+
*
17+
* These declarations extend the ImportMeta interface to include Vite-specific
18+
* environment variables, resolving the TypeScript error:
19+
* "Property 'env' does not exist on type 'ImportMeta'"
20+
*
21+
* @see https://vitejs.dev/guide/env-and-mode.html#env-files
22+
*/
123
import axios, {
224
AxiosError,
325
AxiosInstance,
4-
AxiosRequestConfig,
26+
AxiosRequestConfig, // Import AxiosRequestConfig
527
AxiosResponse,
628
isAxiosError as axiosIsAxiosError,
729
} from 'axios';
8-
import { useAuthStore } from '../state/authStore'; // Adjust path if needed
930

1031
// TypeScript declaration for Vite env
1132
declare global {
@@ -21,11 +42,11 @@ declare global {
2142

2243
// API base URL - should match your backend
2344
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api';
24-
2545
// Default timeout in milliseconds
2646
const DEFAULT_TIMEOUT = 15000;
2747

28-
// Extend AxiosRequestConfig to add _retry flag for token refresh logic
48+
// Define an interface for the request config with retry flag
49+
// by extending the original AxiosRequestConfig
2950
interface ExtendedAxiosRequestConfig extends AxiosRequestConfig {
3051
_retry?: boolean;
3152
}
@@ -45,7 +66,7 @@ const createApiClient = (): AxiosInstance => {
4566

4667
// Request interceptor - adds auth token to requests
4768
apiClient.interceptors.request.use(
48-
(config) => {
69+
config => {
4970
const token = localStorage.getItem('accessToken');
5071
if (token && config.headers) {
5172
config.headers.Authorization = `Bearer ${token}`;
@@ -55,65 +76,60 @@ const createApiClient = (): AxiosInstance => {
5576
(error: AxiosError) => Promise.reject(error)
5677
);
5778

58-
// Response interceptor - handle 401 errors and token refresh
79+
// Response interceptor - handle common errors
5980
apiClient.interceptors.response.use(
6081
(response: AxiosResponse) => response,
6182
async (error: AxiosError) => {
83+
// Cast error.config to the extended interface
6284
const originalRequest = error.config as ExtendedAxiosRequestConfig;
6385

86+
// Handle 401 Unauthorized errors (expired token)
6487
if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
6588
originalRequest._retry = true;
6689

6790
try {
68-
// Attempt to refresh token
91+
// Call refresh token endpoint
6992
const refreshResponse = await axios.post(
7093
`${API_BASE_URL}/auth/refresh-token`,
7194
{},
72-
{ withCredentials: true }
95+
{
96+
withCredentials: true, // Needed for cookies
97+
}
7398
);
7499

75100
const newToken = refreshResponse.data.token;
76101
localStorage.setItem('accessToken', newToken);
77102

103+
// Retry the original request with new token
78104
if (originalRequest.headers) {
79105
originalRequest.headers.Authorization = `Bearer ${newToken}`;
80106
}
81-
82107
return apiClient(originalRequest);
83108
} catch (refreshError) {
84-
// Refresh token failed - logout user
109+
// If refresh token fails, redirect to login
85110
localStorage.removeItem('accessToken');
86-
const store = useAuthStore.getState();
87-
store.logout();
88-
111+
// Ensure window is defined (for SSR or test environments)
89112
if (typeof window !== 'undefined') {
90113
window.location.href = '/login';
91114
}
92115

116+
// Ensure we reject with an Error object
93117
if (refreshError instanceof Error) {
94118
return Promise.reject(refreshError);
95119
} else if (typeof refreshError === 'string') {
96120
return Promise.reject(new Error(refreshError));
97121
} else {
122+
// For other types, you might want to serialize or provide a generic message
98123
return Promise.reject(
99124
new Error(
100125
`An unknown error occurred during token refresh: ${JSON.stringify(refreshError)}`
101126
)
102127
);
103128
}
104129
}
105-
} else if (error.response?.status === 401) {
106-
// Other 401 errors after retry or no retry - logout user
107-
localStorage.removeItem('accessToken');
108-
const store = useAuthStore.getState();
109-
store.logout();
110-
111-
if (typeof window !== 'undefined') {
112-
window.location.href = '/login';
113-
}
114130
}
115131

116-
return Promise.reject(error);
132+
return Promise.reject(error); // error here is AxiosError, which is an Error instance
117133
}
118134
);
119135

@@ -132,7 +148,7 @@ export interface ApiResponse<T> {
132148
status: number;
133149
}
134150

135-
// Common error handler function
151+
// Common error handler
136152
export const handleApiError = (error: unknown): string => {
137153
if (axiosIsAxiosError(error)) {
138154
const response = error.response;

frontend/src/api/labs.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,3 @@ export const deleteLab = async (labId: string): Promise<void> => {
6464
throw new Error(handleApiError(error));
6565
}
6666
};
67-
68-

frontend/src/state/authStore.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)