feat(authentication): implement frontend authentication system
- Created auth and user types (T10) - Implemented API client with token handling (T11) - Built AuthContext with JWT decoding (T12) - Added ProtectedRoute component (T13) - Created LoginPage, RegisterPage, DashboardPage (T14-T16) - Updated App.tsx with routing and auth provider (T17) - Added Dockerfile, nginx.conf for frontend deployment (T18-T19) - Updated docker-compose.yml to include frontend service (T20) - Updated .gitignore to exclude frontend build artifacts (T21) - Removed unused App.css (T22) Refs #2
This commit is contained in:
58
Frontend/src/api/client.ts
Normal file
58
Frontend/src/api/client.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { LoginRequest, RegisterRequest, AuthResponse, RegisterResponse } from '../types/auth';
|
||||
import { User } from '../types/user';
|
||||
|
||||
const API_URL = import.meta.env.VITE_API_URL || '';
|
||||
|
||||
class ApiClient {
|
||||
private async request<T>(input: RequestInfo, init?: RequestInit): Promise<T> {
|
||||
const token = localStorage.getItem('token');
|
||||
|
||||
const headers = new Headers(init?.headers);
|
||||
if (token) {
|
||||
headers.set('Authorization', `Bearer ${token}`);
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_URL}${input}`, {
|
||||
...init,
|
||||
headers,
|
||||
});
|
||||
|
||||
// Handle 401 Unauthorized - clear token and redirect to login
|
||||
if (response.status === 401) {
|
||||
localStorage.removeItem('token');
|
||||
window.location.href = '/login';
|
||||
throw new Error('Unauthorized');
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `Error ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async login(data: LoginRequest): Promise<AuthResponse> {
|
||||
return this.request<AuthResponse>('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async register(data: RegisterRequest): Promise<RegisterResponse> {
|
||||
return this.request<RegisterResponse>('/api/auth/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
async getUsers(): Promise<User[]> {
|
||||
return this.request<User[]>('/api/users', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient();
|
||||
Reference in New Issue
Block a user