Backup: 2025-06-07 19:48 - Script test

[Restore from backup: vip-coordinator-backup-2025-06-07-19-48-script-test]
This commit is contained in:
2025-06-07 19:48:00 +02:00
parent 8fb00ec041
commit dc4655cef4
103 changed files with 16396 additions and 6143 deletions

109
frontend/src/api/client.ts Normal file
View File

@@ -0,0 +1,109 @@
// 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 })
};