{"id":3827,"date":"2025-07-31T16:22:56","date_gmt":"2025-07-31T15:22:56","guid":{"rendered":"https:\/\/strattonapps.com\/?page_id=3827"},"modified":"2025-07-31T16:44:22","modified_gmt":"2025-07-31T15:44:22","slug":"bot-globito-academy","status":"publish","type":"page","link":"https:\/\/strattonapps.com\/es\/bot-globito-academy\/","title":{"rendered":"bot globito academy"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"3827\" class=\"elementor elementor-3827\">\n\t\t\t\t\t\t<div class=\"elementor-inner\">\n\t\t\t\t<div class=\"elementor-section-wrap\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-a3bf9f5 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"a3bf9f5\" 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\t\t<div class=\"elementor-row\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b694864\" data-id=\"b694864\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-column-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9cbbdd5 elementor-widget elementor-widget-html\" data-id=\"9cbbdd5\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<script>\n(function() {\n  \/\/ <<< INICIO: Bloque para evitar reinicializaci\u00f3n >>>\n  if (window.floatingChatInitialized) {\n    console.warn('Floating Chat: Intento de reinicializaci\u00f3n, omitiendo.');\n    return;\n  }\n  window.floatingChatInitialized = true;\n  \/\/ <<< FIN: Bloque para evitar reinicializaci\u00f3n >>>\n\n  const WEBHOOK_URL = 'https:\/\/primary-production-dbbe.up.railway.app\/webhook\/racks-academy';\n  const IDs = {\n    button: 'floating-chat-button',\n    window: 'floating-chat-window',\n    body: 'floating-chat-body',\n    input: 'floating-chat-input',\n    sendBtn: 'floating-chat-send',\n    typingIndicator: 'floating-chat-typing-indicator',\n    greeting: 'floating-chat-greeting'\n  };\n  const CHAT_HISTORY_KEY = 'racksChatHistory';\n  const GREETING_SHOWN_KEY = 'racksGreetingShown';\n\n  let chatBodyEl;\n\n  \/\/ --- Funciones de Ayuda ---\n  function addMessageToUI(type, content, isHtml = false) {\n    if (!chatBodyEl) return;\n    const bubble = document.createElement('div');\n    bubble.className = type === 'user' ? 'user-bubble' : 'server-bubble';\n    if (isHtml && type === 'server') {\n      bubble.innerHTML = content;\n    } else {\n      bubble.textContent = content;\n    }\n    chatBodyEl.appendChild(bubble);\n    chatBodyEl.scrollTop = chatBodyEl.scrollHeight;\n  }\n\n  function saveMessageToHistory(type, content, isHtml = false) {\n    try {\n      const history = JSON.parse(localStorage.getItem(CHAT_HISTORY_KEY)) || [];\n      history.push({ type, content, isHtml, timestamp: new Date().toISOString() });\n      localStorage.setItem(CHAT_HISTORY_KEY, JSON.stringify(history));\n    } catch (e) {\n      console.error(\"Error guardando historial en localStorage:\", e);\n    }\n  }\n\n  function loadChatHistory() {\n    if (!chatBodyEl) return;\n    try {\n      const history = JSON.parse(localStorage.getItem(CHAT_HISTORY_KEY));\n      if (history && Array.isArray(history)) {\n        history.forEach(msg => addMessageToUI(msg.type, msg.content, msg.isHtml));\n      }\n    } catch (e) {\n      console.error(\"Error cargando historial desde localStorage:\", e);\n    }\n  }\n\n  function showTypingIndicator() {\n    if (!chatBodyEl || document.getElementById(IDs.typingIndicator)) return;\n    const indicatorBubble = document.createElement('div');\n    indicatorBubble.id = IDs.typingIndicator;\n    indicatorBubble.className = 'server-bubble typing-indicator';\n    indicatorBubble.innerHTML = `<span><\/span><span><\/span><span><\/span>`;\n    chatBodyEl.appendChild(indicatorBubble);\n    chatBodyEl.scrollTop = chatBodyEl.scrollHeight;\n  }\n\n  function hideTypingIndicator() {\n    const indicator = document.getElementById(IDs.typingIndicator);\n    if (indicator) indicator.remove();\n  }\n  \/\/ --- Fin Funciones de Ayuda ---\n\n  function init() {\n    if (document.getElementById(IDs.button)) return;\n\n    \/\/ --- INICIO: Importaci\u00f3n de fuentes de Google ---\n    const fontLink1 = document.createElement('link'); fontLink1.rel = 'preconnect'; fontLink1.href = 'https:\/\/fonts.googleapis.com';\n    const fontLink2 = document.createElement('link'); fontLink2.rel = 'preconnect'; fontLink2.href = 'https:\/\/fonts.gstatic.com'; fontLink2.crossOrigin = 'true';\n    const fontLink3 = document.createElement('link'); fontLink3.rel = 'stylesheet'; fontLink3.href = 'https:\/\/fonts.googleapis.com\/css2?family=Bai+Jamjuree:wght@700&family=Inter:wght@400;600&display=swap';\n    document.head.appendChild(fontLink1);\n    document.head.appendChild(fontLink2);\n    document.head.appendChild(fontLink3);\n    \/\/ --- FIN: Importaci\u00f3n de fuentes ---\n\n    const style = document.createElement('style');\n    \/\/ --- INICIO DE ESTILOS COMPLETOS ---\n    style.textContent = `\n      :root {\n        --chat-primary-color: #92400e; --chat-primary-hover: #c97a2a;\n        --chat-font-body: \"Inter\", sans-serif; --chat-font-header: \"Bai Jamjuree\", sans-serif;\n        --chat-bg-dark: #1a1a1c; --chat-border-dark: #2f2f31; --chat-text-light: #fff;\n        --chat-text-dark: #1a1a1c; --chat-server-bubble: #2a2a2e;\n      }\n      #${IDs.button}, #${IDs.window}, #${IDs.input}, #${IDs.sendBtn}, #${IDs.greeting} { font-family: var(--chat-font-body); }\n      #${IDs.button} {\n        position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; border-radius: 50%;\n        background: var(--chat-primary-color); display: flex; align-items: center; justify-content: center;\n        border: none; cursor: pointer; box-shadow: 0 5px 20px rgba(232, 140, 48, 0.25);\n        transition: transform .3s, background-color .3s; z-index: 10000;\n      }\n      #${IDs.button}:hover { transform: scale(1.05); background-color: var(--chat-primary-hover); }\n      #${IDs.button} svg { width: 32px; height: 32px; fill: var(--chat-text-light); }\n\n      #${IDs.greeting} {\n        position: fixed; bottom: 95px; right: 20px; background: var(--chat-server-bubble);\n        color: var(--chat-text-light); padding: 14px 20px; padding-right: 45px; border-radius: 16px;\n        box-shadow: 0 5px 25px rgba(0,0,0,0.3); max-width: 280px; font-size: 14px; line-height: 1.5;\n        cursor: pointer; z-index: 9999; opacity: 0; transform: translateY(10px);\n        transition: opacity 0.4s ease, transform 0.4s ease; display: none;\n      }\n      #${IDs.greeting}.visible { display: block; opacity: 1; transform: translateY(0); }\n      #${IDs.greeting}::after {\n        content: ''; position: absolute; bottom: -8px; right: 25px; width: 0; height: 0;\n        border: 8px solid transparent; border-top-color: var(--chat-server-bubble);\n      }\n      #${IDs.greeting}-close {\n        position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; border: none;\n        background: transparent; color: #aaa; font-size: 20px; cursor: pointer; line-height: 24px; text-align: center;\n      }\n      #${IDs.greeting}-close:hover { color: #fff; }\n\n      #${IDs.window} {\n        position: fixed; bottom: 90px; right: 20px; width: 380px; max-height: 65vh;\n        background: var(--chat-bg-dark); border: 1px solid var(--chat-border-dark); border-radius: 16px;\n        box-shadow: 0 10px 40px rgba(0,0,0,0.3); display: none; flex-direction: column;\n        overflow: hidden; z-index: 9999; color: var(--chat-text-light);\n      }\n      #${IDs.window} header {\n        font-family: var(--chat-font-header); padding: 18px 20px; font-size: 1em; font-weight: 300;\n        color: var(--chat-text-light); border-bottom: 1px solid var(--chat-border-dark);\n        background: var(--chat-bg-dark); text-align: left;\n      }\n      #${IDs.body} { flex: 1; padding: 16px; overflow-y: auto; background: var(--chat-bg-dark); }\n      #${IDs.body}::-webkit-scrollbar { width: 6px; }\n      #${IDs.body}::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }\n      #${IDs.body}::-webkit-scrollbar-track { background: var(--chat-bg-dark); }\n      #${IDs.body} .user-bubble, #${IDs.body} .server-bubble {\n        padding: 12px 16px; border-radius: 18px; max-width: 85%; margin: 10px 0;\n        font-size: 15px; line-height: 1.5; word-wrap: break-word; box-shadow: 0 2px 4px rgba(0,0,0,0.2); clear: both;\n      }\n      #${IDs.body} .user-bubble {\n        background: var(--chat-primary-color); color: #fff; border-bottom-right-radius: 4px; float: right; font-size: 13px;\n      }\n      #${IDs.body} .server-bubble {\n        background: var(--chat-server-bubble); color: var(--chat-text-light); border-bottom-left-radius: 4px; float: left; font-size: 13px;\n      }\n      #${IDs.body} .server-bubble a { color: var(--chat-primary-color); text-decoration: underline; font-weight: 600; }\n      .typing-indicator span { background-color: #777; height: 8px; width: 8px; border-radius: 50%; display: inline-block; margin: 0 2px; animation: bounce 1.4s infinite ease-in-out both; }\n      .typing-indicator span:nth-child(1) { animation-delay: -0.32s; } .typing-indicator span:nth-child(2) { animation-delay: -0.16s; }\n      @keyframes bounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1.0); } }\n      .chat-input-container { display: flex; padding: 12px; border-top: 1px solid var(--chat-border-dark); background: var(--chat-bg-dark); }\n      #${IDs.input} { flex: 1; padding: 12px 15px; font-size: 15px; border: 1px solid var(--chat-border-dark); background-color: var(--chat-server-bubble); color: var(--chat-text-light); border-radius: 10px; outline: none; margin-right: 10px; transition: border-color .2s; }\n      #${IDs.input}::placeholder { color: #888; }\n      #${IDs.input}:focus { border-color: var(--chat-primary-color); }\n      #${IDs.sendBtn} { padding: 12px 20px; background: var(--chat-primary-color); color: var(--chat-text-light); border: none; border-radius: 10px; cursor: pointer; font-weight: 600; font-size: 15px; transition: background-color .2s; text-transform: uppercase;}\n      #${IDs.sendBtn}:hover { background: var(--chat-primary-hover); }\n      @media (max-width: 600px) {\n        #${IDs.button} { width: 55px; height: 55px; bottom: 16px; right: 16px; }\n        #${IDs.button} svg { width: 28px; height: 28px; }\n        #${IDs.greeting} { width: calc(100% - 48px); right: 16px; bottom: 85px; }\n        #${IDs.window} { width: calc(100% - 32px); height: 75vh; max-height: none; right: 16px; bottom: 80px; }\n      }\n    `;\n    \/\/ --- FIN DE ESTILOS ---\n    document.head.appendChild(style);\n\n    \/\/ --- Creaci\u00f3n de elementos HTML ---\n    const btn = document.createElement('button');\n    btn.id = IDs.button;\n    btn.type = 'button';\n    btn.setAttribute('aria-label', 'Abrir chat');\n    btn.innerHTML = '<svg viewBox=\"0 0 24 24\"><path d=\"M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z\"\/><\/svg>';\n    document.body.appendChild(btn);\n    \n    const greetingBubble = document.createElement('div');\n    greetingBubble.id = IDs.greeting;\n    greetingBubble.innerHTML = `\n        <span>\u00bfTienes alguna pregunta? Estoy para ayudarte.<\/span>\n        <button id=\"${IDs.greeting}-close\" aria-label=\"Cerrar saludo\">\u00d7<\/button>\n    `;\n    document.body.appendChild(greetingBubble);\n\n    const win = document.createElement('div');\n    win.id = IDs.window;\n    win.setAttribute('role', 'log');\n    win.setAttribute('aria-live', 'polite');\n    win.innerHTML = `\n      <header>Racks Academy<\/header>\n      <div id=\"${IDs.body}\"><\/div>\n      <div class=\"chat-input-container\">\n        <input id=\"${IDs.input}\" type=\"text\" placeholder=\"Escribe tu duda...\" autocomplete=\"off\" aria-label=\"Mensaje a enviar\" \/>\n        <button id=\"${IDs.sendBtn}\" type=\"button\" aria-label=\"Enviar mensaje\">Enviar<\/button>\n      <\/div>\n    `;\n    document.body.appendChild(win);\n\n    chatBodyEl = document.getElementById(IDs.body);\n    const inputEl = document.getElementById(IDs.input);\n    const sendBtn = document.getElementById(IDs.sendBtn);\n    const greetingCloseBtn = document.getElementById(`${IDs.greeting}-close`);\n\n    if (!chatBodyEl || !inputEl || !sendBtn) {\n        console.error('Chat init: Error al obtener elementos del DOM.');\n        return;\n    }\n\n    loadChatHistory();\n\n    \/\/ --- L\u00f3gica de saludo ---\n    const hideGreeting = () => {\n        greetingBubble.classList.remove('visible');\n        sessionStorage.setItem(GREETING_SHOWN_KEY, 'true');\n    };\n    \n    if (!sessionStorage.getItem(GREETING_SHOWN_KEY)) {\n        setTimeout(() => {\n            if (win.style.display !== 'flex') {\n                greetingBubble.classList.add('visible');\n            }\n        }, 3000);\n    }\n    \n    greetingCloseBtn.addEventListener('click', (e) => {\n        e.stopPropagation();\n        hideGreeting();\n    });\n    \n    greetingBubble.addEventListener('click', () => {\n        hideGreeting();\n        const isOpen = win.style.display === 'flex';\n        if (isOpen) return;\n\n        win.style.display = 'flex';\n        btn.setAttribute('aria-label', 'Cerrar chat');\n\n        try {\n            const history = JSON.parse(localStorage.getItem(CHAT_HISTORY_KEY)) || [];\n            if (history.length === 0) {\n                sendMessage(\"\u00a1Hola! \ud83d\udc4b Me gustar\u00eda recibir m\u00e1s informaci\u00f3n.\");\n            } else {\n                inputEl.focus();\n            }\n        } catch (e) {\n            console.error(\"Error al leer historial para saludo autom\u00e1tico:\", e);\n            inputEl.focus();\n        }\n        \n        setTimeout(() => {\n            if(chatBodyEl) chatBodyEl.scrollTop = chatBodyEl.scrollHeight;\n        }, 50);\n    });\n    \n    btn.addEventListener('click', () => {\n      hideGreeting(); \n      const isOpen = win.style.display === 'flex';\n      win.style.display = isOpen ? 'none' : 'flex';\n      btn.setAttribute('aria-label', isOpen ? 'Abrir chat' : 'Cerrar chat');\n      if (win.style.display === 'flex') {\n          if(inputEl) inputEl.focus();\n          if(chatBodyEl) chatBodyEl.scrollTop = chatBodyEl.scrollHeight;\n      }\n    });\n\n    \/\/ --- Funci\u00f3n sendMessage ---\n    async function sendMessage(predefinedMessage = null) {\n      const msg = predefinedMessage || inputEl.value.trim();\n      if (!msg) return;\n\n      addMessageToUI('user', msg);\n      saveMessageToHistory('user', msg);\n      \n      if (!predefinedMessage) {\n        inputEl.value = '';\n      }\n      inputEl.focus();\n\n      showTypingIndicator();\n\n      try {\n        const payload = { message: msg, timestamp: new Date().toISOString(), url: window.location.href };\n        const response = await fetch(WEBHOOK_URL, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application\/json' },\n          body: JSON.stringify(payload)\n        });\n        \n        hideTypingIndicator();\n\n        if (!response.ok) {\n          const errorText = await response.text();\n          throw new Error(`Error del servidor: ${response.status}. Respuesta: ${errorText}`);\n        }\n\n        const contentType = response.headers.get(\"content-type\");\n        if (contentType && contentType.includes(\"application\/json\")) {\n            const data = await response.json();\n            if (data.responseMessage) {\n              addMessageToUI('server', data.responseMessage, true);\n              saveMessageToHistory('server', data.responseMessage, true);\n            } else {\n              addMessageToUI('server', \"Respuesta inesperada del servidor.\");\n              saveMessageToHistory('server', \"Respuesta inesperada del servidor.\");\n            }\n        } else {\n            const textData = await response.text();\n            addMessageToUI('server', textData);\n            saveMessageToHistory('server', textData);\n        }\n      } catch (err) {\n        console.error('Chat sendMessage: Error:', err);\n        hideTypingIndicator();\n        let errorMsg = \"Error al enviar mensaje. Intenta de nuevo.\";\n        if (err instanceof TypeError && err.message.toLowerCase().includes(\"failed to fetch\")) {\n            errorMsg = \"Error de red. No se pudo conectar con el servidor.\";\n        }\n        addMessageToUI('server', errorMsg);\n        saveMessageToHistory('server', errorMsg);\n      }\n    }\n\n    sendBtn.addEventListener('click', () => sendMessage());\n    inputEl.addEventListener('keydown', e => {\n      if (e.key === 'Enter' && !e.shiftKey) {\n        e.preventDefault();\n        sendMessage();\n      }\n    });\n  }\n\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', init);\n  } else {\n    init();\n  }\n})();\n<\/script>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":[],"_links":{"self":[{"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/pages\/3827"}],"collection":[{"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/comments?post=3827"}],"version-history":[{"count":16,"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/pages\/3827\/revisions"}],"predecessor-version":[{"id":3844,"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/pages\/3827\/revisions\/3844"}],"wp:attachment":[{"href":"https:\/\/strattonapps.com\/es\/wp-json\/wp\/v2\/media?parent=3827"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}