109 lines
3.6 KiB
TypeScript
109 lines
3.6 KiB
TypeScript
// Simplified API client that handles all the complexity in one place
|
|
// Use empty string for relative URLs when no API URL is specified
|
|
const API_BASE_URL = import.meta.env.VITE_API_URL || '';
|
|
|
|
class ApiClient {
|
|
private baseURL: string;
|
|
|
|
constructor(baseURL: string) {
|
|
this.baseURL = baseURL;
|
|
}
|
|
|
|
private getAuthHeaders(): HeadersInit {
|
|
const token = localStorage.getItem('authToken');
|
|
return {
|
|
'Content-Type': 'application/json',
|
|
...(token && { Authorization: `Bearer ${token}` })
|
|
};
|
|
}
|
|
|
|
private async handleResponse<T>(response: Response): Promise<T> {
|
|
if (!response.ok) {
|
|
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
throw new Error(error.error?.message || error.error || `Request failed: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
// Generic request method
|
|
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
|
const url = `${this.baseURL}${endpoint}`;
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
...this.getAuthHeaders(),
|
|
...options.headers
|
|
}
|
|
});
|
|
return this.handleResponse<T>(response);
|
|
}
|
|
|
|
// Convenience methods
|
|
async get<T>(endpoint: string): Promise<T> {
|
|
return this.request<T>(endpoint);
|
|
}
|
|
|
|
async post<T>(endpoint: string, data?: any): Promise<T> {
|
|
return this.request<T>(endpoint, {
|
|
method: 'POST',
|
|
body: data ? JSON.stringify(data) : undefined
|
|
});
|
|
}
|
|
|
|
async put<T>(endpoint: string, data?: any): Promise<T> {
|
|
return this.request<T>(endpoint, {
|
|
method: 'PUT',
|
|
body: data ? JSON.stringify(data) : undefined
|
|
});
|
|
}
|
|
|
|
async delete<T>(endpoint: string): Promise<T> {
|
|
return this.request<T>(endpoint, { method: 'DELETE' });
|
|
}
|
|
|
|
async patch<T>(endpoint: string, data?: any): Promise<T> {
|
|
return this.request<T>(endpoint, {
|
|
method: 'PATCH',
|
|
body: data ? JSON.stringify(data) : undefined
|
|
});
|
|
}
|
|
}
|
|
|
|
// Export a singleton instance
|
|
export const api = new ApiClient(API_BASE_URL);
|
|
|
|
// Export specific API methods for better type safety and convenience
|
|
export const vipApi = {
|
|
list: () => api.get<any[]>('/api/vips'),
|
|
get: (id: string) => api.get<any>(`/api/vips/${id}`),
|
|
create: (data: any) => api.post<any>('/api/vips', data),
|
|
update: (id: string, data: any) => api.put<any>(`/api/vips/${id}`, data),
|
|
delete: (id: string) => api.delete<any>(`/api/vips/${id}`),
|
|
getSchedule: (id: string) => api.get<any[]>(`/api/vips/${id}/schedule`)
|
|
};
|
|
|
|
export const driverApi = {
|
|
list: () => api.get<any[]>('/api/drivers'),
|
|
get: (id: string) => api.get<any>(`/api/drivers/${id}`),
|
|
create: (data: any) => api.post<any>('/api/drivers', data),
|
|
update: (id: string, data: any) => api.put<any>(`/api/drivers/${id}`, data),
|
|
delete: (id: string) => api.delete<any>(`/api/drivers/${id}`),
|
|
getSchedule: (id: string) => api.get<any[]>(`/api/drivers/${id}/schedule`)
|
|
};
|
|
|
|
export const scheduleApi = {
|
|
create: (vipId: string, data: any) => api.post<any>(`/api/vips/${vipId}/schedule`, data),
|
|
update: (vipId: string, eventId: string, data: any) =>
|
|
api.put<any>(`/api/vips/${vipId}/schedule/${eventId}`, data),
|
|
delete: (vipId: string, eventId: string) =>
|
|
api.delete<any>(`/api/vips/${vipId}/schedule/${eventId}`),
|
|
updateStatus: (vipId: string, eventId: string, status: string) =>
|
|
api.patch<any>(`/api/vips/${vipId}/schedule/${eventId}/status`, { status })
|
|
};
|
|
|
|
export const authApi = {
|
|
me: () => api.get<any>('/auth/me'),
|
|
logout: () => api.post<void>('/auth/logout'),
|
|
setup: () => api.get<any>('/auth/setup'),
|
|
googleCallback: (code: string) => api.post<any>('/auth/google/callback', { code })
|
|
}; |