PageSourceSearch

https://xmatica.ai/js/chatbot.js

js xmatica.ai collected 2026-10-05 14:21:27 UTC 8,857 bytes, 276 lines download raw bytes

1document.addEventListener("DOMContentLoaded", () => {
2  /*────────────── CONFIG ──────────────*/
3  const WEBHOOK =
4    "https://n8n.xmatica.ai/webhook/f505c057-6040-4cad-9652-4f7be4ffd8d4/chat";
5
6  /*────────────── SESIÓN ──────────────*/
7  const getSessionId = () => {
8    let sid = localStorage.getItem("chatSessionId");
9    if (!sid) {
10      sid = `session-${Date.now()}`;
11      localStorage.setItem("chatSessionId", sid);
12    }
13    return sid;
14  };
15
16  /*────────── CARGA RECURSOS ──────────*/
17  const fa = document.createElement("link");
18  fa.rel = "stylesheet";
19  fa.href =
20    "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css";
21  document.head.appendChild(fa);
22
23  const css = document.createElement("style");
24  css.textContent = `
25  /* Botón flotante */
26  #chatbot-button{
27    position:fixed!important;
28    bottom:20px;
29    right:20px;
30    width:60px;
31    height:60px;
32    background:#007BFF;
33    color:#fff;
34    border-radius:50%;
35    display:flex;
36    align-items:center;
37    justify-content:center;
38    box-shadow:0 4px 10px rgba(0,0,0,.3);
39    cursor:pointer;
40    transition:transform .2s ease-in-out;
41    z-index:9999;
42  }
43  #chatbot-button:hover{transform:scale(1.1);}
44  #chatbot-button i{font-size:24px;}
45
46  /* Ventana de chat */
47  #chat-container{
48    position:fixed!important;
49    bottom:90px;
50    right:20px;
51    width:350px;
52    max-width:90%;
53    height:500px;
54    background:#fff;
55    border-radius:10px;
56    box-shadow:0 8px 15px rgba(0,0,0,.3);
57    display:none;
58    flex-direction:column;
59    z-index:9998;
60    resize:both;
61    overflow:hidden;
62  }
63
64  /* Encabezado */
65  #chat-header{
66    background:#007BFF;
67    color:#fff;
68    padding:10px;
69    border-top-left-radius:10px;
70    border-top-right-radius:10px;
71    font-size:16px;
72    font-weight:bold;
73    display:flex;
74    justify-content:space-between;
75    align-items:center;
76    cursor:move;
77  }
78  #maximize-button{background:none;border:none;color:#fff;font-size:16px;cursor:pointer;}
79
80  /* Área de mensajes */
81  #messages{
82    flex-grow:1;
83    overflow-y:auto;
84    padding:10px;
85    background:#f9f9f9;
86    border-radius:0 0 10px 10px;
87  }
88  .message{margin-bottom:10px;display:flex;align-items:flex-start;}
89  .message.user{justify-content:flex-end;}
90  .message.bot{justify-content:flex-start;}
91  .bubble{
92    max-width:70%;
93    padding:12px;
94    border-radius:20px;
95    font-size:14px;
96    line-height:1.5;
97  }
98  .message.bot .bubble{background:#f1f0f0;color:#333;border-radius:20px 20px 20px 0;}
99  .message.user .bubble{background:#007BFF;color:#fff;border-radius:20px 20px 0 20px;}
100
101  .icon{width:30px;height:30px;margin:0 10px;display:flex;align-items:center;justify-content:center;}
102  .message.bot .icon i,
103  .message.user .icon i{font-size:20px;color:#007BFF;}
104
105  /* Input */
106  #input-container{display:flex;padding:10px;border-top:1px solid #ddd;background:#fff;}
107  #message-input{flex:1;padding:10px;border:1px solid #ddd;border-radius:5px;}
108  #send-button{margin-left:10px;padding:10px 20px;background:#007BFF;color:#fff;border:none;border-radius:5px;cursor:pointer;}
109  #send-button:hover{background:#0056b3;}
110
111  /* Indicador “escribiendo” */
112  .typing-indicator{display:flex;align-items:center;margin-top:5px;}
113  .dot{
114    width:8px;height:8px;margin:0 3px;
115    background:gray;border-radius:50%;
116    animation:typing 1.5s infinite;
117  }
118  .dot:nth-child(2){animation-delay:.3s;}
119  .dot:nth-child(3){animation-delay:.6s;}
120  @keyframes typing{0%,100%{opacity:.2;}50%{opacity:1;}}
121  `;
122  document.head.appendChild(css);
123
124  /*────────── CREAR ELEMENTOS ─────────*/
125  const btn = document.createElement("div");
126  btn.id = "chatbot-button";
127  btn.innerHTML = '<i class="fa-solid fa-robot"></i>';
128  document.body.appendChild(btn);
129
130  const chat = document.createElement("div");
131  chat.id = "chat-container";
132  chat.innerHTML = `
133    <div id="chat-header">
134      Chatbot
135      <button id="maximize-button"><i class="fa-solid fa-expand"></i></button>
136    </div>
137    <div id="messages"></div>
138    <div id="input-container">
139      <input id="message-input" type="text" placeholder="Escribe tu mensaje..." autocomplete="off">
140      <button id="send-button">Enviar</button>
141    </div>`;
142  document.body.appendChild(chat);
143
144  /*──────────── MOSTRAR/OCULTAR ───────*/
145  btn.onclick = () => {
146    chat.style.display = chat.style.display === "flex" ? "none" : "flex";
147  };
148
149  let maximized = false;
150  document.getElementById("maximize-button").onclick = (e) => {
151    const nav = document.querySelector("nav");
152    maximized = !maximized;
153    if (maximized) {
154      chat.style.cssText =
155        "display:flex;width:calc(100% - 20px);height:calc(100% - 40px);bottom:20px;right:20px;border-radius:10px;resize:none";
156      btn.style.display = "none";
157      if (nav) nav.style.display = "none";
158      e.target.innerHTML = '<i class="fa-solid fa-compress"></i>';
159    } else {
160      chat.style.cssText =
161        "display:flex;width:350px;height:500px;bottom:90px;right:20px;resize:both";
162      btn.style.display = "flex";
163      if (nav) nav.style.display = "flex";
164      e.target.innerHTML = '<i class="fa-solid fa-expand"></i>';
165    }
166  };
167
168  /*────────── FUNCIONES AUX ───────────*/
169  const msgDiv = () => document.getElementById("messages");
170
171  const appendTyping = () => {
172    const div = document.createElement("div");
173    div.className = "message bot";
174    div.innerHTML = `
175      <div class="icon"><i class="fa-solid fa-robot"></i></div>
176      <div class="bubble"><div class="typing-indicator">
177        <span class="dot"></span><span class="dot"></span><span class="dot"></span>
178      </div></div>`;
179    msgDiv().appendChild(div);
180    msgDiv().scrollTop = msgDiv().scrollHeight;
181    return div.querySelector(".bubble");
182  };
183
184  const sendReq = async (text) => {
185    const res = await fetch(WEBHOOK, {
186      method: "POST",
187      headers: { "Content-Type": "application/json" },
188      body: JSON.stringify({
189        message: text,
190        sessionId: getSessionId(),
191        origen: "chatweb",
192      }),
193    });
194    return res.json();
195  };
196
197  const sendUserMsg = async (text) => {
198    const ud = document.createElement("div");
199    ud.className = "message user";
200    ud.innerHTML = `<div class="bubble">${text}</div><div class="icon"><i class="fa-solid fa-user"></i></div>`;
201    msgDiv().appendChild(ud);
202
203    const bub = appendTyping();
204    try {
205      const data = await sendReq(text);
206      bub.innerHTML = (data.response || "Sin respuesta.").replace(
207        /\n/g,
208        "<br>"
209      );
210    } catch {
211      bub.textContent = "Error al conectar.";
212    }
213    msgDiv().scrollTop = msgDiv().scrollHeight;
214  };
215
216  const sendHidden = async (text) => {
217    const bub = appendTyping();
218    try {
219      const data = await sendReq(text);
220      bub.innerHTML = (data.response || "Sin respuesta.").replace(
221        /\n/g,
222        "<br>"
223      );
224    } catch {
225      bub.textContent = "Error al conectar.";
226    }
227  };
228
229  /*───────── EVENTOS MENSAJE ──────────*/
230  document.body.addEventListener("click", (e) => {
231    if (e.target.id === "send-button") {
232      const inp = document.getElementById("message-input");
233      const val = inp.value.trim();
234      if (val) {
235        inp.value = "";
236        sendUserMsg(val);
237      }
238    }
239  });
240  document.body.addEventListener("keypress", (e) => {
241    if (e.key === "Enter") {
242      const inp = document.getElementById("message-input");
243      const val = inp.value.trim();
244      if (val) {
245        inp.value = "";
246        sendUserMsg(val);
247      }
248    }
249  });
250
251  /*───── FORMULARIO FOOTER → BOT ─────*/
252  document.body.addEventListener("click", async (e) => {
253    if (e.target.id !== "contact-submit") return;
254    e.preventDefault();
255    const n = document.getElementById("contact-name")?.value.trim();
256    const m = document.getElementById("contact-email")?.value.trim();
257    if (!n || !m) {
258      alert("Completá nombre y correo.");
259      return;
260    }
261    chat.style.display = "flex"; // abre chat
262    await sendHidden(
263      `Me conecte por la web de xmatica, quisiera saber de que se trata los servicios de uds: Nombre=${n}, Email=${m}`
264    );
265    document.getElementById("contact-name").value = "";
266    document.getElementById("contact-email").value = "";
267  });
268
269  /*───────── AUTOOPEN opcional ────────*/
270  if (new URLSearchParams(location.search).get("autoOpen") === "true") {
271    chat.style.display = "flex";
272    sendHidden("Hola, vine de la invitación en redes y quiero ver la demo.");
273  }
274
275  console.log("🚀 Chatbot JS cargado");
276});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.