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(endpoint: string, params?: Record): Promise { 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(endpoint: string, data: any): Promise { 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(endpoint: string, data: any): Promise { 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(endpoint: string): Promise { 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( endpoint: string, file: File, additionalData?: Record ): Promise { 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( endpoint: string, page: number = 1, limit: number = 10, filters?: Record ): 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( endpoint: string, query: string, filters?: Record ): Promise { return apiGet(endpoint, { search: query, ...filters, }); }