feat: Implement a structured API service layer for authentication and user management, replacing the old API utility.

This commit is contained in:
pradeepkumar
2025-12-22 11:53:38 +05:30
parent aa97e36cfd
commit c4ccb2bd6c
10 changed files with 469 additions and 198 deletions

View File

@@ -1,147 +0,0 @@
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api/v1';
interface ApiResponse<T> {
success: boolean;
data: T;
message?: string;
}
interface LoginResponse {
user: {
id: string;
email: string;
role: string;
firstName: string;
lastName: string;
avatar: string | null;
};
accessToken: string;
refreshToken: string;
}
interface User {
id: string;
email: string;
role: string;
status: string;
emailVerified: boolean;
authProvider: string;
createdAt: string;
lastLoginAt: string | null;
profile: {
firstName: string;
lastName: string;
avatar: string | null;
phone: string | null;
city: string | null;
state: string | null;
country: string | null;
} | null;
}
class ApiClient {
private baseUrl: string;
constructor() {
this.baseUrl = API_URL;
}
private getToken(): string | null {
if (typeof window === 'undefined') return null;
return localStorage.getItem('accessToken');
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<ApiResponse<T>> {
const token = this.getToken();
const headers: HeadersInit = {
'Content-Type': 'application/json',
...(token && { Authorization: `Bearer ${token}` }),
...options.headers,
};
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers,
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'An error occurred');
}
return data;
}
async login(email: string, password: string): Promise<LoginResponse> {
const response = await this.request<LoginResponse>('/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password }),
});
// Check if user is ADMIN
if (response.data.user.role !== 'ADMIN') {
throw new Error('Access denied. Admin privileges required.');
}
// Store tokens
localStorage.setItem('accessToken', response.data.accessToken);
localStorage.setItem('refreshToken', response.data.refreshToken);
localStorage.setItem('user', JSON.stringify(response.data.user));
return response.data;
}
async logout(): Promise<void> {
try {
await this.request('/auth/logout', { method: 'POST' });
} finally {
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
localStorage.removeItem('user');
}
}
async getCurrentUser(): Promise<User> {
const response = await this.request<User>('/auth/me');
return response.data;
}
async getUsers(page = 1, limit = 10): Promise<{ users: User[]; total: number; page: number; limit: number }> {
const response = await this.request<{ users: User[]; total: number; page: number; limit: number }>(
`/users?page=${page}&limit=${limit}`
);
return response.data;
}
async refreshToken(): Promise<{ accessToken: string; refreshToken: string }> {
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) {
throw new Error('No refresh token available');
}
const response = await fetch(`${this.baseUrl}/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Failed to refresh token');
}
localStorage.setItem('accessToken', data.data.accessToken);
localStorage.setItem('refreshToken', data.data.refreshToken);
return data.data;
}
}
export const api = new ApiClient();
export type { User, LoginResponse };