@skykeys/webchatapp
Version:
Widget de chat embeddable pour WebChatApp avec persistance des conversations
2 lines (1 loc) • 26.7 kB
JavaScript
!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e=Object.defineProperty,n=Object.getOwnPropertySymbols,t=Object.prototype.hasOwnProperty,i=Object.prototype.propertyIsEnumerable,s=(n,t,i)=>t in n?e(n,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):n[t]=i,o=(e,n,t)=>new Promise(((i,s)=>{var o=e=>{try{r(t.next(e))}catch(n){s(n)}},a=e=>{try{r(t.throw(e))}catch(n){s(n)}},r=e=>e.done?i(e.value):Promise.resolve(e.value).then(o,a);r((t=t.apply(e,n)).next())}));try{let e=function(){try{window.chatWidget=new a(window.webchatConfig)}catch(e){}};if(!window.webchatConfig)throw new Error("Configuration manquante");class a{constructor(e){this.config=((e,o)=>{for(var a in o||(o={}))t.call(o,a)&&s(e,a,o[a]);if(n)for(var a of n(o))i.call(o,a)&&s(e,a,o[a]);return e})({apiUrl:e.apiUrl||"http://localhost:8080",siteId:e.siteId,agentName:e.agentName||"Support",welcomeMessage:e.welcomeMessage||"Besoin d'aide ?",primaryColor:e.primaryColor||"#2196f3"},e),this.isOpen=!1,this.socket=null,this.conversationId=null,this.visitorToken=null,this.messages=[],this.selectedFile=null,this.typingTimeout=null,this.connected=!1,this.agentsOnline=!1,this.storageKey=`webchat_conversation_${this.config.siteId}`,this.init()}init(){return o(this,null,(function*(){try{yield this.authenticate(),this.loadExistingConversation(),this.createUI(),yield this.connectWebSocket(),this.conversationId&&this.joinExistingConversation(),this.initNavigationTracking()}catch(e){}}))}authenticate(){return o(this,null,(function*(){try{const e=yield fetch(`${this.config.apiUrl}/webchat/auth/${this.config.siteId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userAgent:navigator.userAgent,referrer:document.referrer,url:window.location.href})});if(!e.ok)throw new Error(`Auth failed: ${e.status}`);const n=yield e.json();this.visitorToken=n.token}catch(e){throw e}}))}connectWebSocket(){return o(this,null,(function*(){return new Promise(((e,n)=>{if(window.io)return this.initSocket(),void e();const t=document.createElement("script");t.src="https://cdn.jsdelivr.net/npm/socket.io-client@4/dist/socket.io.min.js",t.onload=()=>{this.initSocket(),e()},t.onerror=()=>n(new Error("Socket.IO load failed")),document.head.appendChild(t)}))}))}initSocket(){this.socket=io(this.config.apiUrl,{auth:{token:this.visitorToken},transports:["websocket","polling"]}),this.agentsOnline=!1,this.socket.on("connect",(()=>{this.updateConnectionStatus(!0),this.socket.emit("getOnlineUsers"),this.conversationId&&this.joinExistingConversation()})),this.socket.on("disconnect",(()=>{this.updateConnectionStatus(!1),this.agentsOnline=!1,this.updateStatus()})),this.socket.on("newMessage",(e=>{this.hideTypingIndicator(),"agent"===e.sender&&e.senderName&&this.updateAgentName(e.senderName),this.displayMessage({id:e.id,content:e.message,sender:"visitor"===e.sender?"user":"agent",timestamp:new Date(e.timestamp),senderName:e.senderName,file:e.file||null})})),this.socket.on("messageSent",(e=>{})),this.socket.on("typing",(e=>{e.agentName&&this.updateAgentName(e.agentName),this.showTypingIndicator(),this.typingTimeout&&clearTimeout(this.typingTimeout),this.typingTimeout=setTimeout((()=>{this.hideTypingIndicator(),this.typingTimeout=null}),3e3)})),this.socket.on("conversationClosed",(e=>{this.handleConversationClosed(e)})),this.socket.on("error",(e=>{})),this.socket.on("userOnline",(e=>{this.agentsOnline=!0,this.updateStatus()})),this.socket.on("userOffline",(e=>{this.socket.emit("getOnlineUsers")})),this.socket.on("onlineUsers",(e=>{const n=e.filter((e=>"AGENT"===e.role||"ADMIN"===e.role));this.agentsOnline=n.length>0,this.updateStatus()})),this.socket.on("onlineUsersUpdate",(e=>{const n=e.filter((e=>"AGENT"===e.role||"ADMIN"===e.role));this.agentsOnline;this.agentsOnline=n.length>0,this.updateStatus()}))}createUI(){if(!document.querySelector('link[href*="fontawesome"]')){const e=document.createElement("link");e.rel="stylesheet",e.href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css",document.head.appendChild(e)}const e=document.createElement("div");e.id="chat-widget",e.innerHTML=`\n <style>\n #chat-widget {\n position: fixed;\n bottom: 20px;\n right: 20px;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n \n .chat-button {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: ${this.config.primaryColor};\n color: white;\n border: none;\n font-size: 24px;\n cursor: pointer;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n transition: all 0.3s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n .chat-button:hover {\n transform: scale(1.1);\n }\n \n .chat-window {\n position: absolute;\n bottom: 80px;\n right: 0;\n width: 350px;\n height: 500px;\n background: white;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\n display: none;\n flex-direction: column;\n overflow: hidden;\n }\n \n .chat-window.open {\n display: flex;\n }\n \n .chat-header {\n background: ${this.config.primaryColor};\n color: white;\n padding: 16px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n \n .chat-messages {\n flex: 1;\n padding: 16px;\n overflow-y: auto;\n background: #f8f9fa;\n }\n \n .message {\n margin-bottom: 12px;\n display: flex;\n gap: 8px;\n }\n \n .message.user {\n flex-direction: row-reverse;\n }\n \n .message-content {\n max-width: 70%;\n padding: 8px 12px;\n border-radius: 12px;\n font-size: 14px;\n line-height: 1.4;\n }\n \n .message.agent .message-content {\n background: white;\n border: 1px solid #e9ecef;\n }\n \n .message.user .message-content {\n background: ${this.config.primaryColor};\n color: white;\n }\n \n .message.system .message-content {\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n font-style: italic;\n text-align: center;\n margin: 0 auto;\n }\n \n .message.file .message-content {\n cursor: pointer;\n transition: background-color 0.2s;\n }\n \n .message.file.agent .message-content:hover {\n background-color: #f8f9fa;\n }\n \n .message.file.user .message-content:hover {\n background-color: rgba(255,255,255,0.1);\n }\n \n .file-attachment {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px;\n }\n \n .file-icon {\n width: 32px;\n height: 32px;\n background: #e9ecef;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n color: #6c757d;\n }\n \n .file-info {\n flex: 1;\n min-width: 0;\n }\n \n .file-name {\n font-weight: 500;\n font-size: 13px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n \n .file-size {\n font-size: 11px;\n opacity: 0.7;\n }\n \n .file-preview {\n max-width: 200px;\n max-height: 150px;\n border-radius: 8px;\n cursor: pointer;\n }\n \n .chat-input {\n padding: 16px;\n border-top: 1px solid #e9ecef;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n \n .file-preview-container {\n display: none;\n background: #f8f9fa;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n padding: 8px;\n margin-bottom: 8px;\n }\n \n .file-preview-item {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n \n .file-preview-remove {\n background: #dc3545;\n color: white;\n border: none;\n border-radius: 50%;\n width: 20px;\n height: 20px;\n cursor: pointer;\n font-size: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n .input-row {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n \n .chat-input input[type="text"] {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid #e9ecef;\n border-radius: 20px;\n outline: none;\n font-size: 14px;\n }\n \n .chat-input input[type="file"] {\n display: none;\n }\n \n .file-upload-btn {\n padding: 8px;\n background: #f8f9fa;\n color: #6c757d;\n border: 1px solid #e9ecef;\n border-radius: 50%;\n cursor: pointer;\n font-size: 16px;\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background-color 0.2s;\n }\n \n .file-upload-btn:hover {\n background: #e9ecef;\n }\n \n .file-upload-btn.uploading {\n background: ${this.config.primaryColor};\n color: white;\n cursor: not-allowed;\n }\n \n .chat-input button[type="submit"] {\n padding: 8px 16px;\n background: ${this.config.primaryColor};\n color: white;\n border: none;\n border-radius: 20px;\n cursor: pointer;\n font-size: 14px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n \n .chat-input button:disabled {\n background: #6c757d;\n cursor: not-allowed;\n }\n \n .status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #28a745;\n margin-right: 8px;\n }\n \n .status-dot.offline {\n background: #dc3545;\n }\n \n @keyframes typing-bounce {\n 0%, 60%, 100% {\n transform: translateY(0);\n }\n 30% {\n transform: translateY(-10px);\n }\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n \n .uploading .file-upload-btn i {\n animation: spin 1s linear infinite;\n }\n \n .file-upload-btn.uploading i:before {\n content: "\f013";\n }\n </style>\n \n <div class="chat-window" id="chat-window">\n <div class="chat-header">\n <div style="display: flex; align-items: center;">\n <div class="status-dot" id="status-dot"></div>\n <div>\n <div style="font-weight: 600;" id="agent-name-header">${this.config.agentName}</div>\n <div style="font-size: 12px; opacity: 0.9;" id="status-text">En ligne</div>\n </div>\n </div>\n <button onclick="window.chatWidget.closeChat()" style="background: none; border: none; color: white; font-size: 20px; cursor: pointer;">\n <i class="fas fa-times"></i>\n </button>\n </div>\n \n <div class="chat-messages" id="chat-messages">\n <div class="message agent">\n <div class="message-content">\n <i class="fas fa-hand-wave" style="margin-right: 8px;"></i>${this.config.welcomeMessage}\n </div>\n </div>\n </div>\n \n <div class="chat-input">\n <div class="file-preview-container" id="file-preview"></div>\n <div class="input-row">\n <input type="file" id="file-input" accept="image/*,application/pdf,.doc,.docx,.txt,.mp3,.wav,.mp4" />\n <button type="button" class="file-upload-btn" id="file-upload-btn" onclick="window.chatWidget.selectFile()">\n <i class="fas fa-paperclip"></i>\n </button>\n <input type="text" id="message-input" placeholder="Tapez votre message..." />\n <button type="submit" id="send-btn" onclick="window.chatWidget.sendMessage()">\n <i class="fas fa-paper-plane"></i>\n <span>Envoyer</span>\n </button>\n </div>\n </div>\n </div>\n \n <button class="chat-button" onclick="window.chatWidget.toggleChat()">\n <i class="fas fa-comments"></i>\n </button>\n `,document.body.appendChild(e);const n=document.getElementById("message-input"),t=document.getElementById("file-input");n.addEventListener("keypress",(e=>{"Enter"===e.key&&this.sendMessage()})),t.addEventListener("change",(e=>{this.handleFileSelect(e)}));let i=null;n.addEventListener("input",(e=>{e.target.value.trim()&&(this.sendTypingEvent(),i&&clearTimeout(i),i=setTimeout((()=>{}),3e3))}))}toggleChat(){this.isOpen=!this.isOpen;document.getElementById("chat-window").classList.toggle("open",this.isOpen),this.isOpen&&document.getElementById("message-input").focus()}closeChat(){this.isOpen=!1,document.getElementById("chat-window").classList.remove("open")}sendMessage(){return o(this,null,(function*(){const e=document.getElementById("message-input"),n=e.value.trim(),t=this.selectedFile;if(n||t){e.value="";try{this.conversationId||(yield this.createConversation()),t?(yield this.sendMessageWithFile(n,t),this.clearSelectedFile()):(this.displayMessage({id:"temp-"+Date.now(),content:n,sender:"user",timestamp:new Date}),this.socket&&this.socket.connected&&this.socket.emit("sendMessage",{conversationId:this.conversationId,message:n}))}catch(i){}}}))}selectFile(){document.getElementById("file-input").click()}handleFileSelect(e){const n=e.target.files[0];n&&this.validateFile(n)&&(this.selectedFile=n,this.showFilePreview(n),e.target.value="")}validateFile(e){return["image/jpeg","image/png","image/gif","image/webp","application/pdf","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/plain","audio/mpeg","audio/wav","video/mp4"].includes(e.type)?!(e.size>10485760)||(alert("Le fichier est trop volumineux. Taille maximum: 10MB."),!1):(alert("Type de fichier non supporté. Types autorisés: images, PDF, documents Word, texte, audio MP3/WAV, vidéo MP4."),!1)}showFilePreview(e){const n=document.getElementById("file-preview"),t=this.getFileIcon(e.type),i=this.formatFileSize(e.size);n.innerHTML=`\n <div class="file-preview-item">\n <div class="file-icon">${t}</div>\n <div class="file-info">\n <div class="file-name">${e.name}</div>\n <div class="file-size">${i}</div>\n </div>\n <button class="file-preview-remove" onclick="window.chatWidget.clearSelectedFile()">\n <i class="fas fa-times"></i>\n </button>\n </div>\n `,n.style.display="block"}clearSelectedFile(){this.selectedFile=null;const e=document.getElementById("file-preview");e.style.display="none",e.innerHTML=""}sendMessageWithFile(e,n){return o(this,null,(function*(){try{this.setUploading(!0),this.displayMessage({id:"temp-"+Date.now(),content:e||"",sender:"user",timestamp:new Date,file:{name:n.name,size:n.size,type:n.type}});const t=new FormData;t.append("file",n),e&&t.append("content",e);const i=yield fetch(`${this.config.apiUrl}/webchat/conversation/${this.conversationId}/message-with-file`,{method:"POST",headers:{Authorization:`Bearer ${this.visitorToken}`},body:t});if(!i.ok)throw new Error(`Upload failed: ${i.status}`)}catch(t){alert("Erreur lors de l'envoi du fichier. Veuillez réessayer.")}finally{this.setUploading(!1)}}))}setUploading(e){const n=document.getElementById("file-upload-btn"),t=document.getElementById("send-btn"),i=document.getElementById("message-input"),s=n.querySelector("i");e?(n.classList.add("uploading"),n.disabled=!0,t.disabled=!0,i.disabled=!0,s&&(s.className="fas fa-spinner")):(n.classList.remove("uploading"),n.disabled=!1,t.disabled=!1,i.disabled=!1,s&&(s.className="fas fa-paperclip"))}getFileIcon(e){return e?e.startsWith("image/")?'<i class="fas fa-image"></i>':"application/pdf"===e?'<i class="fas fa-file-pdf"></i>':e.includes("word")?'<i class="fas fa-file-word"></i>':e.startsWith("audio/")?'<i class="fas fa-file-audio"></i>':e.startsWith("video/")?'<i class="fas fa-file-video"></i>':e.includes("text")||"text/plain"===e?'<i class="fas fa-file-alt"></i>':e.includes("excel")||e.includes("spreadsheet")?'<i class="fas fa-file-excel"></i>':e.includes("powerpoint")||e.includes("presentation")?'<i class="fas fa-file-powerpoint"></i>':e.includes("zip")||e.includes("rar")||e.includes("7z")?'<i class="fas fa-file-archive"></i>':'<i class="fas fa-file"></i>':'<i class="fas fa-paperclip"></i>'}formatFileSize(e){if(0===e)return"0 B";const n=Math.floor(Math.log(e)/Math.log(1024));return parseFloat((e/Math.pow(1024,n)).toFixed(2))+" "+["B","KB","MB","GB"][n]}createConversation(){return o(this,null,(function*(){try{const e=yield fetch(`${this.config.apiUrl}/webchat/conversation/${this.config.siteId}`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.visitorToken}`},body:JSON.stringify({visitorName:"Visiteur",initialMessage:null})});if(!e.ok)throw new Error(`Conversation failed: ${e.status}`);const n=yield e.json();this.conversationId=n.conversationId,this.saveConversationId(this.conversationId);localStorage.getItem(this.storageKey);this.socket&&this.socket.connected&&this.socket.emit("joinConversation",this.conversationId)}catch(e){throw e}}))}displayMessage(e){const n=document.getElementById("chat-messages"),t=document.createElement("div");t.className=`message ${e.sender}`;let i="";if("agent"===e.sender){i=`\n <div style="font-size: 11px; color: #666; margin-bottom: 4px; padding-left: 4px;">\n ${e.senderName||this.config.agentName}\n </div>\n `}else"user"===e.sender&&(i='\n <div style="font-size: 11px; color: #666; margin-bottom: 4px; padding-right: 4px; text-align: right;">\n Vous\n </div>\n ');let s="";if(e.file){const n=e.file.type||e.file.mimeType||"",i=e.file.name||e.file.filename||"Fichier",o=e.file.size||0,a=e.file.url||"#",r=this.getFileIcon(n),l=this.formatFileSize(o);s=n.startsWith("image/")?`\n ${e.content?`<div style="margin-bottom: 8px;">${e.content}</div>`:""}\n <div class="file-attachment">\n <img src="${a}" alt="${i}" class="file-preview" \n onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';" />\n <div class="file-attachment" style="display: none;">\n <div class="file-icon">${r}</div>\n <div class="file-info">\n <div class="file-name">${i}</div>\n <div class="file-size">${l}</div>\n </div>\n </div>\n </div>\n `:`\n ${e.content?`<div style="margin-bottom: 8px;">${e.content}</div>`:""}\n <div class="file-attachment">\n <div class="file-icon">${r}</div>\n <div class="file-info">\n <div class="file-name">${i}</div>\n <div class="file-size">${l}</div>\n </div>\n </div>\n `,t.classList.add("file")}else s=e.content;t.innerHTML=`\n ${i}\n <div class="message-content">\n ${s}\n </div>\n `,n.appendChild(t),n.scrollTop=n.scrollHeight,this.messages.push(e)}updateConnectionStatus(e){this.connected=e,this.updateStatus()}updateStatus(){const e=document.getElementById("status-dot"),n=document.getElementById("status-text");if(!e||!n)return;const t=this.connected&&this.agentsOnline;e.className="status-dot "+(t?"":"offline"),this.connected?this.agentsOnline?n.textContent="En ligne":n.textContent="Aucun agent disponible":n.textContent="Hors ligne"}showTypingIndicator(){this.hideTypingIndicator();const e=document.getElementById("chat-messages"),n=document.createElement("div");n.id="typing-indicator",n.className="message agent",n.innerHTML=`\n <div style="font-size: 11px; color: #666; margin-bottom: 4px; padding-left: 4px;">\n ${this.config.agentName}\n </div>\n <div class="message-content" style="display: flex; align-items: center; gap: 8px;">\n <div style="display: flex; gap: 4px;">\n <div style="width: 8px; height: 8px; background: #666; border-radius: 50%; animation: typing-bounce 1.4s infinite ease-in-out;"></div>\n <div style="width: 8px; height: 8px; background: #666; border-radius: 50%; animation: typing-bounce 1.4s infinite ease-in-out; animation-delay: 0.2s;"></div>\n <div style="width: 8px; height: 8px; background: #666; border-radius: 50%; animation: typing-bounce 1.4s infinite ease-in-out; animation-delay: 0.4s;"></div>\n </div>\n <span style="font-size: 12px; color: #666;">est en train d'écrire...</span>\n </div>\n `,e.appendChild(n),e.scrollTop=e.scrollHeight}hideTypingIndicator(){const e=document.getElementById("typing-indicator");e&&e.remove(),this.typingTimeout&&(clearTimeout(this.typingTimeout),this.typingTimeout=null)}sendTypingEvent(){this.socket&&this.socket.connected&&this.conversationId&&this.socket.emit("typing",{conversationId:this.conversationId})}handleConversationClosed(e){this.displayMessage({id:"system-"+Date.now(),content:e.message||"Cette conversation a été fermée.",sender:"system",timestamp:new Date(e.timestamp)}),this.conversationId=null,this.clearConversationId();const n=document.getElementById("message-input"),t=document.querySelector(".chat-input button");n&&(n.disabled=!0,n.placeholder="Conversation fermée - Rechargez pour redémarrer"),t&&(t.disabled=!0,t.textContent="Fermé"),setTimeout((()=>{n&&(n.disabled=!1,n.placeholder="Tapez votre message..."),t&&(t.disabled=!1,t.textContent="Envoyer"),this.displayMessage({id:"system-restart-"+Date.now(),content:"Vous pouvez maintenant démarrer une nouvelle conversation.",sender:"system",timestamp:new Date})}),5e3)}updateAgentName(e){this.config.agentName=e;const n=document.getElementById("agent-name-header");n&&(n.textContent=e)}saveConversationId(e){try{localStorage.setItem(this.storageKey,e);localStorage.getItem(this.storageKey)}catch(n){}}loadExistingConversation(){try{const e=localStorage.getItem(this.storageKey);e&&(this.conversationId=e)}catch(e){}}clearConversationId(){try{localStorage.removeItem(this.storageKey)}catch(e){}}joinExistingConversation(){this.socket&&this.socket.connected&&this.conversationId&&(this.socket.emit("joinConversation",this.conversationId),this.loadConversationHistory())}loadConversationHistory(){return o(this,null,(function*(){if(this.conversationId&&this.visitorToken)try{const e=yield fetch(`${this.config.apiUrl}/webchat/conversation/${this.conversationId}/messages`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.visitorToken}`}});if(!e.ok){if(404===e.status)return this.clearConversationId(),void(this.conversationId=null);throw new Error(`Failed to load history: ${e.status}`)}const n=yield e.json();this.messages=[];const t=document.getElementById("chat-messages");t&&(t.innerHTML=""),n.messages.forEach((e=>{this.displayMessage({id:e.id,content:e.content,sender:"visitor"===e.sender?"user":"agent",timestamp:new Date(e.timestamp),senderName:e.senderName,file:e.file||null})}))}catch(e){this.clearConversationId(),this.conversationId=null}}))}initNavigationTracking(){this.currentUrl=window.location.href,window.addEventListener("popstate",(()=>{this.onNavigationChange()}));const e=history.pushState,n=history.replaceState;history.pushState=(...n)=>{e.apply(history,n),setTimeout((()=>{this.onNavigationChange()}),0)},history.replaceState=(...e)=>{n.apply(history,e),setTimeout((()=>{this.onNavigationChange()}),0)},document.addEventListener("click",(e=>{const n=e.target.closest("a");if(n&&n.href&&"#"!==n.href)try{const e=new URL(n.href),t=new URL(window.location.href);e.origin===t.origin&&setTimeout((()=>{this.onNavigationChange()}),100)}catch(t){}})),setInterval((()=>{window.location.href!==this.currentUrl&&this.onNavigationChange()}),2e3)}onNavigationChange(){const e=window.location.href;if(e!==this.currentUrl){const n=this.currentUrl;this.currentUrl=e,this.socket&&this.socket.connected&&this.conversationId&&this.socket.emit("updateVisitorLocation",{conversationId:this.conversationId,url:e,previousUrl:n,timestamp:(new Date).toISOString()}),this.updateVisitorToken(e)}}updateVisitorToken(e){return o(this,null,(function*(){try{const n=yield fetch(`${this.config.apiUrl}/webchat/update-location/${this.config.siteId}`,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.visitorToken}`},body:JSON.stringify({url:e,userAgent:navigator.userAgent,referrer:document.referrer})});if(n.ok){const e=yield n.json();e.token&&(this.visitorToken=e.token)}}catch(n){}}))}}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}catch(a){}}));