166 lines
4.0 KiB
TypeScript
166 lines
4.0 KiB
TypeScript
import { type ClassValue, clsx } from 'clsx';
|
|
import { twMerge } from 'tailwind-merge';
|
|
|
|
// Función para unir clases de Tailwind
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs));
|
|
}
|
|
|
|
// Configuración base de la API
|
|
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';
|
|
|
|
// Interceptor para manejar errores comunes
|
|
async function handleApiError(response: Response) {
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
|
|
// Manejar errores de autenticación
|
|
if (response.status === 401) {
|
|
throw new Error('No autorizado. Por favor inicia sesión.');
|
|
}
|
|
|
|
// Manejar errores de validación
|
|
if (response.status === 422) {
|
|
const fieldErrors = errorData.errors || {};
|
|
const errorMessage = Object.entries(fieldErrors)
|
|
.map(([field, errors]) => `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}`)
|
|
.join('; ');
|
|
throw new Error(errorMessage || 'Error de validación');
|
|
}
|
|
|
|
// Manejar errores de servidor
|
|
if (response.status >= 500) {
|
|
throw new Error('Error del servidor. Por favor intenta de nuevo más tarde.');
|
|
}
|
|
|
|
// Manejar otros errores
|
|
throw new Error(errorData.message || 'Error en la solicitud');
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
// Función genérica para peticiones GET
|
|
export async function apiGet<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
|
|
const url = new URL(`${API_BASE_URL}${endpoint}`);
|
|
|
|
if (params) {
|
|
Object.entries(params).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null) {
|
|
url.searchParams.append(key, String(value));
|
|
}
|
|
});
|
|
}
|
|
|
|
const response = await fetch(url.toString(), {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
await handleApiError(response);
|
|
return response.json();
|
|
}
|
|
|
|
// Función genérica para peticiones POST
|
|
export async function apiPost<T>(endpoint: string, data: any): Promise<T> {
|
|
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data),
|
|
});
|
|
|
|
await handleApiError(response);
|
|
return response.json();
|
|
}
|
|
|
|
// Función genérica para peticiones PUT
|
|
export async function apiPut<T>(endpoint: string, data: any): Promise<T> {
|
|
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data),
|
|
});
|
|
|
|
await handleApiError(response);
|
|
return response.json();
|
|
}
|
|
|
|
// Función genérica para peticiones DELETE
|
|
export async function apiDelete<T>(endpoint: string): Promise<T> {
|
|
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
await handleApiError(response);
|
|
return response.json();
|
|
}
|
|
|
|
// Función para subir archivos
|
|
export async function apiUpload<T>(
|
|
endpoint: string,
|
|
file: File,
|
|
additionalData?: Record<string, any>
|
|
): Promise<T> {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
if (additionalData) {
|
|
Object.entries(additionalData).forEach(([key, value]) => {
|
|
formData.append(key, String(value));
|
|
});
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
await handleApiError(response);
|
|
return response.json();
|
|
}
|
|
|
|
// Función para peticiones con paginación
|
|
export async function apiGetPaginated<T>(
|
|
endpoint: string,
|
|
page: number = 1,
|
|
limit: number = 10,
|
|
filters?: Record<string, any>
|
|
): Promise<{
|
|
data: T[];
|
|
pagination: {
|
|
page: number;
|
|
limit: number;
|
|
total: number;
|
|
totalPages: number;
|
|
};
|
|
}> {
|
|
const params = {
|
|
page,
|
|
limit,
|
|
...filters,
|
|
};
|
|
|
|
return apiGet(endpoint, params);
|
|
}
|
|
|
|
// Función para buscar
|
|
export async function apiSearch<T>(
|
|
endpoint: string,
|
|
query: string,
|
|
filters?: Record<string, any>
|
|
): Promise<T[]> {
|
|
return apiGet(endpoint, {
|
|
search: query,
|
|
...filters,
|
|
});
|
|
}
|