{"id":900,"date":"2026-02-23T10:44:04","date_gmt":"2026-02-23T16:44:04","guid":{"rendered":"https:\/\/mudanzasmt.com\/?page_id=900"},"modified":"2026-03-10T13:55:24","modified_gmt":"2026-03-10T19:55:24","slug":"disistribuidor-de-leads","status":"publish","type":"page","link":"https:\/\/mudanzasmt.com\/index.php\/disistribuidor-de-leads\/","title":{"rendered":"Distribuidor de Leads WhatsApp"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"900\" class=\"elementor elementor-900\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-908c534 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"908c534\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-5c06eaf\" data-id=\"5c06eaf\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-180ce87 elementor-widget elementor-widget-html\" data-id=\"180ce87\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\r\n<script src=\"https:\/\/unpkg.com\/react@18\/umd\/react.production.min.js\"><\/script>\r\n<script src=\"https:\/\/unpkg.com\/react-dom@18\/umd\/react-dom.production.min.js\"><\/script>\r\n<script src=\"https:\/\/unpkg.com\/@babel\/standalone\/babel.min.js\"><\/script>\r\n\r\n<style>\r\n  \/* CSS Hack para hacer que todo el texto de la fecha sea clickeable y abra el calendario nativo *\/\r\n  .date-picker-wrapper input[type=\"datetime-local\"] {\r\n    position: relative;\r\n  }\r\n  .date-picker-wrapper input[type=\"datetime-local\"]::-webkit-calendar-picker-indicator {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    opacity: 0;\r\n    cursor: pointer;\r\n  }\r\n<\/style>\r\n\r\n<div id=\"distribuidor-leads-root\"><\/div>\r\n\r\n<script type=\"text\/babel\">\r\n  const { useState, useEffect } = React;\r\n\r\n  \/\/ --- \u00cdconos en formato SVG ---\r\n  const Activity = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"22 12 18 12 15 21 9 3 6 12 2 12\"><\/polyline><\/svg>;\r\n  const Users = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"\/><circle cx=\"9\" cy=\"7\" r=\"4\"\/><path d=\"M22 21v-2a4 4 0 0 0-3-3.87\"\/><path d=\"M16 3.13a4 4 0 0 1 0 7.75\"\/><\/svg>;\r\n  const UserPlus = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2\"\/><circle cx=\"9\" cy=\"7\" r=\"4\"\/><line x1=\"19\" y1=\"8\" x2=\"19\" y2=\"14\"\/><line x1=\"22\" y1=\"11\" x2=\"16\" y2=\"11\"\/><\/svg>;\r\n  const PhoneIncoming = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"16 2 16 8 22 8\"\/><line x1=\"23\" y1=\"1\" x2=\"16\" y2=\"8\"\/><path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"\/><\/svg>;\r\n  const MessageSquare = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"\/><\/svg>;\r\n  const Power = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M18.36 6.64a9 9 0 1 1-12.73 0\"\/><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"12\"\/><\/svg>;\r\n  const Trash2 = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"\/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"\/><line x1=\"10\" y1=\"11\" x2=\"10\" y2=\"17\"\/><line x1=\"14\" y1=\"11\" x2=\"14\" y2=\"17\"\/><\/svg>;\r\n  const List = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><line x1=\"8\" y1=\"6\" x2=\"21\" y2=\"6\"\/><line x1=\"8\" y1=\"12\" x2=\"21\" y2=\"12\"\/><line x1=\"8\" y1=\"18\" x2=\"21\" y2=\"18\"\/><line x1=\"3\" y1=\"6\" x2=\"3.01\" y2=\"6\"\/><line x1=\"3\" y1=\"12\" x2=\"3.01\" y2=\"12\"\/><line x1=\"3\" y1=\"18\" x2=\"3.01\" y2=\"18\"\/><\/svg>;\r\n  const Download = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"\/><polyline points=\"7 10 12 15 17 10\"\/><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"\/><\/svg>;\r\n  const Calendar = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"\/><line x1=\"16\" y1=\"2\" x2=\"16\" y2=\"6\"\/><line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"6\"\/><line x1=\"3\" y1=\"10\" x2=\"21\" y2=\"10\"\/><\/svg>;\r\n  const Repeat = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"17 1 21 5 17 9\"\/><path d=\"M3 11V9a4 4 0 0 1 4-4h14\"\/><polyline points=\"7 23 3 19 7 15\"\/><path d=\"M21 13v2a4 4 0 0 1-4 4H3\"\/><\/svg>;\r\n  const RefreshCw = ({ className }) => <svg className={className} xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><polyline points=\"23 4 23 10 17 10\"\/><polyline points=\"1 20 1 14 7 14\"\/><path d=\"M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15\"\/><\/svg>;\r\n\r\n  function App() {\r\n    const [agents, setAgents] = useState([]);\r\n    const [cycle, setCycle] = useState([]); \r\n    const [logs, setLogs] = useState([]); \r\n    const [realHistory, setRealHistory] = useState([]); \r\n    const [isLoading, setIsLoading] = useState(true);\r\n    const [activeTab, setActiveTab] = useState('bot');\r\n    \r\n    \/\/ --- ESTADOS PARA FILTROS AVANZADOS ---\r\n    const [startDate, setStartDate] = useState('');\r\n    const [endDate, setEndDate] = useState('');\r\n    const [selectedAgent, setSelectedAgent] = useState('');\r\n    const [selectedBot, setSelectedBot] = useState('');\r\n\r\n    \/\/ --- ESTADOS PARA LA RULETA MANUAL ---\r\n    const [rotation, setRotation] = useState(0);\r\n    const [isSpinning, setIsSpinning] = useState(false);\r\n    const [raffleWinner, setRaffleWinner] = useState(null);\r\n    const [ruletaLeadName, setRuletaLeadName] = useState(''); \r\n    const [ruletaLeadPhone, setRuletaLeadPhone] = useState(''); \r\n\r\n    \/\/ --- RUTAS DE APIS ---\r\n    const API_URL = 'https:\/\/mudanzasmt.com\/api-vendedores.php';\r\n    const API_RULETA_URL = 'https:\/\/mudanzasmt.com\/api-ruleta.php'; \r\n    const isPlaceholder = API_URL.includes('TU-DOMINIO.com');\r\n\r\n    \/\/ --- ESTADOS PARA EL FORMULARIO DE AGENTE ---\r\n    const [newName, setNewName] = useState('');\r\n    const [newBranch, setNewBranch] = useState('');\r\n    const [newPhone, setNewPhone] = useState(''); \r\n    \r\n    const [showToolsToast, setShowToolsToast] = useState(true);\r\n    const [isDismissed, setIsDismissed] = useState(false);\r\n\r\n    useEffect(() => {\r\n      fetchVendedores();\r\n      fetchHistory(); \r\n      \r\n      \/\/ SINCRONIZACI\u00d3N EN TIEMPO REAL (Cada 3 segundos)\r\n      const interval = setInterval(() => {\r\n        fetchVendedores(true); \/\/ El par\u00e1metro \"true\" indica que es una actualizaci\u00f3n silenciosa\r\n        fetchHistory(true);\r\n      }, 3000);\r\n      \r\n      return () => clearInterval(interval); \r\n    }, []);\r\n\r\n    \/\/ --- NUEVO: EVENTO PARA MOSTRAR\/OCULTAR AL HACER SCROLL ---\r\n    useEffect(() => {\r\n      const handleScroll = () => {\r\n        if (window.scrollY > 300) {\r\n          setIsDismissed(false); \/\/ Resetea el estado manual al bajar\r\n          setShowToolsToast(false); \/\/ Se oculta autom\u00e1ticamente al bajar\r\n        } else if (window.scrollY < 100 && !isDismissed) {\r\n          setShowToolsToast(true); \/\/ Vuelve a aparecer al subir al tope\r\n        }\r\n      };\r\n\r\n      window.addEventListener('scroll', handleScroll);\r\n      return () => window.removeEventListener('scroll', handleScroll);\r\n    }, [isDismissed]);\r\n\r\n    const fetchVendedores = async (isPolling = false) => {\r\n      if (isPlaceholder) {\r\n        if (!isPolling) {\r\n          setIsLoading(false);\r\n          addLog('Modo de prueba activo.', 'warning');\r\n        }\r\n        return;\r\n      }\r\n      try {\r\n        \/\/ SOLUCI\u00d3N: Agregamos timestamp y cache: 'no-store' para obligar al navegador a descargar siempre la \u00faltima versi\u00f3n\r\n        const response = await fetch(`${API_URL}?_t=${Date.now()}`, { cache: 'no-store' });\r\n        if (!response.ok) throw new Error('Error en la red');\r\n        const data = await response.json();\r\n        \r\n        \/\/ Evitar que la pantalla parpadee actualizando el estado SOLO si hay cambios reales\r\n        setAgents(prevAgents => {\r\n           if (JSON.stringify(prevAgents) === JSON.stringify(data)) return prevAgents;\r\n           return data;\r\n        });\r\n\r\n        \/\/ Actualizar el ciclo de vendedores activos tambi\u00e9n solo si cambi\u00f3\r\n        setCycle(prevCycle => {\r\n           const activos = data.filter(a => a.active).map(a => a.id);\r\n           \/\/ Comprobamos si las listas ordenadas son iguales para no reescribir el estado a lo tonto\r\n           if (JSON.stringify([...prevCycle].sort()) === JSON.stringify([...activos].sort())) {\r\n               return prevCycle;\r\n           }\r\n           return activos.sort(() => Math.random() - 0.5);\r\n        });\r\n\r\n        if (!isPolling) {\r\n          setIsLoading(false);\r\n          addLog('Base de datos sincronizada correctamente.', 'success');\r\n        }\r\n      } catch (error) {\r\n        if (!isPolling) {\r\n          addLog('Error al conectar con la base de datos.', 'error');\r\n          setIsLoading(false);\r\n        }\r\n      }\r\n    };\r\n\r\n    const fetchHistory = async (isPolling = false) => {\r\n      if (isPlaceholder) return;\r\n      try {\r\n        \/\/ SOLUCI\u00d3N: Agregamos timestamp y cache: 'no-store' a la llamada del historial\r\n        const response = await fetch(`${API_URL}?action=historial&_t=${Date.now()}`, { cache: 'no-store' });\r\n        if (!response.ok) throw new Error('Error en red');\r\n        const data = await response.json();\r\n        \r\n        \/\/ Actualizar historial SOLO si hay cambios\r\n        setRealHistory(prev => {\r\n            if (JSON.stringify(prev) === JSON.stringify(data)) return prev;\r\n            return data;\r\n        });\r\n      } catch (error) {\r\n        if (!isPolling) console.warn(\"Error leyendo historial en vivo\");\r\n      }\r\n    };\r\n\r\n    const addLog = (message, type = 'info') => {\r\n      const newLog = {\r\n        id: Date.now() + Math.random(),\r\n        time: new Date().toLocaleTimeString('es-MX', { timeZone: 'America\/Merida', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true }),\r\n        message, type\r\n      };\r\n      setLogs(prev => [newLog, ...prev]);\r\n    };\r\n\r\n    const getMexicoDate = (fechaSql) => {\r\n      if (!fechaSql) return new Date();\r\n      \/\/ Mantenemos la 'Z' indicando que la base de datos guarda en UTC.\r\n      \/\/ As\u00ed JavaScript hace correctamente la conversi\u00f3n a la hora de M\u00e9rida.\r\n      const utcIsoString = fechaSql.replace(' ', 'T') + 'Z';\r\n      return new Date(utcIsoString);\r\n    };\r\n\r\n    const formatMySqlTime = (fechaSql) => {\r\n      if (!fechaSql) return '--\/--\/---- --:--';\r\n      try {\r\n          const date = getMexicoDate(fechaSql);\r\n          return date.toLocaleString('es-MX', { timeZone: 'America\/Merida', day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', hour12: true });\r\n      } catch(e) { return fechaSql; }\r\n    };\r\n\r\n    const formatForCSV = (fechaSql) => {\r\n        if (!fechaSql) return '';\r\n        try {\r\n            const date = getMexicoDate(fechaSql);\r\n            return date.toLocaleString('es-MX', { timeZone: 'America\/Merida', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true });\r\n        } catch(e) { return fechaSql; }\r\n    };\r\n\r\n    const getBotName = (botString) => {\r\n        if (!botString || botString === 'Desconocido' || botString === 'Bot Principal' || botString.trim() === '') {\r\n            return 'Bot 1';\r\n        }\r\n        return botString;\r\n    };\r\n\r\n    const formatDateTimeLocal = (date) => {\r\n        const pad = (n) => n.toString().padStart(2, '0');\r\n        const Y = date.getFullYear(); const M = pad(date.getMonth() + 1); const D = pad(date.getDate());\r\n        const h = pad(date.getHours()); const m = pad(date.getMinutes());\r\n        return `${Y}-${M}-${D}T${h}:${m}`;\r\n    };\r\n\r\n    const setToday = () => {\r\n       const start = new Date(); start.setHours(0, 0, 0, 0);\r\n       const end = new Date(); end.setHours(23, 59, 59, 999);\r\n       setStartDate(formatDateTimeLocal(start)); setEndDate(formatDateTimeLocal(end));\r\n    };\r\n\r\n    const setYesterday = () => {\r\n       const start = new Date(); start.setDate(start.getDate() - 1); start.setHours(0, 0, 0, 0);\r\n       const end = new Date(); end.setDate(end.getDate() - 1); end.setHours(23, 59, 59, 999);\r\n       setStartDate(formatDateTimeLocal(start)); setEndDate(formatDateTimeLocal(end));\r\n    };\r\n\r\n    const clearFilters = () => { setStartDate(''); setEndDate(''); setSelectedAgent(''); setSelectedBot(''); };\r\n\r\n    const filteredHistory = realHistory.filter(record => {\r\n        const recordTime = getMexicoDate(record.fecha).getTime();\r\n        \r\n        \/\/ SOLUCI\u00d3N AL FILTRO: A\u00f1adimos -06:00 a los valores de los inputs para alinearlos\r\n        \/\/ con la zona horaria. Adem\u00e1s, garantizamos que el \"endDate\" abarque hasta el \u00faltimo segundo del minuto.\r\n        const filterStart = startDate ? new Date(startDate + '-06:00').getTime() : 0;\r\n        \r\n        let filterEnd = Infinity;\r\n        if (endDate) {\r\n            const endObj = new Date(endDate + '-06:00');\r\n            endObj.setSeconds(59, 999); \/\/ Incluir todo el minuto completo\r\n            filterEnd = endObj.getTime();\r\n        }\r\n\r\n        const matchesDate = recordTime >= filterStart && recordTime <= filterEnd;\r\n        const matchesAgent = selectedAgent === '' || record.agent_name === selectedAgent;\r\n        \r\n        const origenReal = getBotName(record.origen_bot);\r\n        const matchesBot = selectedBot === '' || origenReal === selectedBot;\r\n        \r\n        return matchesDate && matchesAgent && matchesBot;\r\n    });\r\n\r\n    const downloadCSV = () => {\r\n      if (filteredHistory.length === 0) return addLog('No hay datos en el rango seleccionado para descargar.', 'warning');\r\n      let csvContent = \"ID,Tel\u00e9fono del Lead,Vendedor Asignado,Origen (Bot),Fecha y Hora (M\u00e9rida)\\n\"; \r\n      filteredHistory.forEach(record => {\r\n        const origen = getBotName(record.origen_bot);\r\n        csvContent += `${record.id},\"${record.lead_phone}\",\"${record.agent_name}\",\"${origen}\",\"${formatForCSV(record.fecha)}\"\\n`;\r\n      });\r\n      const blob = new Blob([\"\\ufeff\" + csvContent], { type: 'text\/csv;charset=utf-8;' });\r\n      const url = URL.createObjectURL(blob);\r\n      const link = document.createElement(\"a\"); link.setAttribute(\"href\", url);\r\n      link.setAttribute(\"download\", `reporte_leads_mudanzas_${new Date().toLocaleDateString('es-MX').replace(\/\\\/\/g, '-')}.csv`);\r\n      document.body.appendChild(link); link.click(); document.body.removeChild(link);\r\n      addLog('Reporte descargado correctamente.', 'success');\r\n    };\r\n\r\n    \/\/ --- L\u00d3GICA DE A\u00d1ADIR VENDEDOR ---\r\n    const handleAddAgent = async (e) => {\r\n      e.preventDefault();\r\n      if (!newName || !newBranch || !newPhone) return;\r\n      \r\n      const finalName = `${newName.trim()} - ${newBranch.trim()}`;\r\n      const finalPhone = `52${newPhone.trim()}`;\r\n\r\n      addLog('Guardando vendedor...', 'info');\r\n      try {\r\n        const response = await fetch(API_URL, {\r\n          method: 'POST', headers: { 'Content-Type': 'application\/json' },\r\n          body: JSON.stringify({ name: finalName, phone: finalPhone })\r\n        });\r\n        const data = await response.json();\r\n        if (data.success) {\r\n          \/\/ Actualizaci\u00f3n optimista\r\n          const newAgent = { id: data.id, name: finalName, phone: finalPhone, active: true };\r\n          setAgents([...agents, newAgent]);\r\n          addLog(`Vendedor guardado exitosamente: ${newAgent.name}`, 'success');\r\n          \r\n          setNewName(''); \r\n          setNewBranch('');\r\n          setNewPhone('');\r\n\r\n          \/\/ Forzar sincronizaci\u00f3n inmediata para asegurar que todos los dispositivos est\u00e9n parejos\r\n          fetchVendedores(true);\r\n        } else { addLog(`Error del servidor: ${data.error}`, 'error'); }\r\n      } catch (error) { addLog('Error de conexi\u00f3n al guardar.', 'error'); }\r\n    };\r\n\r\n    const toggleAgentStatus = async (id) => {\r\n      const agent = agents.find(a => a.id === id);\r\n      const newStatus = !agent.active;\r\n      \r\n      \/\/ Actualizaci\u00f3n optimista local\r\n      setAgents(agents.map(a => a.id === id ? { ...a, active: newStatus } : a));\r\n      try {\r\n        const response = await fetch(API_URL, {\r\n          method: 'PUT', headers: { 'Content-Type': 'application\/json' },\r\n          body: JSON.stringify({ id: id, active: newStatus })\r\n        });\r\n        const data = await response.json();\r\n        if (data.success) {\r\n          addLog(`Vendedor ${agent.name} ahora est\u00e1 ${newStatus ? 'ACTIVO' : 'INACTIVO'}`, 'info');\r\n          \/\/ Forzar sincronizaci\u00f3n silenciosa tras \u00e9xito\r\n          fetchVendedores(true);\r\n        } else {\r\n          \/\/ Revertir si hubo fallo\r\n          setAgents(agents.map(a => a.id === id ? { ...a, active: !newStatus } : a));\r\n          addLog(`Error al actualizar estado: ${data.error}`, 'error');\r\n        }\r\n      } catch (error) {\r\n        setAgents(agents.map(a => a.id === id ? { ...a, active: !newStatus } : a));\r\n        addLog('Error de conexi\u00f3n al actualizar.', 'error');\r\n      }\r\n    };\r\n\r\n    const deleteAgent = async (id) => {\r\n      const confirmDelete = window.confirm(\"\u26a0\ufe0f \u00bfEst\u00e1s seguro de que deseas eliminar este vendedor de forma permanente?\\n\\nEsta acci\u00f3n no se puede deshacer.\");\r\n      if (!confirmDelete) return;\r\n\r\n      const agentToDelete = agents.find(a => a.id === id);\r\n      const previousAgents = [...agents];\r\n      setAgents(agents.filter(a => a.id !== id));\r\n      \r\n      try {\r\n        const response = await fetch(`${API_URL}?id=${id}`, { method: 'DELETE' });\r\n        const data = await response.json();\r\n        if (data.success) { \r\n          addLog(`Vendedor eliminado permanentemente: ${agentToDelete.name}`, 'warning'); \r\n          fetchVendedores(true); \/\/ Sincronizar silenciosamente\r\n        } \r\n        else { setAgents(previousAgents); addLog(`Error al eliminar: ${data.error}`, 'error'); }\r\n      } catch (error) { setAgents(previousAgents); addLog('Error de conexi\u00f3n al eliminar.', 'error'); }\r\n    };\r\n\r\n    \/\/ ==========================================\r\n    \/\/ L\u00d3GICA DE LA RULETA DE SORTEO MANUAL\r\n    \/\/ ==========================================\r\n    const activeAgentsForRoulette = agents.filter(a => a.active);\r\n    const rouletteColors = ['#1a3a85', '#3b82f6', '#f59e0b', '#ef4444', '#8b5cf6', '#14b8a6', '#f97316', '#6366f1'];\r\n\r\n    const spinRoulette = () => {\r\n      \/\/ Solo validamos que pongan el tel\u00e9fono y que tenga 10 d\u00edgitos. El nombre es opcional.\r\n      if (!ruletaLeadPhone) {\r\n        addLog(`\u26a0\ufe0f Debes escribir el tel\u00e9fono del prospecto para poder girar la ruleta.`, 'warning');\r\n        setActiveTab('sistema');\r\n        return;\r\n      }\r\n      if (ruletaLeadPhone.length < 10) {\r\n         addLog(`\u26a0\ufe0f El tel\u00e9fono debe tener 10 d\u00edgitos completos.`, 'warning');\r\n         setActiveTab('sistema');\r\n         return;\r\n      }\r\n\r\n      if (isSpinning || activeAgentsForRoulette.length === 0) return;\r\n      \r\n      setIsSpinning(true);\r\n      setRaffleWinner(null);\r\n      \r\n      const extraSpins = 360 * (5 + Math.floor(Math.random() * 5));\r\n      const randomAngle = Math.floor(Math.random() * 360);\r\n      const newRotation = rotation + extraSpins + randomAngle;\r\n      \r\n      setRotation(newRotation);\r\n      \r\n      const sliceAngle = 360 \/ activeAgentsForRoulette.length;\r\n      const normalizedRot = newRotation % 360;\r\n      const winningAngle = (360 - normalizedRot) % 360;\r\n      const winnerIndex = Math.round(winningAngle \/ sliceAngle) % activeAgentsForRoulette.length;\r\n      const winner = activeAgentsForRoulette[winnerIndex];\r\n      \r\n      setTimeout(async () => {\r\n        setIsSpinning(false);\r\n        setRaffleWinner(winner);\r\n        addLog(`\ud83c\udfb2 Sorteo finalizado. Ganador: ${winner.name}`, 'success');\r\n        \r\n        \/\/ --- CONEXI\u00d3N A LA BASE DE DATOS DE LA RULETA ---\r\n        try {\r\n          const res = await fetch(API_RULETA_URL, {\r\n            method: 'POST',\r\n            headers: { 'Content-Type': 'application\/json' },\r\n            body: JSON.stringify({\r\n              agent_name: winner.name,\r\n              lead_name: ruletaLeadName.trim() || 'Sin nombre', \/\/ Si est\u00e1 vac\u00edo, se manda esto\r\n              lead_phone: `52${ruletaLeadPhone.trim()}`\r\n            })\r\n          });\r\n          const data = await res.json();\r\n          if (data.success) {\r\n            addLog(`\ud83d\udcdd Resultado guardado en la tabla de la ruleta exitosamente.`, 'info');\r\n            setRuletaLeadName('');\r\n            setRuletaLeadPhone('');\r\n            \/\/ Sincronizar el historial para que todos vean la asignaci\u00f3n en el panel de inmediato\r\n            fetchHistory(true);\r\n          } else {\r\n            addLog(`\u274c Error guardando sorteo: ${data.error}`, 'error');\r\n          }\r\n        } catch (err) {\r\n          addLog(`\u274c Error de red guardando sorteo de ruleta.`, 'error');\r\n        }\r\n\r\n        setActiveTab('sistema'); \r\n      }, 4000);\r\n    };\r\n\r\n    const scrollToRuleta = () => {\r\n      const element = document.getElementById('seccion-ruleta');\r\n      if (element) {\r\n        element.scrollIntoView({ behavior: 'smooth' });\r\n        setShowToolsToast(false);\r\n      }\r\n    };\r\n\r\n    \/\/ --- C\u00c1LCULOS PARA ESTAD\u00cdSTICAS DEL D\u00cdA ---\r\n    const todayStart = new Date();\r\n    todayStart.setHours(0, 0, 0, 0);\r\n\r\n    const historyToday = realHistory.filter(r => {\r\n        const d = getMexicoDate(r.fecha);\r\n        return d >= todayStart;\r\n    });\r\n\r\n    const getLeadsToday = (agentName) => {\r\n        return historyToday.filter(r => r.agent_name === agentName).length;\r\n    };\r\n\r\n    return (\r\n      <div className=\"min-h-screen bg-[#09a8b4] p-4 md:p-8 font-sans text-slate-800 relative\">\r\n        \r\n        {\/* TOAST FLOTANTE DE HERRAMIENTAS ADICIONALES (ANIMACI\u00d3N SUAVE) *\/}\r\n        <div className={`fixed top-4 right-4 sm:top-6 sm:right-6 z-[60] bg-white shadow-2xl border border-slate-200 rounded-xl p-2 sm:p-3 flex items-center gap-3 transition-all duration-500 ease-in-out transform ${showToolsToast ? 'translate-y-0 opacity-100' : '-translate-y-[150%] opacity-0 pointer-events-none'}`}>\r\n          <div \r\n            onClick={scrollToRuleta}\r\n            className=\"flex items-center gap-3 cursor-pointer group\"\r\n          >\r\n            <div className=\"bg-[#1a3a85]\/10 p-2 rounded-lg group-hover:bg-[#1a3a85]\/20 transition-colors hidden sm:block\">\r\n              <Repeat className=\"w-4 h-4 text-[#1a3a85]\" \/>\r\n            <\/div>\r\n            <div className=\"pl-2 sm:pl-0 pr-2\">\r\n              <p className=\"text-sm font-bold text-slate-800 group-hover:text-[#1a3a85] transition-colors\">Herramientas Adicionales<\/p>\r\n              <p className=\"text-xs text-slate-500\">Ir a la ruleta manual &darr;<\/p>\r\n            <\/div>\r\n          <\/div>\r\n          <div className=\"border-l border-slate-200 pl-2 sm:pl-3\">\r\n            <button \r\n              onClick={() => { setShowToolsToast(false); setIsDismissed(true); }} \r\n              className=\"text-slate-400 hover:text-slate-600 hover:bg-slate-100 p-1.5 rounded-lg transition-colors flex items-center justify-center\"\r\n              title=\"Cerrar aviso\"\r\n            >\r\n              <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"><\/line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"><\/line><\/svg>\r\n            <\/button>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div className=\"max-w-6xl mx-auto space-y-6\">\r\n          \r\n          <header className=\"bg-white p-5 sm:p-6 rounded-2xl shadow-lg border border-slate-100 flex flex-col md:flex-row items-center justify-between gap-4\">\r\n            <div className=\"flex flex-col sm:flex-row items-center gap-4 text-center sm:text-left flex-1 min-w-0 w-full\">\r\n              {\/* === ENLACE REAL DE TU LOGO INTEGRADO === *\/}\r\n              <img decoding=\"async\" \r\n                src=\"https:\/\/mudanzasmt.com\/azul%20(3).png\" \r\n                alt=\"Terrexpress Logo\" \r\n                className=\"w-36 sm:w-48 h-auto object-contain shrink-0\"\r\n              \/>\r\n              <div className=\"hidden sm:block border-l-2 border-slate-200 h-8 mx-2 shrink-0\"><\/div>\r\n              <div className=\"min-w-0\">\r\n                <h1 className=\"text-lg sm:text-xl font-bold text-slate-900 truncate\">\r\n                  Distribuidor de Leads\r\n                <\/h1>\r\n              <\/div>\r\n            <\/div>\r\n            <div className=\"flex items-center gap-3 text-sm font-medium w-full md:w-auto justify-center md:justify-end flex-wrap shrink-0\">\r\n              <div className=\"px-4 py-2 bg-blue-50 text-blue-800 border border-blue-100 rounded-lg shadow-sm\">\r\n                Vendedores Activos: <span className=\"font-bold ml-1\">{activeAgentsForRoulette.length}<\/span>\r\n              <\/div>\r\n            <\/div>\r\n          <\/header>\r\n\r\n          <div className=\"grid grid-cols-1 lg:grid-cols-12 gap-6\">\r\n            \r\n            {\/* COLUMNA IZQUIERDA: VENDEDORES *\/}\r\n            <div className=\"lg:col-span-5 space-y-6\">\r\n              <div className=\"bg-white rounded-2xl shadow-lg border border-slate-100 overflow-hidden\">\r\n                <div className=\"p-5 border-b border-slate-100 flex items-center justify-between\">\r\n                  <h2 className=\"text-lg font-semibold flex items-center gap-2\">\r\n                    <Users className=\"w-5 h-5 text-slate-500\" \/>\r\n                    Equipo de Ventas\r\n                  <\/h2>\r\n                <\/div>\r\n                <div className=\"divide-y divide-slate-50\">\r\n                  {isLoading ? (\r\n                    <div className=\"p-8 text-center text-slate-400\">Cargando datos del servidor...<\/div>\r\n                  ) : agents.length === 0 ? (\r\n                    <div className=\"p-8 text-center text-slate-400\">No hay vendedores registrados.<\/div>\r\n                  ) : (\r\n                    agents.map(agent => (\r\n                      <div key={agent.id} className=\"p-4 flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between hover:bg-slate-50 transition-colors\">\r\n                        <div className=\"flex items-center gap-4\">\r\n                          <div className={`w-10 h-10 rounded-full flex items-center justify-center text-white font-bold shrink-0 ${agent.active ? 'bg-[#1a3a85]' : 'bg-slate-300'}`}>\r\n                            {agent.name.charAt(0).toUpperCase()}\r\n                          <\/div>\r\n                          <div>\r\n                            <p className=\"font-medium text-slate-900\">{agent.name}<\/p>\r\n                            <div className=\"flex items-center gap-2 mt-0.5\">\r\n                              <p className=\"text-xs text-slate-500\">{agent.phone}<\/p>\r\n                              <span className=\"text-[10px] bg-indigo-50 text-[#1a3a85] font-bold px-2 py-0.5 rounded-full border border-indigo-100\">\r\n                                {getLeadsToday(agent.name)} leads hoy\r\n                              <\/span>\r\n                            <\/div>\r\n                          <\/div>\r\n                        <\/div>\r\n                        <div className=\"flex items-center gap-2 w-full sm:w-auto justify-end\">\r\n                          <button \r\n                            onClick={() => toggleAgentStatus(agent.id)}\r\n                            className={`flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium transition-colors ${\r\n                              agent.active \r\n                                ? 'bg-[#1a3a85] text-white shadow-sm hover:bg-[#132b63]' \r\n                                : 'bg-slate-100 text-slate-600 hover:bg-slate-200'\r\n                            }`}\r\n                          >\r\n                            <Power className=\"w-3.5 h-3.5\" \/>\r\n                            {agent.active ? 'Activo' : 'Inactivo'}\r\n                          <\/button>\r\n                          <button \r\n                            onClick={() => deleteAgent(agent.id)}\r\n                            className=\"p-1.5 text-red-400 hover:text-red-600 hover:bg-red-50 rounded-full transition-colors\"\r\n                            title=\"Eliminar vendedor\"\r\n                          >\r\n                            <Trash2 className=\"w-4 h-4\" \/>\r\n                          <\/button>\r\n                        <\/div>\r\n                      <\/div>\r\n                    ))\r\n                  )}\r\n                <\/div>\r\n              <\/div>\r\n\r\n              {\/* FORMULARIO DE AGENTES *\/}\r\n              <form onSubmit={handleAddAgent} className=\"bg-white p-5 rounded-2xl shadow-lg border border-slate-100 flex flex-col gap-4\">\r\n                <div className=\"flex flex-col gap-3\">\r\n                  {\/* Fila 1: Nombre y Sucursal *\/}\r\n                  <div className=\"flex flex-1 gap-2 items-center bg-slate-50 border border-slate-200 rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-blue-500\">\r\n                    <input \r\n                      type=\"text\" \r\n                      placeholder=\"Nombre del asesor\" \r\n                      className=\"flex-1 px-4 py-2.5 bg-transparent focus:outline-none text-sm w-full\"\r\n                      value={newName}\r\n                      onChange={(e) => setNewName(e.target.value)}\r\n                    \/>\r\n                    <span className=\"text-slate-400 font-bold\">-<\/span>\r\n                    <input \r\n                      type=\"text\" \r\n                      placeholder=\"Sucursal (Ej. M\u00e9rida TX)\" \r\n                      className=\"flex-1 px-4 py-2.5 bg-transparent focus:outline-none text-sm w-full\"\r\n                      value={newBranch}\r\n                      onChange={(e) => setNewBranch(e.target.value)}\r\n                    \/>\r\n                  <\/div>\r\n\r\n                  {\/* Fila 2: C\u00f3digo de Pa\u00eds FIJO (Shrink-0), Tel\u00e9fono y Bot\u00f3n *\/}\r\n                  <div className=\"flex flex-col sm:flex-row gap-3\">\r\n                    <div className=\"flex flex-1 items-center bg-slate-50 border border-slate-200 rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-blue-500\">\r\n                      \r\n                      {\/* C\u00d3DIGO FIJO *\/}\r\n                      <span className=\"w-14 shrink-0 flex items-center justify-center bg-slate-100 border-r border-slate-200 text-slate-500 font-semibold text-sm select-none py-2.5\">\r\n                        +52\r\n                      <\/span>\r\n                      \r\n                      <input \r\n                        type=\"text\" \r\n                        placeholder=\"Ej. 999 000 0000\" \r\n                        className=\"flex-1 px-4 py-2.5 bg-transparent focus:outline-none text-sm w-full\"\r\n                        value={newPhone}\r\n                        onChange={(e) => setNewPhone(e.target.value.replace(\/\\D\/g, ''))} \/* Solo acepta n\u00fameros *\/\r\n                        maxLength=\"10\" \/* M\u00e1ximo de 10 d\u00edgitos *\/\r\n                      \/>\r\n                    <\/div>\r\n\r\n                    <button \r\n                      type=\"submit\"\r\n                      className=\"bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded-lg font-medium flex items-center justify-center gap-2 transition-colors disabled:opacity-50 text-sm sm:w-auto w-full shrink-0\"\r\n                      disabled={!newName || !newBranch || newPhone.length < 10}\r\n                    >\r\n                      <UserPlus className=\"w-4 h-4\" \/>\r\n                      A\u00f1adir\r\n                    <\/button>\r\n                  <\/div>\r\n                <\/div>\r\n              <\/form>\r\n            <\/div>\r\n\r\n            {\/* COLUMNA DERECHA: CONSOLA *\/}\r\n            <div className=\"lg:col-span-7 flex flex-col lg:relative min-h-[500px] lg:min-h-0\">\r\n              \r\n              {\/* CONSOLA NEGRA *\/}\r\n              <div className=\"bg-slate-900 text-slate-300 rounded-2xl shadow-lg overflow-hidden flex flex-col flex-1 lg:absolute lg:inset-0 w-full\">\r\n                <div className=\"flex border-b border-slate-800 bg-slate-950 items-center justify-between\">\r\n                  <div className=\"flex flex-1\">\r\n                    <button \r\n                      onClick={() => setActiveTab('bot')}\r\n                      className={`flex-1 py-3 text-sm font-semibold flex items-center justify-center gap-2 transition-colors ${activeTab === 'bot' ? 'text-white border-b-2 border-[#1a3a85] bg-slate-900' : 'text-slate-500 hover:text-slate-300 hover:bg-slate-900\/50'}`}\r\n                    >\r\n                      <Activity className=\"w-4 h-4\" \/> Bot en Vivo\r\n                      {activeTab === 'bot' && (\r\n                        <span className=\"flex h-2 w-2 ml-1\">\r\n                          <span className=\"animate-ping absolute inline-flex h-2 w-2 rounded-full bg-[#1a3a85] opacity-75\"><\/span>\r\n                          <span className=\"relative inline-flex rounded-full h-2 w-2 bg-[#1a3a85]\"><\/span>\r\n                        <\/span>\r\n                      )}\r\n                    <\/button>\r\n                    <button \r\n                      onClick={() => setActiveTab('sistema')}\r\n                      className={`flex-1 py-3 text-sm font-semibold flex items-center justify-center gap-2 transition-colors ${activeTab === 'sistema' ? 'text-white border-b-2 border-blue-500 bg-slate-900' : 'text-slate-500 hover:text-slate-300 hover:bg-slate-900\/50'}`}\r\n                    >\r\n                      <List className=\"w-4 h-4\" \/> Sistema Local\r\n                    <\/button>\r\n                  <\/div>\r\n                  \r\n                  {activeTab === 'bot' && (\r\n                    <div className=\"flex items-center gap-2 mr-3\">\r\n                      <button \r\n                        onClick={() => {\r\n                          fetchHistory();\r\n                          addLog('Historial de asignaciones actualizado manualmente.', 'info');\r\n                        }} \r\n                        className=\"px-3 py-1.5 text-xs font-medium text-blue-400 bg-blue-400\/10 hover:bg-blue-400\/20 border border-blue-400\/20 rounded-lg transition-colors flex items-center gap-1.5\"\r\n                        title=\"Forzar actualizaci\u00f3n de la lista\"\r\n                      >\r\n                        <RefreshCw className=\"w-4 h-4\" \/> \r\n                        <span className=\"hidden sm:inline\">Actualizar<\/span>\r\n                      <\/button>\r\n                      <button \r\n                        onClick={downloadCSV} \r\n                        className=\"px-3 py-1.5 text-xs font-medium text-[#4a7aff] bg-[#1a3a85]\/20 hover:bg-[#1a3a85]\/40 border border-[#1a3a85]\/30 rounded-lg transition-colors flex items-center gap-1.5\"\r\n                      >\r\n                        <Download className=\"w-4 h-4\" \/> \r\n                        <span className=\"hidden sm:inline\">Descargar CSV<\/span>\r\n                      <\/button>\r\n                    <\/div>\r\n                  )}\r\n                <\/div>\r\n\r\n                {activeTab === 'bot' && (\r\n                  <div className=\"bg-slate-800\/50 border-b border-slate-800 p-3 flex flex-col gap-3 text-xs\">\r\n                    <div className=\"flex items-center gap-2 overflow-x-auto pb-1\">\r\n                      <Calendar className=\"w-4 h-4 text-slate-400 shrink-0\" \/>\r\n                      <button onClick={clearFilters} className={`px-3 py-1.5 rounded-full whitespace-nowrap transition-colors ${!startDate && !endDate && !selectedAgent && !selectedBot ? 'bg-blue-600 text-white' : 'bg-slate-800 text-slate-400 hover:bg-slate-700'}`}>Todo<\/button>\r\n                      <button onClick={setToday} className=\"px-3 py-1.5 bg-slate-800 text-slate-400 hover:bg-slate-700 rounded-full whitespace-nowrap transition-colors\">Hoy<\/button>\r\n                      <button onClick={setYesterday} className=\"px-3 py-1.5 bg-slate-800 text-slate-400 hover:bg-slate-700 rounded-full whitespace-nowrap transition-colors\">Ayer<\/button>\r\n                    <\/div>\r\n                    \r\n                    <div className=\"flex flex-col sm:flex-row flex-wrap gap-2\">\r\n                      <div className=\"flex-1 min-w-[140px] flex items-center bg-slate-800 rounded px-2 py-1.5 border border-slate-700 focus-within:border-blue-500\">\r\n                        <span className=\"text-slate-500 mr-2 shrink-0\">Origen:<\/span>\r\n                        <select value={selectedBot} onChange={(e) => setSelectedBot(e.target.value)} className=\"bg-transparent text-slate-300 w-full focus:outline-none cursor-pointer appearance-none\">\r\n                          <option value=\"\">Todo<\/option>\r\n                          {Array.from(new Set(realHistory.map(r => getBotName(r.origen_bot)))).sort().map(bot => (\r\n                            <option key={bot} value={bot}>{bot}<\/option>\r\n                          ))}\r\n                        <\/select>\r\n                      <\/div>\r\n\r\n                      <div className=\"flex-1 min-w-[140px] flex items-center bg-slate-800 rounded px-2 py-1.5 border border-slate-700 focus-within:border-blue-500\">\r\n                        <span className=\"text-slate-500 mr-2 shrink-0\">Asesor:<\/span>\r\n                        <select value={selectedAgent} onChange={(e) => setSelectedAgent(e.target.value)} className=\"bg-transparent text-slate-300 w-full focus:outline-none cursor-pointer appearance-none\">\r\n                          <option value=\"\">Todos los asesores<\/option>\r\n                          {Array.from(new Set(realHistory.map(r => r.agent_name))).sort().map(name => (\r\n                            <option key={name} value={name}>{name}<\/option>\r\n                          ))}\r\n                        <\/select>\r\n                      <\/div>\r\n                      <div className=\"flex-1 min-w-[140px] flex items-center bg-slate-800 rounded px-2 py-1.5 border border-slate-700 focus-within:border-blue-500 date-picker-wrapper relative\">\r\n                        <span className=\"text-slate-500 mr-2 w-10 pointer-events-none\">Desde<\/span>\r\n                        <input \r\n                          type=\"datetime-local\" \r\n                          value={startDate} \r\n                          onChange={(e) => setStartDate(e.target.value)} \r\n                          className=\"bg-transparent text-slate-300 w-full focus:outline-none cursor-pointer pr-6\" \r\n                        \/>\r\n                        <Calendar className=\"w-4 h-4 text-slate-400 absolute right-2 pointer-events-none\" \/>\r\n                      <\/div>\r\n                      <div className=\"flex-1 min-w-[140px] flex items-center bg-slate-800 rounded px-2 py-1.5 border border-slate-700 focus-within:border-blue-500 date-picker-wrapper relative\">\r\n                        <span className=\"text-slate-500 mr-2 w-10 pointer-events-none\">Hasta<\/span>\r\n                        <input \r\n                          type=\"datetime-local\" \r\n                          value={endDate} \r\n                          onChange={(e) => setEndDate(e.target.value)} \r\n                          className=\"bg-transparent text-slate-300 w-full focus:outline-none cursor-pointer pr-6\" \r\n                        \/>\r\n                        <Calendar className=\"w-4 h-4 text-slate-400 absolute right-2 pointer-events-none\" \/>\r\n                      <\/div>\r\n                    <\/div>\r\n                  <\/div>\r\n                )}\r\n\r\n                <div className=\"p-4 flex-1 overflow-y-auto space-y-3 font-mono text-xs\">\r\n                  {activeTab === 'bot' ? (\r\n                    filteredHistory.length === 0 ? <p className=\"text-slate-600 text-center mt-4\">{realHistory.length === 0 ? 'Esperando actividad real...' : 'No hay registros en la fecha.'}<\/p> : \r\n                    filteredHistory.map(record => (\r\n                      <div key={record.id} className=\"flex gap-3 items-start border-b border-slate-800\/50 pb-2\">\r\n                        <span className=\"text-[#4a7aff]\/90 shrink-0 font-bold\">[{formatMySqlTime(record.fecha)}]<\/span>\r\n                        <span className=\"text-slate-300\">\r\n                          <span className=\"inline-block px-1.5 py-0.5 rounded text-[10px] font-bold bg-blue-500\/20 text-blue-400 mr-2 border border-blue-500\/20 uppercase\">\r\n                            {getBotName(record.origen_bot)}\r\n                          <\/span>\r\n                          Nuevo lead <span className=\"text-[#4a7aff]\">{record.lead_phone}<\/span> fue asignado a <span className=\"text-white font-semibold\">{record.agent_name}<\/span>.\r\n                        <\/span>\r\n                      <\/div>\r\n                    ))\r\n                  ) : (\r\n                    logs.length === 0 ? <p className=\"text-slate-600 text-center mt-4\">No hay avisos recientes.<\/p> : \r\n                    logs.map(log => (\r\n                      <div key={log.id} className=\"flex gap-3\">\r\n                        <span className=\"text-slate-500 shrink-0\">[{log.time}]<\/span>\r\n                        <span className={`${log.type === 'error' ? 'text-red-400' : ''} ${log.type === 'success' ? 'text-[#4a7aff]' : ''} ${log.type === 'warning' ? 'text-amber-400' : ''} ${log.type === 'info' ? 'text-blue-300' : ''}`}>\r\n                          {log.message}\r\n                        <\/span>\r\n                      <\/div>\r\n                    ))\r\n                  )}\r\n                <\/div>\r\n              <\/div>\r\n\r\n            <\/div>\r\n          <\/div>\r\n          \r\n          {\/* ========================================================= *\/}\r\n          {\/* SECCI\u00d3N SEPARADORA VISUAL *\/}\r\n          {\/* ========================================================= *\/}\r\n          <div className=\"relative py-8 mt-4\">\r\n            <div className=\"absolute inset-0 flex items-center\" aria-hidden=\"true\">\r\n              <div className=\"w-full border-t-2 border-slate-200 border-dashed\"><\/div>\r\n            <\/div>\r\n            <div className=\"relative flex justify-center\">\r\n              <span className=\"bg-white px-6 py-2 rounded-full text-xs text-slate-500 font-bold uppercase tracking-widest flex items-center gap-2 border border-slate-200 shadow-lg\">\r\n                Herramientas Adicionales\r\n              <\/span>\r\n            <\/div>\r\n          <\/div>\r\n\r\n          {\/* ========================================================= *\/}\r\n          {\/* NUEVA SECCI\u00d3N: RULETA GIRATORIA PARA SORTEOS MANUALES *\/}\r\n          {\/* ========================================================= *\/}\r\n          <div id=\"seccion-ruleta\" className=\"bg-white p-6 sm:p-8 rounded-2xl shadow-xl border border-slate-200 border-t-4 border-t-[#1a3a85] flex flex-col relative overflow-hidden\">\r\n            <div className=\"absolute top-0 right-0 w-64 h-64 bg-[#1a3a85]\/10 rounded-full blur-3xl opacity-60 -translate-y-1\/2 translate-x-1\/2 pointer-events-none\"><\/div>\r\n            \r\n            <div className=\"flex flex-col sm:flex-row items-center justify-between mb-8 border-b border-slate-100 pb-4 gap-4 relative z-10\">\r\n              <div>\r\n                <h2 className=\"text-xl font-bold flex items-center gap-2 text-slate-800\">\r\n                  <Repeat className=\"w-6 h-6 text-[#1a3a85]\" \/>\r\n                  Ruleta de Sorteo Manual\r\n                <\/h2>\r\n                <p className=\"text-sm text-slate-500 mt-1\">Ingresa los datos del prospecto y distrib\u00fayelo de forma justa y equitativa.<\/p>\r\n              <\/div>\r\n              <button\r\n                onClick={() => {\r\n                  fetchVendedores();\r\n                  addLog('Ruleta sincronizada manualmente con la Base de Datos.', 'info');\r\n                }}\r\n                className=\"flex items-center gap-2 px-5 py-2.5 text-sm font-bold text-white bg-slate-800 hover:bg-slate-700 rounded-lg transition-colors shadow-sm shrink-0\"\r\n                title=\"Sincronizar vendedores activos\"\r\n              >\r\n                <RefreshCw className=\"w-4 h-4\" \/>\r\n                Sincronizar Ruleta\r\n              <\/button>\r\n            <\/div>\r\n\r\n            <div className=\"flex flex-col lg:flex-row items-center justify-center gap-12 py-6 relative z-10\">\r\n              \r\n              <div className=\"relative w-64 h-64 sm:w-80 sm:h-80 shrink-0\">\r\n                <div className=\"absolute -top-4 left-1\/2 -translate-x-1\/2 z-30 drop-shadow-xl\">\r\n                  <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"#1e293b\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\">\r\n                    <path d=\"M12 22L3 4H21L12 22Z\" stroke=\"white\" strokeWidth=\"2\" strokeLinejoin=\"round\" \/>\r\n                  <\/svg>\r\n                <\/div>\r\n                \r\n                <div \r\n                  className=\"w-full h-full rounded-full border-[6px] sm:border-[8px] border-slate-800 shadow-2xl overflow-hidden relative bg-slate-200\"\r\n                  style={{ \r\n                    transform: `rotate(${rotation}deg)`, \r\n                    transition: 'transform 4s cubic-bezier(0.25, 0.1, 0.25, 1)' \r\n                  }}\r\n                >\r\n                   <div className=\"absolute inset-0 rounded-full shadow-[inset_0_0_30px_rgba(0,0,0,0.6)] z-20 pointer-events-none\"><\/div>\r\n\r\n                   <div \r\n                     className=\"absolute inset-0 z-0\" \r\n                     style={{ \r\n                       background: activeAgentsForRoulette.length > 0 \r\n                        ? `conic-gradient(from -${180 \/ activeAgentsForRoulette.length}deg, ${activeAgentsForRoulette.map((a, i) => {\r\n                             const slice = 360 \/ activeAgentsForRoulette.length;\r\n                             return `${rouletteColors[i % rouletteColors.length]} ${i * slice}deg ${(i+1) * slice}deg`;\r\n                           }).join(', ')})` \r\n                        : '#cbd5e1'\r\n                     }}\r\n                   ><\/div>\r\n                   \r\n                   {activeAgentsForRoulette.map((agent, i) => {\r\n                     const sliceAngle = 360 \/ activeAgentsForRoulette.length;\r\n                     const rotationAngle = i * sliceAngle;\r\n                     return (\r\n                       <div \r\n                         key={agent.id} \r\n                         className=\"absolute inset-0 z-10\" \r\n                         style={{ transform: `rotate(${rotationAngle}deg)` }}\r\n                       >\r\n                         <div \r\n                           className=\"absolute top-0 left-1\/2 w-1 sm:w-1.5 h-1\/2 bg-slate-800 origin-bottom\"\r\n                           style={{ \r\n                             transform: `translateX(-50%) rotate(${sliceAngle \/ 2}deg)`,\r\n                             borderRadius: '2px'\r\n                           }}\r\n                         ><\/div>\r\n\r\n                         <div \r\n                           className=\"absolute top-6 sm:top-8 left-1\/2 -translate-x-1\/2 text-white font-black text-xs sm:text-sm uppercase tracking-wider\" \r\n                           style={{ textShadow: '0 2px 6px rgba(0,0,0,0.9), 0 0 2px rgba(0,0,0,1)' }}\r\n                         >\r\n                           {agent.name.split('-')[0].trim()}\r\n                         <\/div>\r\n                       <\/div>\r\n                     )\r\n                   })}\r\n                <\/div>\r\n                \r\n                <div className=\"absolute top-1\/2 left-1\/2 -translate-x-1\/2 -translate-y-1\/2 w-12 h-12 sm:w-16 sm:h-16 bg-slate-800 rounded-full border-4 border-slate-700 shadow-xl flex items-center justify-center z-30\">\r\n                  <div className=\"w-4 h-4 bg-slate-300 rounded-full shadow-inner\"><\/div>\r\n                <\/div>\r\n              <\/div>\r\n\r\n              <div className=\"flex flex-col items-center lg:items-start text-center lg:text-left space-y-4 max-w-sm w-full\">\r\n                \r\n                {\/* --- CAMPOS PARA CAPTURAR AL LEAD ANTES DE GIRAR --- *\/}\r\n                <div className=\"w-full space-y-3 bg-slate-50 p-4 rounded-xl border border-slate-200\">\r\n                  <p className=\"text-xs font-bold text-slate-500 uppercase tracking-wide\">Datos del Prospecto<\/p>\r\n                  \r\n                  <input \r\n                    type=\"text\" \r\n                    placeholder=\"Nombre en Facebook\/Instagram (Opcional)\" \r\n                    className=\"w-full px-4 py-2 bg-white border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#1a3a85] text-sm\"\r\n                    value={ruletaLeadName}\r\n                    onChange={(e) => setRuletaLeadName(e.target.value)}\r\n                  \/>\r\n                  \r\n                  <div className=\"flex items-center bg-white border border-slate-300 rounded-lg overflow-hidden focus-within:ring-2 focus-within:ring-[#1a3a85]\">\r\n                    <span className=\"px-3 py-2 bg-slate-100 border-r border-slate-200 text-slate-500 text-sm font-medium select-none\">+52<\/span>\r\n                    <input \r\n                      type=\"text\" \r\n                      placeholder=\"Tel\u00e9fono (Obligatorio, Ej. 9990000000)\" \r\n                      className=\"w-full px-3 py-2 bg-transparent focus:outline-none text-sm\"\r\n                      value={ruletaLeadPhone}\r\n                      onChange={(e) => setRuletaLeadPhone(e.target.value.replace(\/\\D\/g, ''))}\r\n                      maxLength=\"10\"\r\n                    \/>\r\n                  <\/div>\r\n                <\/div>\r\n                \r\n                <button \r\n                  onClick={spinRoulette}\r\n                  disabled={isSpinning || activeAgentsForRoulette.length === 0 || ruletaLeadPhone.length < 10}\r\n                  className={`w-full py-4 rounded-xl font-black text-white text-lg shadow-lg transition-all transform active:scale-95 flex items-center justify-center gap-2 ${isSpinning || activeAgentsForRoulette.length === 0 || ruletaLeadPhone.length < 10 ? 'bg-slate-400 cursor-not-allowed' : 'bg-[#1a3a85] hover:bg-[#132b63] hover:-translate-y-1'}`}\r\n                >\r\n                  {isSpinning ? (\r\n                    <><RefreshCw className=\"w-5 h-5 animate-spin\" \/> Sorteando...<\/>\r\n                  ) : (\r\n                    <><Repeat className=\"w-5 h-5\" \/> Girar Ruleta<\/>\r\n                  )}\r\n                <\/button>\r\n                \r\n                <div className=\"h-28 flex flex-col items-center justify-center w-full border-2 border-dashed border-slate-200 rounded-xl bg-slate-50\">\r\n                  {raffleWinner && !isSpinning ? (\r\n                    <div className=\"animate-bounce flex flex-col items-center\">\r\n                      <p className=\"text-xs text-slate-400 uppercase tracking-widest font-bold mb-1\">Ganador de la Ruleta:<\/p>\r\n                      <div className=\"text-2xl font-black text-[#1a3a85] px-6\">\r\n                        \ud83c\udf89 {raffleWinner.name.split('-')[0].trim()}\r\n                      <\/div>\r\n                    <\/div>\r\n                  ) : isSpinning ? (\r\n                    <p className=\"text-slate-400 font-medium animate-pulse\">Eligiendo asesor...<\/p>\r\n                  ) : (\r\n                    <p className=\"text-slate-400 font-medium text-sm\">Completa el n\u00famero para girar<\/p>\r\n                  )}\r\n                <\/div>\r\n              <\/div>\r\n\r\n            <\/div>\r\n          <\/div>\r\n\r\n        <\/div>\r\n      <\/div>\r\n    );\r\n  }\r\n\r\n  const root = ReactDOM.createRoot(document.getElementById('distribuidor-leads-root'));\r\n  root.render(<App \/>);\r\n<\/script>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/pages\/900"}],"collection":[{"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/comments?post=900"}],"version-history":[{"count":95,"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/pages\/900\/revisions"}],"predecessor-version":[{"id":1000,"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/pages\/900\/revisions\/1000"}],"wp:attachment":[{"href":"https:\/\/mudanzasmt.com\/index.php\/wp-json\/wp\/v2\/media?parent=900"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}