From 557f8bdd77eb1119e8dc10e771a7b4cf26117814 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 17:58:41 +0000 Subject: [PATCH] Add System Configuration section --- src/components/admin/ConfigTab.tsx | 363 +++++++++++++++++++++++++++-- src/hooks/useSystemConfig.ts | 149 ++++++++++++ src/services/configApi.ts | 162 +++++++++++++ 3 files changed, 653 insertions(+), 21 deletions(-) create mode 100644 src/hooks/useSystemConfig.ts create mode 100644 src/services/configApi.ts diff --git a/src/components/admin/ConfigTab.tsx b/src/components/admin/ConfigTab.tsx index 242e175..09143d1 100644 --- a/src/components/admin/ConfigTab.tsx +++ b/src/components/admin/ConfigTab.tsx @@ -1,5 +1,12 @@ -import React from 'react'; -import { Settings, Cog, Database, Wifi, Shield } from 'lucide-react'; +import React, { useState } from 'react'; +import { Settings, Cog, Database, Wifi, Shield, Server, Key, Users, Activity, RefreshCw, TestTube, Edit, Save, X } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Switch } from '@/components/ui/switch'; +import { Badge } from '@/components/ui/badge'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { useSystemConfig } from '@/hooks/useSystemConfig'; interface ConfigTabProps { isAdmin: boolean; @@ -7,6 +14,22 @@ interface ConfigTabProps { } const ConfigTab: React.FC = ({ isSuperAdmin }) => { + const [editingApi, setEditingApi] = useState(null); + const [editingParam, setEditingParam] = useState(null); + const { + apiConfigs, + systemParameters, + integrations, + securityConfig, + auditLogs, + loading, + updateApiConfig, + testApiConnection, + updateSystemParameter, + syncIntegration, + updateSecurityConfig, + } = useSystemConfig(); + if (!isSuperAdmin) { return (
@@ -17,29 +40,327 @@ const ConfigTab: React.FC = ({ isSuperAdmin }) => { ); } + const handleApiEdit = (id: string, field: string, value: string) => { + const config = apiConfigs.find(c => c.id === id); + if (config) { + updateApiConfig({ ...config, [field]: value }); + setEditingApi(null); + } + }; + + const handleParamEdit = (id: string, value: string) => { + const param = systemParameters.find(p => p.id === id); + if (param) { + updateSystemParameter({ ...param, value }); + setEditingParam(null); + } + }; + return (

Configuración del Sistema

-
- -

- Configuración del Sistema -

-

- Esta sección está en desarrollo y se implementará según las especificaciones del informe. -

-
- Funcionalidades pendientes: -
    -
  • • Configuración de API
  • -
  • • Parámetros del sistema
  • -
  • • Gestión de integrations
  • -
  • • Configuración de seguridad
  • -
  • • Logs de auditoría
  • -
-
-
+ + + + + APIs + + + + Parámetros + + + + Integraciones + + + + Seguridad + + + + Auditoría + + + + + + + + + Configuración de APIs + + + + {loading ? ( +
+ +
+ ) : ( +
+ {apiConfigs.map((config) => ( +
+
+

{config.name}

+
+ + {config.status} + + +
+
+
+
+ + {editingApi === config.id + '-endpoint' ? ( +
+ { + if (e.key === 'Enter') { + handleApiEdit(config.id, 'endpoint', e.currentTarget.value); + } + }} + /> + +
+ ) : ( +
+ {config.endpoint} + +
+ )} +
+
+ + {config.timeout}ms +
+
+
+ ))} +
+ )} +
+
+
+ + + + + + + Parámetros del Sistema + + + + {loading ? ( +
+ +
+ ) : ( +
+ {systemParameters.map((param) => ( +
+
+
+

{param.key}

+

{param.description}

+
+ {param.category} +
+
+ + {editingParam === param.id ? ( +
+ { + if (e.key === 'Enter') { + handleParamEdit(param.id, e.currentTarget.value); + } + }} + /> + +
+ ) : ( +
+ {param.value} + +
+ )} +
+
+ ))} +
+ )} +
+
+
+ + + + + + + Gestión de Integraciones + + + + {loading ? ( +
+ +
+ ) : ( +
+ {integrations.map((integration) => ( +
+
+
+

{integration.name}

+

{integration.type}

+
+
+ + {integration.status} + + +
+
+ {integration.lastSync && ( +

+ Última sincronización: {new Date(integration.lastSync).toLocaleString()} +

+ )} +
+ ))} +
+ )} +
+
+
+ + + + + + + Configuración de Seguridad + + + + {loading ? ( +
+ +
+ ) : ( +
+ {securityConfig.map((config) => ( +
+
+
+

{config.setting}

+

{config.description}

+ {config.category} +
+
+ {typeof config.value === 'boolean' ? ( + + updateSecurityConfig({ ...config, value: checked }) + } + /> + ) : ( + {config.value} + )} +
+
+
+ ))} +
+ )} +
+
+
+ + + + + + + Logs de Auditoría + + + + {loading ? ( +
+ +
+ ) : ( +
+ {auditLogs.map((log) => ( +
+
+
+ + {log.status} + + {log.action} +
+ + {new Date(log.timestamp).toLocaleString()} + +
+
+

Usuario: {log.user}

+

IP: {log.ip}

+

Detalles: {log.details}

+
+
+ ))} +
+ )} +
+
+
+
); }; diff --git a/src/hooks/useSystemConfig.ts b/src/hooks/useSystemConfig.ts new file mode 100644 index 0000000..7a1c85a --- /dev/null +++ b/src/hooks/useSystemConfig.ts @@ -0,0 +1,149 @@ +import { useState, useEffect } from 'react'; +import { useToast } from '@/hooks/use-toast'; +import { configApi, ApiConfig, SystemParameter, Integration, SecurityConfig, AuditLog } from '@/services/configApi'; + +export const useSystemConfig = () => { + const [apiConfigs, setApiConfigs] = useState([]); + const [systemParameters, setSystemParameters] = useState([]); + const [integrations, setIntegrations] = useState([]); + const [securityConfig, setSecurityConfig] = useState([]); + const [auditLogs, setAuditLogs] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const { toast } = useToast(); + + const loadData = async () => { + setLoading(true); + setError(null); + try { + const [apis, parameters, integs, security, logs] = await Promise.all([ + configApi.getApiConfigs(), + configApi.getSystemParameters(), + configApi.getIntegrations(), + configApi.getSecurityConfig(), + configApi.getAuditLogs(1, 20).then(result => result.logs), + ]); + + setApiConfigs(apis); + setSystemParameters(parameters); + setIntegrations(integs); + setSecurityConfig(security); + setAuditLogs(logs); + } catch (err) { + const message = err instanceof Error ? err.message : 'Error loading system configuration'; + setError(message); + console.error('Error loading system config:', err); + } finally { + setLoading(false); + } + }; + + const updateApiConfig = async (config: Partial) => { + try { + const updated = await configApi.updateApiConfig(config); + setApiConfigs(prev => prev.map(c => c.id === updated.id ? updated : c)); + toast({ + title: "Configuración Actualizada", + description: "La configuración de API se actualizó correctamente", + }); + } catch (err) { + toast({ + title: "Error", + description: "No se pudo actualizar la configuración de API", + variant: "destructive", + }); + } + }; + + const testApiConnection = async (configId: string) => { + try { + const success = await configApi.testApiConnection(configId); + toast({ + title: success ? "Conexión Exitosa" : "Conexión Fallida", + description: success ? "La API responde correctamente" : "No se pudo conectar a la API", + variant: success ? "default" : "destructive", + }); + return success; + } catch (err) { + toast({ + title: "Error", + description: "Error al probar la conexión", + variant: "destructive", + }); + return false; + } + }; + + const updateSystemParameter = async (parameter: Partial) => { + try { + const updated = await configApi.updateSystemParameter(parameter); + setSystemParameters(prev => prev.map(p => p.id === updated.id ? updated : p)); + toast({ + title: "Parámetro Actualizado", + description: "El parámetro del sistema se actualizó correctamente", + }); + } catch (err) { + toast({ + title: "Error", + description: "No se pudo actualizar el parámetro", + variant: "destructive", + }); + } + }; + + const syncIntegration = async (integrationId: string) => { + try { + await configApi.syncIntegration(integrationId); + toast({ + title: "Sincronización Iniciada", + description: "La integración se está sincronizando", + }); + // Reload integrations to get updated status + const updatedIntegrations = await configApi.getIntegrations(); + setIntegrations(updatedIntegrations); + } catch (err) { + toast({ + title: "Error", + description: "No se pudo sincronizar la integración", + variant: "destructive", + }); + } + }; + + const updateSecurityConfig = async (config: Partial) => { + try { + const updated = await configApi.updateSecurityConfig(config); + setSecurityConfig(prev => prev.map(c => c.id === updated.id ? updated : c)); + toast({ + title: "Configuración de Seguridad Actualizada", + description: "Los ajustes de seguridad se actualizaron correctamente", + }); + } catch (err) { + toast({ + title: "Error", + description: "No se pudo actualizar la configuración de seguridad", + variant: "destructive", + }); + } + }; + + useEffect(() => { + loadData(); + }, []); + + return { + apiConfigs, + systemParameters, + integrations, + securityConfig, + auditLogs, + loading, + error, + refetch: loadData, + updateApiConfig, + testApiConnection, + updateSystemParameter, + syncIntegration, + updateSecurityConfig, + }; +}; \ No newline at end of file diff --git a/src/services/configApi.ts b/src/services/configApi.ts new file mode 100644 index 0000000..c7e2d9e --- /dev/null +++ b/src/services/configApi.ts @@ -0,0 +1,162 @@ +import { API_BASE_URL } from './config'; + +export interface ApiConfig { + id: string; + name: string; + endpoint: string; + apiKey: string; + status: 'active' | 'inactive'; + timeout: number; +} + +export interface SystemParameter { + id: string; + key: string; + value: string; + type: 'string' | 'number' | 'boolean' | 'json'; + description: string; + category: string; +} + +export interface Integration { + id: string; + name: string; + type: string; + status: 'connected' | 'disconnected' | 'error'; + config: Record; + lastSync: string; +} + +export interface SecurityConfig { + id: string; + category: string; + setting: string; + value: boolean | string | number; + description: string; +} + +export interface AuditLog { + id: string; + action: string; + user: string; + timestamp: string; + details: string; + ip: string; + status: 'success' | 'failed'; +} + +export const configApi = { + // API Configuration + async getApiConfigs(): Promise { + try { + const response = await fetch(`${API_BASE_URL}/config/apis`); + if (!response.ok) throw new Error('Failed to fetch API configs'); + return await response.json(); + } catch (error) { + console.error('Error fetching API configs:', error); + return []; + } + }, + + async updateApiConfig(config: Partial): Promise { + const response = await fetch(`${API_BASE_URL}/config/apis/${config.id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(config), + }); + if (!response.ok) throw new Error('Failed to update API config'); + return await response.json(); + }, + + async testApiConnection(configId: string): Promise { + const response = await fetch(`${API_BASE_URL}/config/apis/${configId}/test`, { + method: 'POST', + }); + return response.ok; + }, + + // System Parameters + async getSystemParameters(): Promise { + try { + const response = await fetch(`${API_BASE_URL}/config/parameters`); + if (!response.ok) throw new Error('Failed to fetch system parameters'); + return await response.json(); + } catch (error) { + console.error('Error fetching system parameters:', error); + return []; + } + }, + + async updateSystemParameter(parameter: Partial): Promise { + const response = await fetch(`${API_BASE_URL}/config/parameters/${parameter.id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(parameter), + }); + if (!response.ok) throw new Error('Failed to update system parameter'); + return await response.json(); + }, + + // Integrations + async getIntegrations(): Promise { + try { + const response = await fetch(`${API_BASE_URL}/config/integrations`); + if (!response.ok) throw new Error('Failed to fetch integrations'); + return await response.json(); + } catch (error) { + console.error('Error fetching integrations:', error); + return []; + } + }, + + async syncIntegration(integrationId: string): Promise { + const response = await fetch(`${API_BASE_URL}/config/integrations/${integrationId}/sync`, { + method: 'POST', + }); + if (!response.ok) throw new Error('Failed to sync integration'); + }, + + async updateIntegration(integration: Partial): Promise { + const response = await fetch(`${API_BASE_URL}/config/integrations/${integration.id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(integration), + }); + if (!response.ok) throw new Error('Failed to update integration'); + return await response.json(); + }, + + // Security Configuration + async getSecurityConfig(): Promise { + try { + const response = await fetch(`${API_BASE_URL}/config/security`); + if (!response.ok) throw new Error('Failed to fetch security config'); + return await response.json(); + } catch (error) { + console.error('Error fetching security config:', error); + return []; + } + }, + + async updateSecurityConfig(config: Partial): Promise { + const response = await fetch(`${API_BASE_URL}/config/security/${config.id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(config), + }); + if (!response.ok) throw new Error('Failed to update security config'); + return await response.json(); + }, + + // Audit Logs + async getAuditLogs(page = 1, limit = 50): Promise<{ logs: AuditLog[], total: number }> { + try { + const response = await fetch(`${API_BASE_URL}/config/audit-logs?page=${page}&limit=${limit}`); + if (!response.ok) throw new Error('Failed to fetch audit logs'); + return await response.json(); + } catch (error) { + console.error('Error fetching audit logs:', error); + return { logs: [], total: 0 }; + } + }, +}; \ No newline at end of file