(function (){
'use strict';
if(!window.TECA_CHAT) return;
var cfg=window.TECA_CHAT;
var isOpen=false;
var isSending=false;
var STORAGE_KEY='teca_chat_history_v2';
var MAX_HISTORY=40;
function loadHistory(){
try {
var raw=window.localStorage.getItem(STORAGE_KEY);
if(!raw) return [];
var parsed=JSON.parse(raw);
if(!parsed||!Array.isArray(parsed.messages)) return [];
if((parsed.lang||'')!==(cfg.lang||'')) return [];
return parsed.messages;
} catch (e){
return [];
}}
var history=loadHistory();
function saveHistory(){
try {
if(history.length > MAX_HISTORY){
history=history.slice(history.length - MAX_HISTORY);
}
window.localStorage.setItem(STORAGE_KEY, JSON.stringify({ lang: cfg.lang||'', messages: history }));
} catch (e){
}}
var launcher=document.createElement('button');
launcher.id='tcb-launcher';
launcher.setAttribute('aria-label', 'Chat');
launcher.innerHTML =
'<svg class="tcb-chat-icon" viewBox="0 0 24 24" fill="#7dd3fc"><path d="M4 4h16a2 2 0 012 2v9a2 2 0 01-2 2H9l-5 4v-4H4a2 2 0 01-2-2V6a2 2 0 012-2z"/><circle cx="8" cy="10.5" r="1.15" fill="#0b3a55"/><circle cx="12" cy="10.5" r="1.15" fill="#0b3a55"/><circle cx="16" cy="10.5" r="1.15" fill="#0b3a55"/></svg>' +
'<svg class="tcb-close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M18 6L6 18M6 6l12 12"/></svg>';
var i18n=cfg.i18n||{};
var siteName=cfg.siteName||'Site';
var avatarText=cfg.avatarText||siteName.charAt(0)||'?';
var panel=document.createElement('div');
panel.id='tcb-panel';
panel.innerHTML =
'<div id="tcb-header">' +
'<div class="tcb-avatar"><span class="tcb-avatar-fallback">' + avatarText + '</span></div>' +
'<div class="tcb-htext">' +
'<div class="tcb-title">' + siteName + '</div>' +
'<div class="tcb-sub"><span class="tcb-dot"></span> ' + (i18n.headerSub||'Online assistant') + '</div>' +
'</div>' +
'<button id="tcb-reset" type="button" title="Clear conversation">🧹</button>' +
'</div>' +
'<div id="tcb-messages"></div>' +
'<div id="tcb-inputbar">' +
'<textarea id="tcb-input" rows="1" placeholder="' + (i18n.placeholder||'Type your question...') + '"></textarea>' +
'<button id="tcb-send" type="button" aria-label="Send">' +
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/></svg>' +
'</button>' +
'</div>';
var messagesEl, inputEl, sendBtn, resetBtn;
document.addEventListener('DOMContentLoaded', function (){
document.body.appendChild(launcher);
document.body.appendChild(panel);
messagesEl=document.getElementById('tcb-messages');
inputEl=document.getElementById('tcb-input');
sendBtn=document.getElementById('tcb-send');
resetBtn=document.getElementById('tcb-reset');
if(history.length > 0){
replayHistory();
}else{
appendBotMessage(cfg.welcome||'Hello 👋', true);
}
sendBtn.addEventListener('click', sendMessage);
resetBtn.addEventListener('click', startNewConversation);
inputEl.addEventListener('input', autoGrow);
inputEl.addEventListener('keydown', function (e){
if(e.key==='Enter'&&!e.shiftKey){
e.preventDefault();
sendMessage();
}});
});
function togglePanel(){
isOpen = !isOpen;
launcher.classList.toggle('tcb-open', isOpen);
panel.classList.toggle('tcb-open', isOpen);
if(isOpen&&inputEl){
setTimeout(function (){ inputEl.focus(); }, 150);
}}
launcher.addEventListener('click', togglePanel);
function scrollToBottom(){
messagesEl.scrollTop=messagesEl.scrollHeight;
}
function appendUserMessage(text, record){
var el=document.createElement('div');
el.className='tcb-msg tcb-msg-user';
el.textContent=text;
messagesEl.appendChild(el);
scrollToBottom();
if(record){
history.push({ type: 'user', text: text });
saveHistory();
}}
function appendBotMessage(text, record){
var el=document.createElement('div');
el.className='tcb-msg tcb-msg-bot';
el.textContent=text;
messagesEl.appendChild(el);
scrollToBottom();
if(record){
history.push({ type: 'bot', text: text });
saveHistory();
}}
function appendSources(sources, record){
if(!sources||!sources.length) return;
var wrap=document.createElement('div');
wrap.className='tcb-sources';
sources.forEach(function (s){
var a=document.createElement('a');
a.href=s.url;
a.target='_blank';
a.rel='noopener';
a.textContent='📄 ' + s.title;
wrap.appendChild(a);
});
messagesEl.appendChild(wrap);
scrollToBottom();
if(record){
history.push({ type: 'sources', sources: sources });
saveHistory();
}}
function appendFallback(record){
var phone=cfg.phone||'';
var wa=cfg.whatsapp||'';
var wrap=document.createElement('div');
wrap.className='tcb-fallback';
var p=document.createElement('p');
p.textContent=i18n.fallbackIntro||"Sorry, I couldn't find an answer to that on the site. Contact us directly:";
wrap.appendChild(p);
var actions=document.createElement('div');
actions.className='tcb-fallback-actions';
if(phone){
var call=document.createElement('a');
call.className='tcb-call';
call.href='tel:' + phone.replace(/[^0-9+]/g, '');
call.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.9v3a2 2 0 01-2.2 2 19.8 19.8 0 01-8.6-3.1 19.5 19.5 0 01-6-6 19.8 19.8 0 01-3.1-8.7A2 2 0 014.1 2h3a2 2 0 012 1.7c.1.9.3 1.8.6 2.7a2 2 0 01-.4 2.1L8 9.9a16 16 0 006 6l1.4-1.4a2 2 0 012.1-.4c.9.3 1.8.5 2.7.6a2 2 0 011.8 2.2z"/></svg>' + phone;
actions.appendChild(call);
}
if(wa){
var whatsapp=document.createElement('a');
whatsapp.className='tcb-wa';
whatsapp.href='https://wa.me/' + wa;
whatsapp.target='_blank';
whatsapp.rel='noopener';
whatsapp.innerHTML='<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2a10 10 0 00-8.5 15.3L2 22l4.8-1.4A10 10 0 1012 2zm5.6 14.3c-.2.6-1.3 1.2-1.8 1.2-.5.1-1.1.1-1.7-.1-.4-.1-.9-.3-1.6-.6-2.7-1.2-4.5-3.9-4.6-4.1-.1-.2-1.1-1.4-1.1-2.7 0-1.3.7-1.9.9-2.1.2-.2.5-.3.7-.3h.5c.2 0 .4 0 .6.4.2.5.7 1.7.8 1.9.1.2.1.3 0 .5-.1.2-.1.3-.3.5-.1.2-.3.3-.4.5-.2.2-.3.3-.1.6.2.3.8 1.3 1.7 2.1 1.2 1 2.1 1.4 2.4 1.5.3.1.4.1.6-.1.2-.2.7-.8.9-1.1.2-.3.4-.2.6-.1.2.1 1.5.7 1.7.8.2.1.4.2.4.3.1.2.1.7-.1 1.3z"/></svg>WhatsApp';
actions.appendChild(whatsapp);
}
wrap.appendChild(actions);
messagesEl.appendChild(wrap);
scrollToBottom();
if(record){
history.push({ type: 'fallback' });
saveHistory();
}}
function showTyping(){
var el=document.createElement('div');
el.className='tcb-typing';
el.id='tcb-typing-indicator';
el.innerHTML='<span></span><span></span><span></span>';
messagesEl.appendChild(el);
scrollToBottom();
}
function hideTyping(){
var el=document.getElementById('tcb-typing-indicator');
if(el) el.remove();
}
function replayHistory(){
history.forEach(function (entry){
if(entry.type==='user'){
appendUserMessage(entry.text, false);
}else if(entry.type==='bot'){
appendBotMessage(entry.text, false);
}else if(entry.type==='sources'){
appendSources(entry.sources, false);
}else if(entry.type==='fallback'){
appendFallback(false);
}});
}
function startNewConversation(){
history=[];
try { window.localStorage.removeItem(STORAGE_KEY); } catch (e){}
messagesEl.innerHTML='';
appendBotMessage(cfg.welcome||'Hello 👋', true);
}
function sendMessage(){
var text=inputEl.value.trim();
if(text===''||isSending) return;
appendUserMessage(text, true);
inputEl.value='';
autoGrow();
isSending=true;
sendBtn.disabled=true;
showTyping();
fetch(cfg.restUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text, lang: cfg.lang||'' })
})
.then(function (r){ return r.json(); })
.then(function (data){
hideTyping();
if(!data||data.type==='no_answer'){
appendFallback(true);
}else if(data.type==='error'){
appendBotMessage(data.text||(i18n.genericError||'Something went wrong, please try again.'), true);
}else{
appendBotMessage(data.text||'', true);
appendSources(data.sources, true);
}})
.catch(function (){
hideTyping();
appendBotMessage(i18n.connError||'Connection issue. Please try again or call us.', true);
appendFallback(true);
})
.finally(function (){
isSending=false;
sendBtn.disabled=false;
});
}
function autoGrow(){
inputEl.style.height='auto';
inputEl.style.height=Math.min(inputEl.scrollHeight, 80) + 'px';
}})();