/* Gogo Telefon chat widget — embeddable, dependency-free (§7). * * Usage on the salon's site: * */ (function () { "use strict"; var script = document.currentScript || document.querySelector("script[data-gogo-key]"); if (!script) return; var KEY = script.getAttribute("data-gogo-key"); if (!KEY) return; var BASE = (function () { try { var u = new URL(script.src); return u.origin; } catch (e) { return ""; } })(); var WS_BASE = BASE.replace(/^http/, "ws"); var STORE = "gogo_chat_" + KEY; /* ---------- styles ---------- */ var css = ".gogo-bubble{position:fixed;bottom:20px;right:20px;width:56px;height:56px;border-radius:50%;" + "background:#7c3aed;color:#fff;border:none;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,.25);" + "font-size:26px;z-index:999999;display:flex;align-items:center;justify-content:center}" + ".gogo-panel{position:fixed;bottom:88px;right:20px;width:340px;max-width:calc(100vw - 32px);" + "height:480px;max-height:calc(100vh - 120px);background:#fff;border-radius:14px;z-index:999999;" + "box-shadow:0 8px 30px rgba(0,0,0,.3);display:none;flex-direction:column;overflow:hidden;" + "font-family:system-ui,sans-serif}" + ".gogo-panel.open{display:flex}" + ".gogo-head{background:#7c3aed;color:#fff;padding:12px 16px;font-weight:600;font-size:15px}" + ".gogo-head small{display:block;font-weight:400;opacity:.85;font-size:12px}" + ".gogo-msgs{flex:1;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px;background:#f7f7fa}" + ".gogo-msg{max-width:82%;padding:8px 12px;border-radius:12px;font-size:14px;line-height:1.45;" + "white-space:pre-wrap;word-wrap:break-word}" + ".gogo-msg.bot{background:#fff;border:1px solid #e5e5ec;align-self:flex-start;border-bottom-left-radius:4px}" + ".gogo-msg.user{background:#7c3aed;color:#fff;align-self:flex-end;border-bottom-right-radius:4px}" + ".gogo-msg.typing{color:#888;font-style:italic;background:#fff;border:1px dashed #ddd}" + ".gogo-form{display:flex;border-top:1px solid #e5e5ec;background:#fff}" + ".gogo-form input[type=text]{flex:1;border:0;padding:12px 14px;font-size:14px;outline:none}" + ".gogo-form button{border:0;background:none;color:#7c3aed;font-weight:700;padding:0 16px;cursor:pointer;font-size:14px}" + ".gogo-hp{position:absolute;left:-9999px;opacity:0;height:0;width:0}"; var style = document.createElement("style"); style.textContent = css; document.head.appendChild(style); /* ---------- DOM ---------- */ var bubble = document.createElement("button"); bubble.className = "gogo-bubble"; bubble.setAttribute("aria-label", "Otvori chat"); bubble.textContent = "💬"; var panel = document.createElement("div"); panel.className = "gogo-panel"; panel.innerHTML = '
Virtuelni asistentGogo Telefon — odgovaramo odmah
' + '
' + '
' + '' + '' + "
"; document.body.appendChild(bubble); document.body.appendChild(panel); var msgs = panel.querySelector(".gogo-msgs"); var form = panel.querySelector(".gogo-form"); var input = form.querySelector('input[type=text]:not(.gogo-hp)'); var honeypot = form.querySelector(".gogo-hp"); function addMsg(text, who) { var el = document.createElement("div"); el.className = "gogo-msg " + who; el.textContent = text; msgs.appendChild(el); msgs.scrollTop = msgs.scrollHeight; return el; } var typingEl = null; function showTyping() { if (typingEl) return; typingEl = addMsg("Gogo piše…", "bot typing"); } function hideTyping() { if (typingEl) { typingEl.remove(); typingEl = null; } } /* ---------- WebSocket ---------- */ var ws = null; var connected = false; function connect() { if (ws) return; var resume = ""; try { resume = localStorage.getItem(STORE) || ""; } catch (e) {} ws = new WebSocket( WS_BASE + "/widget/ws?key=" + encodeURIComponent(KEY) + (resume ? "&resume=" + encodeURIComponent(resume) : "") ); ws.onopen = function () { connected = true; }; ws.onmessage = function (ev) { var data; try { data = JSON.parse(ev.data); } catch (e) { return; } if (data.session) { try { localStorage.setItem(STORE, data.session); } catch (e) {} } if (data.type === "greeting") { addMsg(data.text, "bot"); } else if (data.type === "resume") { msgs.innerHTML = ""; (data.messages || []).forEach(function (m) { addMsg(m.text, m.role === "user" ? "user" : "bot"); }); } else if (data.type === "typing") { showTyping(); } else if (data.type === "message") { hideTyping(); addMsg(data.text, "bot"); } }; ws.onclose = function (ev) { connected = false; ws = null; hideTyping(); if (ev.code === 4429) { addMsg("Previše pokušaja — molimo pokušajte kasnije ili pozovite salon.", "bot"); } }; } bubble.addEventListener("click", function () { panel.classList.toggle("open"); if (panel.classList.contains("open")) { connect(); input.focus(); } }); form.addEventListener("submit", function (e) { e.preventDefault(); var text = input.value.trim(); if (!text || !ws || !connected) return; addMsg(text, "user"); ws.send(JSON.stringify({ type: "message", text: text, website: honeypot.value })); input.value = ""; }); })();