From aadb98571c46fb89d412dccc1874566cf24b91dc Mon Sep 17 00:00:00 2001 From: Claude AI Date: Thu, 29 Jan 2026 10:59:25 +0000 Subject: [PATCH] feat(fase3): add Queue management frontend page Co-Authored-By: Claude Opus 4.5 --- frontend/src/pages/Queues.tsx | 248 ++++++++++++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 frontend/src/pages/Queues.tsx diff --git a/frontend/src/pages/Queues.tsx b/frontend/src/pages/Queues.tsx new file mode 100644 index 0000000..a75ab44 --- /dev/null +++ b/frontend/src/pages/Queues.tsx @@ -0,0 +1,248 @@ +import { useState } from 'react'; +import { + Button, + Card, + Form, + Input, + InputNumber, + message, + Modal, + Popconfirm, + Select, + Space, + Table, + Tag, + Typography, +} from 'antd'; +import { + DeleteOutlined, + EditOutlined, + PlusOutlined, + TeamOutlined, +} from '@ant-design/icons'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { apiClient } from '../api/client'; + +const { Title } = Typography; + +interface Queue { + id: string; + name: string; + description: string | null; + assignment_method: string; + max_per_agent: number; + sla_first_response: number; + sla_resolution: number; + is_active: boolean; + agent_count: number; +} + +const ASSIGNMENT_METHOD_LABELS: Record = { + round_robin: 'Round Robin', + least_busy: 'Menos Ocupado', + skill_based: 'Por Habilidades', +}; + +export default function Queues() { + const [isModalOpen, setIsModalOpen] = useState(false); + const [isAgentsModalOpen, setIsAgentsModalOpen] = useState(false); + const [selectedQueue, setSelectedQueue] = useState(null); + const [form] = Form.useForm(); + const queryClient = useQueryClient(); + + const { data: queues, isLoading } = useQuery({ + queryKey: ['queues'], + queryFn: () => apiClient.get('/api/queues'), + }); + + const createMutation = useMutation({ + mutationFn: (data: Partial) => apiClient.post('/api/queues', data), + onSuccess: () => { + message.success('Cola creada'); + queryClient.invalidateQueries({ queryKey: ['queues'] }); + closeModal(); + }, + }); + + const updateMutation = useMutation({ + mutationFn: ({ id, data }: { id: string; data: Partial }) => + apiClient.put(`/api/queues/${id}`, data), + onSuccess: () => { + message.success('Cola actualizada'); + queryClient.invalidateQueries({ queryKey: ['queues'] }); + closeModal(); + }, + }); + + const deleteMutation = useMutation({ + mutationFn: (id: string) => apiClient.delete(`/api/queues/${id}`), + onSuccess: () => { + message.success('Cola eliminada'); + queryClient.invalidateQueries({ queryKey: ['queues'] }); + }, + }); + + const closeModal = () => { + setIsModalOpen(false); + setSelectedQueue(null); + form.resetFields(); + }; + + const handleSubmit = (values: Partial) => { + if (selectedQueue) { + updateMutation.mutate({ id: selectedQueue.id, data: values }); + } else { + createMutation.mutate(values); + } + }; + + const handleEdit = (queue: Queue) => { + setSelectedQueue(queue); + form.setFieldsValue(queue); + setIsModalOpen(true); + }; + + const handleCreate = () => { + setSelectedQueue(null); + form.resetFields(); + setIsModalOpen(true); + }; + + const handleManageAgents = (queue: Queue) => { + setSelectedQueue(queue); + setIsAgentsModalOpen(true); + }; + + const columns = [ + { title: 'Nombre', dataIndex: 'name', key: 'name' }, + { + title: 'Método Asignación', + dataIndex: 'assignment_method', + key: 'assignment_method', + render: (method: string) => ASSIGNMENT_METHOD_LABELS[method] || method, + }, + { + title: 'Agentes', + dataIndex: 'agent_count', + key: 'agent_count', + render: (count: number) => }>{count}, + }, + { title: 'Max/Agente', dataIndex: 'max_per_agent', key: 'max_per_agent' }, + { + title: 'SLA Respuesta', + dataIndex: 'sla_first_response', + key: 'sla_first_response', + render: (seconds: number) => `${Math.round(seconds / 60)} min`, + }, + { + title: 'Acciones', + key: 'actions', + render: (_: unknown, record: Queue) => ( + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +
+ + setIsAgentsModalOpen(false)} + footer={null} + width={600} + > +

Gestión de agentes en cola (próximamente)

+
+ + ); +}