Backup: 2025-06-08 00:29 - User and admin online ready for dockerhub

[Restore from backup: vip-coordinator-backup-2025-06-08-00-29-user and admin online ready for dockerhub]
This commit is contained in:
2025-06-08 00:29:00 +02:00
parent 035f76fdd3
commit 36cb8e8886
33 changed files with 3676 additions and 3527 deletions

View File

@@ -1,13 +1,79 @@
// API Configuration
// VITE_API_URL must be set at build time - no fallback to prevent production issues
export const API_BASE_URL = (import.meta as any).env.VITE_API_URL;
// Use relative URLs by default so it works with any domain/reverse proxy
export const API_BASE_URL = (import.meta as any).env.VITE_API_URL || '';
if (!API_BASE_URL) {
throw new Error('VITE_API_URL environment variable is required');
// API Error class
export class ApiError extends Error {
constructor(
message: string,
public status?: number,
public code?: string,
public details?: unknown
) {
super(message);
this.name = 'ApiError';
}
}
// Helper function for API calls
export const apiCall = (endpoint: string, options?: RequestInit) => {
// Helper function for API calls with error handling
export const apiCall = async (endpoint: string, options?: RequestInit) => {
const url = endpoint.startsWith('/') ? `${API_BASE_URL}${endpoint}` : endpoint;
return fetch(url, options);
// Get auth token from localStorage
const authToken = localStorage.getItem('authToken');
// Build headers
const headers: HeadersInit = {
'Content-Type': 'application/json',
...options?.headers,
};
// Add authorization header if token exists
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}
try {
const response = await fetch(url, {
...options,
headers,
});
// Handle non-2xx responses
if (!response.ok) {
let errorData;
try {
errorData = await response.json();
} catch {
errorData = { error: { message: response.statusText } };
}
throw new ApiError(
errorData.error?.message || `Request failed with status ${response.status}`,
response.status,
errorData.error?.code,
errorData.error?.details
);
}
// Try to parse JSON response
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
const data = await response.json();
return { response, data };
}
return { response, data: null };
} catch (error) {
// Network errors or other issues
if (error instanceof ApiError) {
throw error;
}
throw new ApiError(
error instanceof Error ? error.message : 'Network request failed',
undefined,
'NETWORK_ERROR'
);
}
};