Add System Configuration section
This commit is contained in:
@@ -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<ConfigTabProps> = ({ isSuperAdmin }) => {
|
||||
const [editingApi, setEditingApi] = useState<string | null>(null);
|
||||
const [editingParam, setEditingParam] = useState<string | null>(null);
|
||||
const {
|
||||
apiConfigs,
|
||||
systemParameters,
|
||||
integrations,
|
||||
securityConfig,
|
||||
auditLogs,
|
||||
loading,
|
||||
updateApiConfig,
|
||||
testApiConnection,
|
||||
updateSystemParameter,
|
||||
syncIntegration,
|
||||
updateSecurityConfig,
|
||||
} = useSystemConfig();
|
||||
|
||||
if (!isSuperAdmin) {
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow p-8 text-center">
|
||||
@@ -17,29 +40,327 @@ const ConfigTab: React.FC<ConfigTabProps> = ({ 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 (
|
||||
<div className="space-y-6">
|
||||
<h2 className="text-xl font-semibold text-gray-900">Configuración del Sistema</h2>
|
||||
|
||||
<div className="bg-white rounded-lg shadow p-8 text-center">
|
||||
<Settings className="w-16 h-16 text-gray-400 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">
|
||||
Configuración del Sistema
|
||||
</h3>
|
||||
<p className="text-gray-600 mb-4">
|
||||
Esta sección está en desarrollo y se implementará según las especificaciones del informe.
|
||||
</p>
|
||||
<div className="text-sm text-gray-500">
|
||||
Funcionalidades pendientes:
|
||||
<ul className="mt-2 space-y-1">
|
||||
<li>• Configuración de API</li>
|
||||
<li>• Parámetros del sistema</li>
|
||||
<li>• Gestión de integrations</li>
|
||||
<li>• Configuración de seguridad</li>
|
||||
<li>• Logs de auditoría</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs defaultValue="apis" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-5">
|
||||
<TabsTrigger value="apis" className="flex items-center gap-2">
|
||||
<Server className="w-4 h-4" />
|
||||
APIs
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="parameters" className="flex items-center gap-2">
|
||||
<Settings className="w-4 h-4" />
|
||||
Parámetros
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="integrations" className="flex items-center gap-2">
|
||||
<Wifi className="w-4 h-4" />
|
||||
Integraciones
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="security" className="flex items-center gap-2">
|
||||
<Shield className="w-4 h-4" />
|
||||
Seguridad
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="audit" className="flex items-center gap-2">
|
||||
<Activity className="w-4 h-4" />
|
||||
Auditoría
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="apis" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Server className="w-5 h-5" />
|
||||
Configuración de APIs
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<RefreshCw className="w-6 h-6 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{apiConfigs.map((config) => (
|
||||
<div key={config.id} className="border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="font-medium">{config.name}</h4>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant={config.status === 'active' ? 'default' : 'secondary'}>
|
||||
{config.status}
|
||||
</Badge>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => testApiConnection(config.id)}
|
||||
>
|
||||
<TestTube className="w-4 h-4 mr-1" />
|
||||
Probar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<label className="font-medium">Endpoint:</label>
|
||||
{editingApi === config.id + '-endpoint' ? (
|
||||
<div className="flex gap-2 mt-1">
|
||||
<Input
|
||||
defaultValue={config.endpoint}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleApiEdit(config.id, 'endpoint', e.currentTarget.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button size="sm" onClick={() => setEditingApi(null)}>
|
||||
<X className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className="text-gray-600">{config.endpoint}</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => setEditingApi(config.id + '-endpoint')}
|
||||
>
|
||||
<Edit className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label className="font-medium">Timeout:</label>
|
||||
<span className="text-gray-600 ml-2">{config.timeout}ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="parameters" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Settings className="w-5 h-5" />
|
||||
Parámetros del Sistema
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<RefreshCw className="w-6 h-6 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{systemParameters.map((param) => (
|
||||
<div key={param.id} className="border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
<h4 className="font-medium">{param.key}</h4>
|
||||
<p className="text-sm text-gray-600">{param.description}</p>
|
||||
</div>
|
||||
<Badge variant="outline">{param.category}</Badge>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="font-medium text-sm">Valor:</label>
|
||||
{editingParam === param.id ? (
|
||||
<div className="flex gap-2 flex-1">
|
||||
<Input
|
||||
type={param.type === 'number' ? 'number' : 'text'}
|
||||
defaultValue={param.value}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleParamEdit(param.id, e.currentTarget.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button size="sm" onClick={() => setEditingParam(null)}>
|
||||
<X className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 flex-1">
|
||||
<span className="text-gray-600">{param.value}</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => setEditingParam(param.id)}
|
||||
>
|
||||
<Edit className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="integrations" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Wifi className="w-5 h-5" />
|
||||
Gestión de Integraciones
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<RefreshCw className="w-6 h-6 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{integrations.map((integration) => (
|
||||
<div key={integration.id} className="border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
<h4 className="font-medium">{integration.name}</h4>
|
||||
<p className="text-sm text-gray-600">{integration.type}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge
|
||||
variant={
|
||||
integration.status === 'connected' ? 'default' :
|
||||
integration.status === 'error' ? 'destructive' : 'secondary'
|
||||
}
|
||||
>
|
||||
{integration.status}
|
||||
</Badge>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => syncIntegration(integration.id)}
|
||||
>
|
||||
<RefreshCw className="w-4 h-4 mr-1" />
|
||||
Sincronizar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{integration.lastSync && (
|
||||
<p className="text-xs text-gray-500">
|
||||
Última sincronización: {new Date(integration.lastSync).toLocaleString()}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="security" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Shield className="w-5 h-5" />
|
||||
Configuración de Seguridad
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<RefreshCw className="w-6 h-6 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{securityConfig.map((config) => (
|
||||
<div key={config.id} className="border rounded-lg p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="font-medium">{config.setting}</h4>
|
||||
<p className="text-sm text-gray-600">{config.description}</p>
|
||||
<Badge variant="outline" className="mt-1">{config.category}</Badge>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{typeof config.value === 'boolean' ? (
|
||||
<Switch
|
||||
checked={config.value}
|
||||
onCheckedChange={(checked) =>
|
||||
updateSecurityConfig({ ...config, value: checked })
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-gray-600">{config.value}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="audit" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Activity className="w-5 h-5" />
|
||||
Logs de Auditoría
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center p-8">
|
||||
<RefreshCw className="w-6 h-6 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{auditLogs.map((log) => (
|
||||
<div key={log.id} className="border rounded-lg p-3">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant={log.status === 'success' ? 'default' : 'destructive'}>
|
||||
{log.status}
|
||||
</Badge>
|
||||
<span className="font-medium">{log.action}</span>
|
||||
</div>
|
||||
<span className="text-sm text-gray-500">
|
||||
{new Date(log.timestamp).toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">
|
||||
<p>Usuario: {log.user}</p>
|
||||
<p>IP: {log.ip}</p>
|
||||
<p>Detalles: {log.details}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user