diff --git a/frontend/src/layouts/MainLayout.tsx b/frontend/src/layouts/MainLayout.tsx index 7ffdfec..9a7c0f0 100644 --- a/frontend/src/layouts/MainLayout.tsx +++ b/frontend/src/layouts/MainLayout.tsx @@ -15,6 +15,7 @@ import { BarChartOutlined, FileTextOutlined, GlobalOutlined, + ApiOutlined, } from '@ant-design/icons'; import { useAuthStore } from '../store/auth'; import Dashboard from '../pages/Dashboard'; @@ -26,6 +27,7 @@ import FlowTemplates from '../pages/FlowTemplates'; import GlobalVariables from '../pages/GlobalVariables'; import Queues from '../pages/Queues'; import SupervisorDashboard from '../pages/SupervisorDashboard'; +import OdooConfig from '../pages/OdooConfig'; const { Header, Sider, Content } = Layout; const { Text } = Typography; @@ -82,6 +84,11 @@ export default function MainLayout() { icon: , label: 'Supervisor', }, + { + key: '/odoo', + icon: , + label: 'Odoo', + }, { key: '/settings', icon: , @@ -194,6 +201,7 @@ export default function MainLayout() { } /> } /> } /> + } /> Configuración (próximamente)} /> diff --git a/frontend/src/pages/OdooConfig.tsx b/frontend/src/pages/OdooConfig.tsx new file mode 100644 index 0000000..fe04dde --- /dev/null +++ b/frontend/src/pages/OdooConfig.tsx @@ -0,0 +1,182 @@ +import { useState, useEffect } from 'react'; +import { + Card, + Form, + Input, + Button, + Space, + Typography, + Alert, + Spin, + Tag, + message, +} from 'antd'; +import { + LinkOutlined, + CheckCircleOutlined, + CloseCircleOutlined, + ReloadOutlined, +} from '@ant-design/icons'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { apiClient } from '../api/client'; + +const { Title } = Typography; + +interface OdooConfig { + url: string; + database: string; + username: string; + is_connected: boolean; +} + +interface OdooConfigUpdate { + url: string; + database: string; + username: string; + api_key?: string; +} + +export default function OdooConfig() { + const [form] = Form.useForm(); + const queryClient = useQueryClient(); + const [testStatus, setTestStatus] = useState<'idle' | 'testing' | 'success' | 'error'>('idle'); + + const { data: config, isLoading } = useQuery({ + queryKey: ['odoo-config'], + queryFn: () => apiClient.get('/api/integrations/odoo/config'), + }); + + useEffect(() => { + if (config) { + form.setFieldsValue({ + url: config.url, + database: config.database, + username: config.username, + }); + } + }, [config, form]); + + const saveMutation = useMutation({ + mutationFn: (data: OdooConfigUpdate) => + apiClient.put('/api/integrations/odoo/config', data), + onSuccess: () => { + message.success('Configuracion guardada'); + queryClient.invalidateQueries({ queryKey: ['odoo-config'] }); + }, + onError: () => { + message.error('Error al guardar'); + }, + }); + + const testMutation = useMutation({ + mutationFn: () => apiClient.post('/api/integrations/odoo/test', {}), + onSuccess: () => { + setTestStatus('success'); + message.success('Conexion exitosa'); + queryClient.invalidateQueries({ queryKey: ['odoo-config'] }); + }, + onError: () => { + setTestStatus('error'); + message.error('Error de conexion'); + }, + }); + + const handleTest = () => { + setTestStatus('testing'); + testMutation.mutate(); + }; + + const handleSave = async () => { + const values = await form.validateFields(); + saveMutation.mutate(values); + }; + + if (isLoading) { + return ; + } + + return ( + + + Configuracion Odoo + + {config?.is_connected ? ( + } color="success">Conectado + ) : ( + } color="error">Desconectado + )} + + + + + + + } + placeholder="https://tu-empresa.odoo.com" + /> + + + + + + + + + + + + + + + + Inicia sesion en Odoo + Ve a Ajustes - Usuarios + Selecciona tu usuario + En la pestana Preferencias, genera una API Key + + } + type="info" + style={{ marginBottom: 24 }} + /> + + + + Guardar + + } + onClick={handleTest} + loading={testMutation.isPending} + > + Probar Conexion + + + + + + ); +}