UNPKG

@ticketping/chat-widget

Version:

Customer support chat widget for Ticketping - Intercom-like experience with real-time messaging

9 lines 76.3 kB
var TicketpingChat=function(){"use strict";var e=Object.defineProperty,t=Object.defineProperties,s=Object.getOwnPropertyDescriptors,i=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,a=(t,s,i)=>s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i,r=(e,t)=>{for(var s in t||(t={}))n.call(t,s)&&a(e,s,t[s]);if(i)for(var s of i(t))o.call(t,s)&&a(e,s,t[s]);return e},c=(e,i)=>t(e,s(i)),l=(e,t,s)=>new Promise((i,n)=>{var o=e=>{try{r(s.next(e))}catch(t){n(t)}},a=e=>{try{r(s.throw(e))}catch(t){n(t)}},r=e=>e.done?i(e.value):Promise.resolve(e.value).then(o,a);r((s=s.apply(e,t)).next())});
/*!
 * Ticketping Chat Widget v1.0.0
 * (c) 2024 Ticketping
 * Licensed under MIT
 */
function h(e,t={}){const s=document.createElement(e);return t?(Object.entries(t).forEach(([e,t])=>{if(null!=t)if("className"===e)s.className=t;else if("textContent"===e)s.textContent=t;else if("innerHTML"===e)s.innerHTML=t;else if(e.startsWith("on")&&"function"==typeof t){const i=e.slice(2).toLowerCase();s.addEventListener(i,t)}else"boolean"==typeof t?t?(s.setAttribute(e,e),s[e]=!0):s[e]=!1:s.setAttribute(e,t)}),s):s}const d={appId:null,teamSlug:null,teamLogoIcon:null,apiBase:"https://api.ticketping.com",wsBase:"wss://ws.ticketping.com",userJWT:null,enableSecureMode:!0,position:"bottom-right",theme:"default",zIndex:999999,autoOpen:!1,enableTypingIndicators:!0,enableFileUpload:!0,enableEmojis:!0,maxFileSize:10485760,allowedFileTypes:["image/jpeg","image/png","image/gif","application/pdf","application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/plain"],maxMessageLength:5e3,enableMarkdown:!1,enableLinkPreviews:!0,showConversationHistory:!0,maxConversationsStored:50,autoDeleteAfterDays:30,enableSoundNotifications:!0,enableBrowserNotifications:!1,analytics:!0,trackUserInteractions:!0,locale:"en",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,debug:!1,logLevel:"error",labels:{headerTitle:"Ticketping",headerSubtitle:"We're here to help!",homeTab:"Home",messagesTab:"Messages",welcomeTitle:"👋 Welcome!",welcomeMessage:"Hi there! How can we help you today?",startConversationButton:"Send us a message",messageInputPlaceholder:"Type your message...",sendButton:"Send",attachButton:"Attach file",typingIndicator:"Support is typing...",agentOnline:"We're online and ready to help!",agentOffline:"We'll get back to you soon!",connectionLost:"Connection lost. Trying to reconnect...",fileTooLarge:"File size exceeds maximum limit",fileTypeNotAllowed:"File type not supported",messageTooLong:"Message is too long",sendError:"Failed to send message. Please try again.",loadError:"Failed to load conversation",noConversations:"No conversations yet",noConversationsDescription:"Start a conversation to get help from our support team.",helpArticlesTitle:"Popular articles",helpArticles:[{title:"Getting started guide",url:"/help/getting-started",icon:"article"},{title:"How to create tickets",url:"/help/create-tickets",icon:"check"},{title:"Best practices",url:"/help/best-practices",icon:"star"}]},customCSS:null,onReady:null,onOpen:null,onClose:null,onMessageSent:null,onMessageReceived:null,onConversationStarted:null,onError:null},u="/api/v1/jwt/auth/",g="/api/v1/chat-session/create/",p="/api/v1/chat-sessions/",m="/messages",v="/api/v1/chat-session/file-upload/",S="/api/v1/team/widget/",y={AUTH:"auth",TYPING_START:"typing_start",TYPING_STOP:"typing_stop",JOIN_CONVERSATION:"join_conversation",LEAVE_CONVERSATION:"leave_conversation",FILE_ATTACHMENT:"file_attachment",MARK_READ:"mark_read",SERVER_STATE:"server_session_state",SERVER_MESSAGE_HISTORY:"server_message_history",SERVER_MESSAGE:"server_message",SERVER_AGENT_STATUS:"server_agent_status",SERVER_AGENT_JOINED:"server_agent_joined",SERVER_AGENT_LEFT:"server_agent_left",SERVER_CONVERSATION_UPDATED:"server_conversation_updated",SERVER_AUTH_SUCCESS:"server_auth_success",SERVER_AUTH_FAILED:"server_auth_failed",SERVER_ANONYMOUS_AUTH_SUCCESS:"server_anonymous_auth_success",SERVER_ANONYMOUS_AUTH_FAILED:"server_anonymous_auth_failed",PONG:"pong",ERROR:"error"},w={CONVERSATIONS:"ticketping_conversations",USER_DATA:"ticketping_user",SETTINGS:"ticketping_settings",DEVICE_ID:"ticketping_device_id",UNREAD_CONVERSATIONS:"ticketping_unread_conversations"},f="ticketping-chat-bubble",C="ticketping-chat-window",b="open";class k{constructor(e,t={}){if(!e)return console.error("ChatBubble: Container is required"),this.container=null,this.element=null,this.notificationBadge=null,this.isOpen=!1,void(this.options=r({onClick:()=>{},showNotificationBadge:!1,notificationCount:0},t));this.container=e,this.options=r({onClick:()=>{},showNotificationBadge:!1,notificationCount:0},t),this.element=null,this.notificationBadge=null,this.isOpen=!1,this.render(),this.attachEventListeners()}render(){if(!this.container)return;this.element=h("button",{className:`${f}`,"aria-label":"Open chat","aria-expanded":"false",role:"button",tabindex:"0"});const e=this.createChatIcon();this.element.appendChild(e),this.options.showNotificationBadge&&this.createNotificationBadge(),this.container.appendChild(this.element)}createChatIcon(){const e=document.createElementNS("http://www.w3.org/2000/svg","svg");e.setAttribute("viewBox","0 0 18 18"),e.setAttribute("width","32"),e.setAttribute("height","32");const t=document.createElementNS("http://www.w3.org/2000/svg","path");return t.setAttribute("d","M14.25,2.25H3.75c-1.105,0-2,.896-2,2v7c0,1.104,.895,2,2,2h2v3l3.75-3h4.75c1.105,0,2-.896,2-2V4.25c0-1.104-.895-2-2-2Z"),t.setAttribute("fill","none"),t.setAttribute("stroke",this.options.iconColor||"#ffffff"),t.setAttribute("stroke-linecap","round"),t.setAttribute("stroke-linejoin","round"),t.setAttribute("stroke-width","1.5"),e.appendChild(t),e}createCloseIcon(){const e=document.createElementNS("http://www.w3.org/2000/svg","svg");e.setAttribute("viewBox","0 0 24 24"),e.setAttribute("width","24"),e.setAttribute("height","24");const t=document.createElementNS("http://www.w3.org/2000/svg","path");return t.setAttribute("d","M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"),e.appendChild(t),e}createNotificationBadge(){this.notificationBadge=h("div",{className:"notification-badge"}),this.element.appendChild(this.notificationBadge)}attachEventListeners(){this.element.addEventListener("click",()=>{this.handleClick()}),this.element.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.handleClick())})}handleClick(){this.options.onClick(),this.notificationBadge&&this.hideNotificationBadge()}setOpen(e){if(this.isOpen=e,this.element)if(e){this.element.classList.add(b),this.element.setAttribute("aria-expanded","true"),this.element.setAttribute("aria-label","Close chat");const e=this.element.querySelector("svg");e&&(this.element.removeChild(e),this.element.appendChild(this.createCloseIcon()))}else{this.element.classList.remove(b),this.element.setAttribute("aria-expanded","false"),this.element.setAttribute("aria-label","Open chat");const e=this.element.querySelector("svg");e&&(this.element.removeChild(e),this.element.appendChild(this.createChatIcon()))}}showNotificationBadge(e=1){this.element&&(this.notificationBadge||this.createNotificationBadge(),this.options.notificationCount=e,this.notificationBadge.style.display=e>0?"flex":"none")}hideNotificationBadge(){this.notificationBadge&&(this.notificationBadge.style.display="none",this.options.notificationCount=0)}updateNotificationCount(e){this.options.notificationCount=e,e>0?this.showNotificationBadge(e):this.hideNotificationBadge()}setTheme(e){this.element&&this.element.setAttribute("data-theme",e)}setPosition(e){this.element&&this.element.setAttribute("data-position",e)}bounce(){this.element&&(this.element.style.animation="tp-bounce 0.6s ease-in-out",setTimeout(()=>{this.element.style.animation=""},600))}hide(){this.element&&(this.element.style.display="none")}show(){this.element&&(this.element.style.display="")}setAriaLabel(e){this.element.setAttribute("aria-label",e)}focus(){this.element&&this.element.focus()}blur(){this.element&&this.element.blur()}disable(){this.element&&(this.element.disabled=!0,this.element.setAttribute("aria-disabled","true"))}enable(){this.element&&(this.element.disabled=!1,this.element.setAttribute("aria-disabled","false"))}destroy(){this.element&&this.element.parentNode&&this.element.parentNode.removeChild(this.element)}showNotification(e=1){return this.showNotificationBadge(e)}hideNotification(){return this.hideNotificationBadge()}}class T{constructor(e,t={}){this.container=e,this.options=r({onClose:()=>{},onTabSwitch:()=>{},onSendMessage:()=>{},onFileUpload:()=>{},onConversationSelect:()=>{},onBackButtonClick:()=>{},teamLogoIcon:null,teamSettings:null},t),this.element=null,this.activeTab="home",this.conversations=[],this.unreadConversations=new Set,this.currentMessages=[],this.isUploading=!1,this.render(),this.attachEventListeners()}render(){this.element=h("div",{className:C}),this.element.innerHTML=`\n      <div class="ticketping-chat-content">\n        <div class="ticketping-tab-content active" id="homeTab">\n          <div class="ticketping-chat-header">\n            <div class="ticketping-workspace-logo">\n              ${this.getLogoHtml()}\n            </div>\n            <button class="ticketping-close-btn" aria-label="Close chat">\n              <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">\n                <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>\n              </svg>\n            </button>\n          </div>\n          <div class="ticketping-home-container">\n            <div class="ticketping-home-content">\n              <h4>${this.getWelcomeTitle()}</h4>\n              <p>${this.getWelcomeMessage()}</p>\n            </div>\n            <div class="ticketping-actions-container">\n              <div class="ticketping-recent-conversation" id="recentConversationSection" style="display: none;">\n                <div class="ticketping-recent-conversation-header">\n                  <span class="ticketping-recent-conversation-title">Recent Conversation</span>\n                </div>\n                <div class="ticketping-recent-conversation-item" id="recentConversationItem">\n                  <div class="ticketping-recent-conversation-preview"></div>\n                  <div class="ticketping-recent-conversation-time"></div>\n                </div>\n              </div>\n              <button class="ticketping-start-conversation-btn">\n                <div class="ticketping-start-conversation-btn-content">\n                  <span class="ticketping-start-conversation-btn-text">Send us a message</span>\n                  <span class="ticketping-start-conversation-btn-subtext">${this.getResponseTimeText()}</span>\n                </div>\n                <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 18 18"><path d="M16.345,1.654c-.344-.344-.845-.463-1.305-.315L2.117,5.493c-.491,.158-.831,.574-.887,1.087-.056,.512,.187,.992,.632,1.251l4.576,2.669,3.953-3.954c.293-.293,.768-.293,1.061,0s.293,.768,0,1.061l-3.954,3.954,2.669,4.576c.235,.402,.65,.639,1.107,.639,.048,0,.097-.003,.146-.008,.512-.056,.929-.396,1.086-.886L16.661,2.96h0c.148-.463,.027-.963-.316-1.306Z" fill="currentColor" fill-opacity="0.6"></path></svg>\n              </button>\n            </div>\n          </div>\n          <div class="ticketping-plug">\n            <a href="https://ticketping.com" target="_blank" rel="noopener noreferrer">\n              <span>Powered by</span> <svg width="65.499" height="13" viewBox="0 0 65.499 13" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Ticketping" style="margin-top: 1px;"><path d="M35.072 9.717q-0.6 0 -0.96 -0.36 -0.347 -0.36 -0.347 -0.96V4.304h-1.813V3.144h1.813V0.971h1.374v2.173h1.96v1.16h-1.96V8.157q0 0.4 0.374 0.4h1.374V9.717zm-6.992 0.186q-1 0 -1.746 -0.413 -0.746 -0.427 -1.173 -1.186 -0.413 -0.773 -0.413 -1.786v-0.16q0 -1.026 0.413 -1.786 0.413 -0.773 1.147 -1.186 0.746 -0.427 1.72 -0.427 0.947 0 1.653 0.427 0.719 0.413 1.12 1.16t0.4 1.746v0.52h-5.054q0.027 0.867 0.573 1.387 0.56 0.506 1.387 0.506 0.773 0 1.16 -0.347 0.4 -0.347 0.613 -0.801l1.133 0.587q-0.186 0.374 -0.547 0.786 -0.347 0.413 -0.92 0.693t-1.467 0.281m-1.921 -4.148h3.64q-0.053 -0.746 -0.534 -1.16 -0.48 -0.427 -1.253 -0.427t-1.266 0.427q-0.48 0.413 -0.587 1.16M18.099 9.717V0.385h1.374v5.32h0.213l2.586 -2.56h1.826l-3.319 3.187 3.427 3.386H22.392l-2.707 -2.733h-0.213v2.733zm-4.837 0.186q-0.947 0 -1.72 -0.4 -0.759 -0.4 -1.213 -1.16 -0.44 -0.759 -0.44 -1.826v-0.173q0 -1.067 0.44 -1.813 0.453 -0.759 1.213 -1.16 0.773 -0.413 1.72 -0.413t1.613 0.347 1.067 0.92q0.413 0.573 0.534 1.266l-1.334 0.281q-0.067 -0.44 -0.281 -0.801t-0.6 -0.573 -0.973 -0.213q-0.573 0 -1.04 0.266 -0.453 0.253 -0.719 0.746 -0.266 0.48 -0.266 1.173v0.12q0 0.693 0.266 1.186t0.719 0.746q0.467 0.253 1.04 0.253 0.867 0 1.321 -0.44 0.453 -0.453 0.573 -1.147l1.334 0.307q-0.16 0.68 -0.573 1.253 -0.4 0.573 -1.067 0.92 -0.666 0.334 -1.613 0.334m-6.464 -0.186V3.144h1.374V9.717zm0.693 -7.466q-0.4 0 -0.68 -0.253 -0.266 -0.266 -0.266 -0.68T6.812 0.65q0.281 -0.266 0.68 -0.266 0.413 0 0.68 0.266 0.266 0.253 0.266 0.666t-0.266 0.68q-0.266 0.253 -0.68 0.253M3.158 9.719q-0.6 0 -0.96 -0.36 -0.347 -0.36 -0.347 -0.96v-4.095H0.038V3.144h1.813V0.971h1.374v2.173h1.96v1.16H3.225V8.157q0 0.4 0.374 0.4H4.972V9.717zm58.588 -6.721q0.768 0 1.356 0.312 0.6 0.3 0.936 0.756v-0.961h1.38v6.72q0 0.912 -0.385 1.621 -0.385 0.719 -1.116 1.128 -0.719 0.407 -1.728 0.407 -1.343 0 -2.232 -0.636 -0.888 -0.624 -1.009 -1.704h1.356q0.156 0.516 0.66 0.828 0.516 0.324 1.224 0.324 0.828 0 1.331 -0.504 0.516 -0.504 0.516 -1.465V8.72q-0.348 0.468 -0.948 0.792 -0.588 0.312 -1.343 0.312 -0.863 0 -1.584 -0.432 -0.707 -0.444 -1.128 -1.224 -0.407 -0.792 -0.407 -1.789t0.407 -1.764q0.42 -0.768 1.128 -1.187 0.719 -0.432 1.584 -0.432m2.292 3.408q0 -0.685 -0.288 -1.187 -0.276 -0.504 -0.732 -0.768t-0.984 -0.264 -0.984 0.264q-0.456 0.251 -0.744 0.756 -0.276 0.492 -0.276 1.175t0.276 1.2q0.288 0.516 0.744 0.792 0.468 0.264 0.984 0.264 0.529 0 0.984 -0.264t0.732 -0.768q0.288 -0.516 0.288 -1.2m-9.654 -3.406q0.78 0 1.392 0.324 0.624 0.324 0.972 0.96t0.348 1.536v3.9h-1.356V6.021q0 -0.888 -0.444 -1.356 -0.444 -0.48 -1.212 -0.48t-1.224 0.48q-0.444 0.468 -0.444 1.356V9.717h-1.368V3.105h1.368v0.756q0.336 -0.407 0.853 -0.636 0.529 -0.229 1.116 -0.229m-13.743 1.081q0.348 -0.456 0.948 -0.768t1.356 -0.312q0.863 0 1.572 0.432 0.719 0.42 1.128 1.187t0.407 1.764 -0.407 1.789q-0.407 0.78 -1.128 1.224 -0.707 0.432 -1.572 0.432 -0.756 0 -1.343 -0.3 -0.588 -0.312 -0.96 -0.768v4.104h-1.368V3.105h1.368zm4.02 2.304q0 -0.685 -0.288 -1.175 -0.276 -0.504 -0.744 -0.756 -0.456 -0.264 -0.984 -0.264 -0.516 0 -0.984 0.264 -0.456 0.264 -0.744 0.768 -0.276 0.504 -0.276 1.187t0.276 1.2q0.288 0.504 0.744 0.768 0.468 0.264 0.984 0.264 0.529 0 0.984 -0.264 0.468 -0.276 0.744 -0.792 0.288 -0.516 0.288 -1.2m2.981 3.337V3.144h1.374V9.717zm0.693 -7.467q-0.4 0 -0.68 -0.253 -0.266 -0.266 -0.266 -0.68t0.266 -0.666q0.281 -0.266 0.68 -0.266 0.413 0 0.68 0.266 0.266 0.253 0.266 0.666t-0.266 0.68q-0.266 0.253 -0.68 0.253" fill="currentColor"/></svg>\n            </a>\n          </div>\n        </div>\n\n        <div class="ticketping-tab-content" id="messagesTab">\n          <div class="ticketping-messages-header">\n            <button class="ticketping-back-btn" id="tpBackBtn" aria-label="Go back">\n              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 256 256"><path d="M165.66,202.34a8,8,0,0,1-11.32,11.32l-80-80a8,8,0,0,1,0-11.32l80-80a8,8,0,0,1,11.32,11.32L91.31,128Z"></path></svg>\n            </button>\n            <div class="ticketping-tab-heading">\n              <span>Messages</span>\n              <span class="ticketping-status-dot ${this.getAvailabilityStatusClass()}"></span>\n            </div>\n            <button class="ticketping-close-btn-2" aria-label="Close chat">\n              <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">\n                <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>\n              </svg>\n            </button>\n          </div>\n          <div class="ticketping-messages-content">\n            <div class="ticketping-conversation-container">\n              <div class="ticketping-conversation-list ticketping-thin-scrollbar" id="conversationList">\n                \x3c!-- Conversations will be populated here --\x3e\n              </div>\n              <div class="ticketping-send-a-message-container" id="sendMessageBtnContainer">\n                <button class="ticketping-send-message-btn">\n                  <span class="ticketping-send-message-btn-text">Send us a message</span>\n                  <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="16px" height="16px" viewBox="0 0 18 18"><path d="M16.345,1.654c-.344-.344-.845-.463-1.305-.315L2.117,5.493c-.491,.158-.831,.574-.887,1.087-.056,.512,.187,.992,.632,1.251l4.576,2.669,3.953-3.954c.293-.293,.768-.293,1.061,0s.293,.768,0,1.061l-3.954,3.954,2.669,4.576c.235,.402,.65,.639,1.107,.639,.048,0,.097-.003,.146-.008,.512-.056,.929-.396,1.086-.886L16.661,2.96h0c.148-.463,.027-.963-.316-1.306Z" fill="currentColor"></path></svg>\n                </button>\n              </div>\n            </div>\n\n            <div class="active-conversation" id="activeConversation" style="display: none;">\n              <div class="ticketping-loading-state" id="loadingState" style="display: none;">\n                <div class="ticketping-loading-content">\n                  <div class="ticketping-loading-spinner">\n                    <div class="tp-loading-spinner-child"></div>\n                  </div>\n                  <div class="ticketping-loading-text">\n                    <p>Starting conversation...</p>\n                    <p class="ticketping-loading-subtext">Connecting you with support</p>\n                  </div>\n                </div>\n              </div>\n\n              <div class="ticketping-messages-list ticketping-thin-scrollbar" id="messagesList">\n                \x3c!-- Messages will be populated here --\x3e\n              </div>\n\n              <div class="typing-indicator" id="typingIndicator">\n                Support is typing\n                <div class="typing-dots">\n                  <span></span>\n                  <span></span>\n                  <span></span>\n                </div>\n              </div>\n\n              <div class="ticketping-availability-bar" id="availabilityBar">\n                ${this.getAvailabilityHtml()}\n              </div>\n\n              <div class="ticketping-message-input-container">\n                <div class="ticketping-message-input-wrapper">\n                  <textarea\n                    id="messageInput"\n                    class="ticketping-message-input"\n                    placeholder="Type your message..."\n                    rows="1"\n                  ></textarea>\n                  <div class="ticketping-input-actions">\n                    <div class="ticketping-file-input-container">\n                      <input type="file" class="ticketping-file-input" accept="image/*,.pdf,.doc,.docx">\n                      <button class="ticketping-file-btn">\n                        <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="16px" height="16px" viewBox="0 0 18 18"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.5 1.75C14.5 1.33579 14.1642 1 13.75 1C13.3358 1 13 1.33579 13 1.75V3.5H11.25C10.8358 3.5 10.5 3.83579 10.5 4.25C10.5 4.66421 10.8358 5 11.25 5H13V6.75C13 7.16421 13.3358 7.5 13.75 7.5C14.1642 7.5 14.5 7.16421 14.5 6.75V5H16.25C16.6642 5 17 4.66421 17 4.25C17 3.83579 16.6642 3.5 16.25 3.5H14.5V1.75Z" fill="currentColor"></path>\n<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.75C2 2.67879 3.67879 1 5.75 1C7.82121 1 9.5 2.67879 9.5 4.75V11.75C9.5 12.9922 8.49221 14 7.25 14C6.00779 14 5 12.9922 5 11.75V5C5 4.58579 5.33579 4.25 5.75 4.25C6.16421 4.25 6.5 4.58579 6.5 5V11.75C6.5 12.1638 6.83621 12.5 7.25 12.5C7.66379 12.5 8 12.1638 8 11.75V4.75C8 3.50721 6.99279 2.5 5.75 2.5C4.50721 2.5 3.5 3.50721 3.5 4.75V11.75C3.5 13.8208 5.17921 15.5 7.25 15.5C9.32079 15.5 11 13.8208 11 11.75V8.75C11 8.33579 11.3358 8 11.75 8C12.1642 8 12.5 8.33579 12.5 8.75V11.75C12.5 14.6492 10.1492 17 7.25 17C4.35079 17 2 14.6492 2 11.75V4.75Z" fill="currentColor" fill-opacity="0.4" data-color="color-2"></path></svg>\n                      </button>\n                    </div>\n                    <button class="ticketping-send-btn" disabled>\n                      <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M208.49,120.49a12,12,0,0,1-17,0L140,69V216a12,12,0,0,1-24,0V69L64.49,120.49a12,12,0,0,1-17-17l72-72a12,12,0,0,1,17,0l72,72A12,12,0,0,1,208.49,120.49Z"></path></svg>\n                    </button>\n                  </div>\n                </div>\n                <div class="ticketping-uploading-overlay" style="display: none;">\n                  <div class="ticketping-uploading-content">\n                    <div class="ticketping-spinner">\n                      <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n                        <circle cx="12" cy="12" r="10" stroke="#e5e7eb" stroke-width="2"/>\n                        <path d="M12 2a10 10 0 0 1 10 10" stroke="#3b82f6" stroke-width="2" stroke-linecap="round">\n                          <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/>\n                        </path>\n                      </svg>\n                    </div>\n                    <span class="ticketping-uploading-text">Uploading...</span>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <div class="ticketping-chat-tabs" id="ticketpingChatTabs">\n        <button class="ticketping-tab active" data-tab="home">\n          <div class="tab-icon">\n<svg class="icon-inactive" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 18 18"><path d="M14.855 5.95L9.605 1.96C9.247 1.688 8.752 1.688 8.395 1.96L3.145 5.95C2.896 6.139 2.75 6.434 2.75 6.747V14.251C2.75 15.356 3.645 16.251 4.75 16.251H7.25V12.251C7.25 11.699 7.698 11.251 8.25 11.251H9.75C10.302 11.251 10.75 11.699 10.75 12.251V16.251H13.25C14.355 16.251 15.25 15.356 15.25 14.251V6.746C15.25 6.433 15.104 6.14 14.855 5.95Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" fill="none"></path></svg>\n            <svg class="icon-active" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 18 18"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.0591 1.36312C9.4333 0.886573 8.56694 0.887449 7.94127 1.36281L2.69155 5.3526C2.2559 5.68346 2 6.19867 2 6.746V14.25C2 15.7692 3.23079 17 4.75 17H13.25C14.7692 17 16 15.7692 16 14.25V6.746C16 6.20008 15.7448 5.68398 15.3088 5.35288L10.0591 1.36312Z" fill="currentColor" fill-opacity="0.4" data-color="color-2"></path>\n<path d="M11.5 13.5V17H6.5V13.5C6.5 12.1193 7.61929 11 9 11C10.3807 11 11.5 12.1193 11.5 13.5Z" fill="currentColor"></path></svg>\n          </div>\n          <span>Home</span>\n        </button>\n        <button class="ticketping-tab" data-tab="messages">\n          <div class="tab-icon">\n            <div class="ticketping-tab-unread-dot" id="messagesTabUnreadDot" style="display: none;"></div>\n<svg class="icon-inactive" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 18 18"><path d="M14.25,2.25H3.75c-1.105,0-2,.896-2,2v7c0,1.104,.895,2,2,2h2v3l3.75-3h4.75c1.105,0,2-.896,2-2V4.25c0-1.104-.895-2-2-2Z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"></path><line x1="5" y1="6.25" x2="13" y2="6.25" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" data-color="color-2"></line><line x1="5" y1="9.25" x2="10.25" y2="9.25" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" data-color="color-2"></line></svg>\n            <svg class="icon-active" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 18 18"><path d="M3.75 1.5C2.23054 1.5 1 2.73203 1 4.25V11.25C1 12.768 2.23054 14 3.75 14H5V16.25C5 16.5383 5.16526 16.8011 5.42511 16.926C5.68496 17.0509 5.99339 17.0158 6.21852 16.8357L9.76309 14H14.25C15.7695 14 17 12.768 17 11.25V4.25C17 2.73203 15.7695 1.5 14.25 1.5H3.75Z" fill="currentColor" fill-opacity="0.4" data-color="color-2"></path>\n<path fill-rule="evenodd" clip-rule="evenodd" d="M4.25 6.25C4.25 5.83579 4.58579 5.5 5 5.5H13C13.4142 5.5 13.75 5.83579 13.75 6.25C13.75 6.66421 13.4142 7 13 7H5C4.58579 7 4.25 6.66421 4.25 6.25Z" fill="currentColor"></path>\n<path fill-rule="evenodd" clip-rule="evenodd" d="M4.25 9.25C4.25 8.83579 4.58579 8.5 5 8.5H10.25C10.6642 8.5 11 8.83579 11 9.25C11 9.66421 10.6642 10 10.25 10H5C4.58579 10 4.25 9.66421 4.25 9.25Z" fill="currentColor"></path></svg>\n\n          </div>\n          <span>Messages</span>\n        </button>\n      </div>\n    `,this.container.appendChild(this.element)}attachEventListeners(){this.element.querySelector(".ticketping-close-btn").addEventListener("click",()=>{this.options.onClose()}),this.element.querySelector(".ticketping-close-btn-2").addEventListener("click",()=>{this.options.onClose()}),this.element.querySelector("#tpBackBtn").addEventListener("click",()=>{this.showConversationList(),this.options.onBackButtonClick()}),this.element.querySelectorAll(".ticketping-tab").forEach(e=>{e.addEventListener("click",()=>{this.switchTab(e.dataset.tab)})}),this.element.querySelector(".ticketping-start-conversation-btn").addEventListener("click",()=>{this.options.onConversationSelect("new"),setTimeout(()=>{this.element.querySelector("#messageInput").focus()},50)}),this.element.querySelector(".ticketping-send-message-btn").addEventListener("click",()=>{this.options.onConversationSelect("new"),setTimeout(()=>{this.element.querySelector("#messageInput").focus()},50)});const e=this.element.querySelector("#recentConversationItem");e&&e.addEventListener("click",()=>{const t=e.dataset.conversationId;t&&this.options.onConversationSelect(t)});const t=this.element.querySelector("#messageInput"),s=this.element.querySelector(".ticketping-send-btn");t.addEventListener("input",()=>{this.handleInputChange(t,s)}),t.addEventListener("keypress",e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),this.sendMessage(t,s))}),s.addEventListener("click",()=>{this.sendMessage(t,s)});const i=this.element.querySelector(".ticketping-file-btn"),n=this.element.querySelector(".ticketping-file-input");i.addEventListener("click",()=>n.click()),n.addEventListener("change",()=>this.handleFileUpload(n))}show(){this.element.classList.add(b)}hide(){this.element.classList.remove(b)}switchTab(e){this.activeTab=e,this.element.querySelectorAll(".ticketping-tab").forEach(t=>{t.classList.toggle("active",t.dataset.tab===e)}),this.element.querySelectorAll(".ticketping-tab-content").forEach(t=>{t.classList.toggle("active",t.id===`${e}Tab`)}),"messages"===e?(this.element.querySelector("#conversationList").classList.add("show"),this.element.querySelector("#sendMessageBtnContainer").classList.add("show")):(this.element.querySelector("#conversationList").classList.remove("show"),this.element.querySelector("#sendMessageBtnContainer").classList.remove("show")),this.options.onTabSwitch(e)}setConversations(e,t=new Set){this.conversations=e,this.unreadConversations=t instanceof Set?t:new Set(t),this.renderConversationList(),this.updateRecentConversation()}renderConversationList(){const e=this.element.querySelector("#conversationList");if(0===this.conversations.length)return void this.showEmptyState();e.innerHTML="";[...this.conversations].sort((e,t)=>{const s=new Date(e.modified||e.created);return new Date(t.modified||t.created)-s}).forEach(t=>{var s;const i=this.unreadConversations.has(t.sessionId),n=h("div",{className:"ticketping-conversation-item"+(i?" unread":""),"data-conversation":t.sessionId}),o=null==(s=t.messages)?void 0:s[t.messages.length-1],a=o?o.messageText.substring(0,50)+"...":"";n.innerHTML=`\n        ${i?'<div class="ticketping-unread-dot"></div>':""}\n        <div class="ticketping-conversation-preview${i?" unread":""}">${t.summary||a||"Support Chat"}</div>\n        <div class="ticketping-conversation-time">${this.formatDateTime(t.modified||t.created)}</div>\n      `,n.addEventListener("click",()=>{this.options.onConversationSelect(t.sessionId)}),e.appendChild(n)})}showEmptyState(){this.element.querySelector("#conversationList").innerHTML='\n      <div class="empty-state">\n        <div class="empty-state-content">\n          <p>No conversations yet</p>\n          <p class="empty-state-subtext">Send us a message to get help</p>\n        </div>\n      </div>\n    '}showConversationItem(){this.element.querySelector("#conversationList").classList.remove("show"),this.element.querySelector("#activeConversation").style.display="flex",this.element.querySelector("#tpBackBtn").classList.add("show"),this.element.querySelector("#sendMessageBtnContainer").classList.remove("show"),this.element.querySelector("#ticketpingChatTabs").style.display="none",this.hideLoadingState(),setTimeout(()=>{this.element.querySelector("#messageInput").focus()},50)}showConversationList(){this.element.querySelector("#conversationList").classList.add("show"),this.element.querySelector("#activeConversation").style.display="none",this.element.querySelector("#tpBackBtn").classList.remove("show"),this.element.querySelector("#sendMessageBtnContainer").classList.add("show"),this.element.querySelector("#ticketpingChatTabs").style.display="flex",this.clearMessages(),this.hideLoadingState()}showLoadingState(){this.element.querySelector("#conversationList").classList.remove("show"),this.element.querySelector("#activeConversation").style.display="flex",this.element.querySelector("#loadingState").style.display="flex",this.element.querySelector("#messagesList").style.display="none",this.element.querySelector("#typingIndicator").style.display="none",this.element.querySelector(".ticketping-message-input-container").style.display="none",this.element.querySelector("#tpBackBtn").classList.add("show"),this.element.querySelector("#sendMessageBtnContainer").classList.remove("show"),this.element.querySelector("#ticketpingChatTabs").style.display="none"}hideLoadingState(){this.element.querySelector("#loadingState").style.display="none",this.element.querySelector("#messagesList").style.display="block",this.element.querySelector("#typingIndicator").style.display="none",this.element.querySelector(".ticketping-message-input-container").style.display="block"}addMessage(e){const t=this.element.querySelector("#messagesList"),s=this.currentMessages[this.currentMessages.length-1];this.currentMessages.push(e);const i=this.processNewMessageForGrouping(e,s);if(i.updatePrevious&&s){const e=t.querySelectorAll(".ticketping-message"),i=e[e.length-1];i&&this.updateMessageElementForGrouping(i,s,!1)}if(i.showDateSeparator){const e=this.createDateSeparatorElement(i.created);t.appendChild(e)}const n=this.createMessageElement(i);t.appendChild(n),this.scrollToBottom()}setMessages(e){const t=this.element.querySelector("#messagesList");t.innerHTML="",this.currentMessages=[...e];this.processMessagesForGrouping(e).forEach(e=>{if(e.showDateSeparator){const s=this.createDateSeparatorElement(e.created);t.appendChild(s)}const s=this.createMessageElement(e);t.appendChild(s)}),this.scrollToBottom()}clearMessages(){this.element.querySelector("#messagesList").innerHTML="",this.currentMessages=[]}createMessageElement(e){let t=`ticketping-message ${e.sender.toLowerCase()}`;e.isGrouped&&(t+=" grouped"),e.isFirstInGroup&&(t+=" first-in-group"),e.isLastInGroup&&(t+=" last-in-group");const s=h("div",{className:t}),i=e.filename&&e.filepath,n=!1!==e.showTimestamp;if(i){const t=e.messageHtml?e.messageHtml:this.escapeHtml(e.messageText||""),i=this.createAttachmentHtml(e.filename,e.filepath);s.innerHTML=`\n        <div class="ticketping-message-bubble">\n          ${t}\n          ${i}\n        </div>\n        ${n?`<div class="ticketping-message-time">${this.formatTime(e.created)}</div>`:""}\n      `}else s.innerHTML=`\n        <div class="ticketping-message-bubble">${e.messageHtml?e.messageHtml:this.escapeHtml(e.messageText)}</div>\n        ${n?`<div class="ticketping-message-time">${this.formatTime(e.created)}</div>`:""}\n      `;return s}createDateSeparatorElement(e){const t=h("div",{className:"ticketping-date-separator"});return t.innerHTML=`\n      <div class="ticketping-date-separator-line"></div>\n      <div class="ticketping-date-separator-text">${this.formatDateSeparator(e)}</div>\n      <div class="ticketping-date-separator-line"></div>\n    `,t}processMessagesForGrouping(e){if(!e||0===e.length)return e;if(1===e.length)return[c(r({},e[0]),{showTimestamp:!0})];const t=e.map(e=>c(r({},e),{showTimestamp:!1,showDateSeparator:!1})),s=[];let i={start:0,end:0,sender:t[0].sender};for(let n=1;n<t.length;n++){const e=t[n],o=t[n-1];this.getDateInUserTimezone(e.created)!==this.getDateInUserTimezone(o.created)&&(t[n].showDateSeparator=!0);const a=new Date(e.created).getTime()-new Date(o.created).getTime();e.sender!==o.sender||a>3e5?(i.end=n-1,s.push(i),i={start:n,end:n,sender:e.sender}):i.end=n}return s.push(i),s.forEach(e=>{if(t[e.end].showTimestamp=!0,e.start===e.end)t[e.start].showTimestamp=!0;else for(let s=e.start;s<=e.end;s++)t[s].isGrouped=!0,t[s].isFirstInGroup=s===e.start,t[s].isLastInGroup=s===e.end}),t[0].showTimestamp=!0,t}processNewMessageForGrouping(e,t){const s=c(r({},e),{showTimestamp:!0,showDateSeparator:!1,isGrouped:!1,isFirstInGroup:!1,isLastInGroup:!1,updatePrevious:!1});if(!t)return s;this.getDateInUserTimezone(e.created)!==this.getDateInUserTimezone(t.created)&&(s.showDateSeparator=!0);const i=new Date(e.created).getTime()-new Date(t.created).getTime();return e.sender!==t.sender||i>3e5||(s.isGrouped=!0,s.isLastInGroup=!0,s.showTimestamp=!0,s.updatePrevious=!0),s}updateMessageElementForGrouping(e,t,s){e.classList.add("grouped"),e.classList.remove("last-in-group");const i=e.querySelector(".ticketping-message-time");i&&(i.style.display=s?"block":"none")}handleInputChange(e,t){const s=e.value.trim().length>0;t.disabled=!s,this.toggleFileInputButton(!s),this.autoResizeTextarea(e)}sendMessage(e,t){const s=e.value.trim();s&&(this.options.onSendMessage({text:s}),e.value="",t.disabled=!0,this.toggleFileInputButton(!0),this.autoResizeTextarea(e))}toggleFileInputButton(e){const t=this.element.querySelector(".ticketping-file-input-container");t&&t.classList.toggle("tp-hidden",!e)}handleFileUpload(e){return l(this,null,function*(){const t=e.files[0];t&&(this.setUploadingState(!0),yield this.options.onFileUpload(t),e.value="",this.finishFileUpload())})}setUploadingState(e){this.isUploading=e;const t=this.element.querySelector(".ticketping-uploading-overlay");t.style.display=e?"flex":"none"}finishFileUpload(){this.setUploadingState(!1)}showTypingIndicator(e=!0){this.element.querySelector("#typingIndicator").classList.toggle("show",e),e&&this.scrollToBottom()}autoResizeTextarea(e){e.style.height="auto",e.style.height=Math.min(e.scrollHeight,100)+"px"}scrollToBottom(){const e=this.element.querySelector("#messagesList");setTimeout(()=>{e.scrollTop=e.scrollHeight},100)}formatTime(e){return new Date(e).toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})}formatDateTime(e){return new Date(e).toLocaleString([],{month:"long",day:"numeric",hour:"numeric",minute:"2-digit"})}getDateInUserTimezone(e){return new Date(e).toLocaleDateString()}formatDateSeparator(e){const t=new Date(e),s=new Date,i=new Date(s);i.setDate(i.getDate()-1);const n=this.getDateInUserTimezone(e),o=this.getDateInUserTimezone(s),a=this.getDateInUserTimezone(i);return n===o?"Today":n===a?"Yesterday":t.toLocaleDateString([],{weekday:"long",month:"long",day:"numeric",year:t.getFullYear()!==s.getFullYear()?"numeric":void 0})}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}getLogoHtml(){const e=this.options.teamLogoIcon;return e?`<img src="${e}" alt="logo">`:'<svg width="40" height="40" viewBox="0 0 1.2 1.2" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.1 0.25a0.15 0.15 0 1 1 -0.3 0 0.15 0.15 0 0 1 0.3 0" fill="#4CB782"/><path opacity=".5" d="M0.762 0.127A0.5 0.5 0 0 0 0.6 0.1C0.324 0.1 0.1 0.324 0.1 0.6c0 0.08 0.019 0.156 0.052 0.223 0.009 0.018 0.012 0.038 0.007 0.057l-0.03 0.111a0.065 0.065 0 0 0 0.08 0.08l0.111 -0.03a0.082 0.082 0 0 1 0.057 0.007A0.498 0.498 0 0 0 0.6 1.1c0.276 0 0.5 -0.224 0.5 -0.5 0 -0.057 -0.009 -0.111 -0.027 -0.162a0.225 0.225 0 0 1 -0.312 -0.312" fill="#1C274C"/></svg>'}getWelcomeTitle(){return"Hi there 👋"}getWelcomeMessage(){const e=this.options.teamSettings;return(null==e?void 0:e.widgetWelcomeMessage)?this.escapeHtml(e.widgetWelcomeMessage):"How can we help you?"}getAvailabilityHtml(){const e=this.options.teamSettings;if(!e)return"";const{isAvailable:t,nextAvailable:s,workHoursDisplay:i}=e;if(t)return"";const n='<svg class="ticketping-availability-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 18 18"><path fill-rule="evenodd" clip-rule="evenodd" d="M8.54419 1.47446C8.70875 1.73227 8.70028 2.06417 8.52278 2.31324C7.88003 3.21522 7.5 4.31129 7.5 5.49999C7.5 8.53778 9.96222 11 13 11C14.0509 11 15.029 10.7009 15.8667 10.1868C16.1275 10.0267 16.4594 10.0412 16.7053 10.2233C16.9513 10.4054 17.0619 10.7186 16.9848 11.0148C16.0904 14.4535 12.9735 17 9.25 17C4.83179 17 1.25 13.4182 1.25 8.99999C1.25 5.08453 4.06262 1.83365 7.77437 1.14073C8.07502 1.0846 8.37963 1.21666 8.54419 1.47446Z" fill="currentColor"></path></svg>',o='<div class="ticketping-availability-subtitle">Leave a message and we\'ll pick it up first thing.</div>';return s?`\n        <div class="ticketping-availability ticketping-availability--offline">\n          ${n}\n          <div class="ticketping-availability-content">\n            <div class="ticketping-availability-title">Offline right now — back ${s.dayName} at ${s.timeFormatted} ${s.timezoneAbbr}</div>\n            ${o}\n          </div>\n        </div>\n      `:(null==i?void 0:i.full)?`\n        <div class="ticketping-availability ticketping-availability--offline">\n          ${n}\n          <div class="ticketping-availability-content">\n            <div class="ticketping-availability-title">Offline right now — Hours: ${this.escapeHtml(i.full)}</div>\n            ${o}\n          </div>\n        </div>\n      `:`\n      <div class="ticketping-availability ticketping-availability--offline">\n        ${n}\n        <div class="ticketping-availability-content">\n          <div class="ticketping-availability-title">Offline right now</div>\n          ${o}\n        </div>\n      </div>\n    `}getAvailabilityStatusClass(){const e=this.options.teamSettings;return e?e.isAvailable?"online":"offline":"online"}getResponseTimeText(){const e=this.options.teamSettings;return e?e.isAvailable?"Typically replies within minutes":e.nextAvailable?`We'll respond on ${e.nextAvailable.dayName} at ${e.nextAvailable.timeFormatted}`:"Typically replies within minutes":"Typically replies within minutes"}isImageFile(e){const t=e.toLowerCase().substring(e.lastIndexOf("."));return[".jpg",".jpeg",".png",".gif",".bmp",".webp",".svg"].includes(t)}createAttachmentHtml(e,t){const s=this.escapeHtml(e);return this.isImageFile(e)?`\n        <div class="ticketping-message-attachment">\n          <div class="ticketping-attachment-image">\n            <a href="${t}" target="_blank" rel="noopener noreferrer">\n              <div class="ticketping-image-container">\n                <div class="ticketping-image-placeholder"></div>\n                <img src="${t}" alt="${s}" class="ticketping-attachment-img" onload="this.parentElement.classList.add('loaded')" onerror="this.parentElement.classList.add('error')" />\n              </div>\n            </a>\n          </div>\n        </div>\n      `:`\n        <div class="ticketping-message-attachment">\n          <div class="ticketping-attachment-info">\n            <div class="ticketping-attachment-name">\n              <a href="${t}" target="_blank" rel="noopener noreferrer" style="color: #3B82F6; text-decoration: underline;">\n                ${s}\n              </a>\n            </div>\n          </div>\n        </div>\n      `}updateAgentStatus(e){const t=this.element.querySelector(".ticketping-chat-header-content p");t.textContent="online"===e?"We're online and ready to help!":"We'll get back to you soon!"}updateRecentConversation(){var e;const t=this.element.querySelector("#recentConversationSection"),s=this.element.querySelector("#recentConversationItem");if(!t||!s)return;if(0===this.conversations.length)return void(t.style.display="none");const i=[...this.conversations].sort((e,t)=>{const s=new Date(e.modified||e.created);return new Date(t.modified||t.created)-s})[0],n=this.unreadConversations.has(i.sessionId),o=null==(e=i.messages)?void 0:e[i.messages.length-1],a=o?o.messageText.substring(0,60)+"...":"",r=i.summary||a||"Support Chat",c=s.querySelector(".ticketping-recent-conversation-preview");if(c.textContent=r,n){if(s.classList.add("unread"),c.classList.add("unread"),!s.querySelector(".ticketping-unread-dot")){const e=h("div",{className:"ticketping-unread-dot"});s.insertBefore(e,s.firstChild)}}else{s.classList.remove("unread"),c.classList.remove("unread");const e=s.querySelector(".ticketping-unread-dot");e&&e.remove()}s.querySelector(".ticketping-recent-conversation-time").textContent=this.formatDateTime(i.modified||i.created),s.dataset.conversationId=i.sessionId,t.style.display="block"}setMessagesTabUnread(e){const t=this.element.querySelector("#messagesTabUnreadDot");t&&(t.style.display=e?"block":"none")}showError(e){console.error(e)}destroy(){this.element&&this.element.parentNode&&this.element.parentNode.removeChild(this.element)}}class I{constructor(e,t=null,s={}){this.wsUrl=e,this.token=t,this.isAnonymous=!t,this.options=r({onSessionState:()=>{},onMessage:()=>{},onFileAttachment:()=>{},onMessageHistory:()=>{},onTyping:()=>{},onStatusChange:()=>{},onError:()=>{},onConnect:()=>{},onDisconnect:()=>{},reconnectAttempts:5,reconnectDelay:1e3,heartbeatInterval:3e4},s),this.ws=null,this.isConnected=!1,this.reconnectCount=0,this.heartbeatTimer=null,this.reconnectTimer=null,this.typingTimer=null,this.connect()}connect(){try{this.ws=new WebSocket(this.wsUrl),this.attachEventListeners()}catch(e){console.error("WebSocket connection failed:",e),this.options.onError(e),this.scheduleReconnect()}}attachEventListeners(){this.ws.onopen=e=>{console.log("WebSocket connected"),this.isConnected=!0,this.reconnectCount=0,this.authenticate(),this.startHeartbeat(),this.options.onConnect(e)},this.ws.onmessage=e=>{try{const t=JSON.parse(e.data);this.handleMessage(t)}catch(t){console.error("Failed to parse WebSocket message:",t),this.options.onError(t)}},this.ws.onclose=e=>{console.log("WebSocket disconnected:",e.code,e.reason),this.isConnected=!1,this.stopHeartbeat(),this.options.onDisconnect(e),1e3!==e.code&&this.reconnectCount<this.options.reconnectAttempts&&this.scheduleReconnect()},this.ws.onerror=e=>{console.error("WebSocket error:",e),this.options.onError(e)}}authenticate(){this.isAnonymous?this.send({type:y.AUTH,anonymous:!0}):this.send({type:y.AUTH,token:this.token})}handleMessage(e){switch(e.type){case y.SERVER_STATE:this.options.onSessionState(e);break;case y.SERVER_MESSAGE:this.options.onMessage(e);break;case y.FILE_ATTACHMENT:this.options.onFileAttachment(e);break;case y.SERVER_MESSAGE_HISTORY:this.options.onMessageHistory(e);break;case y.SERVER_TYPING:this.options.onTyping(e);break;case y.SERVER_AGENT_STATUS:this.options.onStatusChange(e);break;case y.SERVER_AGENT_JOINED:this.options.onStatusChange(r({type:"agent_joined"},e));break;case y.SERVER_AGENT_LEFT:this.options.onStatusChange(r({type:"agent_left"},e));break;case y.SERVER_CONVERSATION_UPDATED:this.options.onMessage(e);break;case y.SERVER_AUTH_SUCCESS:console.log("WebSocket authentication successful");break;case y.SERVER_AUTH_FAILED:console.error("WebSocket authentication failed"),this.options.onError(new Error("Authentication failed")),this.disconnect();break;case y.SERVER_ANONYMOUS_AUTH_SUCCESS:console.log("Anonymous WebSocket authentication successful");break;case y.SERVER_ANONYMOUS_AUTH_FAILED:console.error("Anonymous WebSocket authentication failed"),this.options.onError(new Error("Anonymous authentication failed")),this.disconnect();break;case y.PONG:break;case y.ERROR:console.error("WebSocket error:",e.message),this.options.onError(new Error(e.message));break;default:console.warn("Unknown WebSocket message type:",e.type)}}send(e){if(!this.isConnected||this.ws.readyState!==WebSocket.OPEN)return console.warn("WebSocket not connected, message queued"),!1;try{return this.ws.send(JSON.stringify(e)),!0}catch(t){return console.error("Failed to send WebSocket message:",t),this.options.onError(t),!1}}sendMessage(e){return this.send(r(r({},e),e.file&&{file:e.file}))}sendTypingStart(e){this.typingTimer&&clearTimeout(this.typingTimer),this.send({type:y.TYPING_START,conversationId:e}),this.typingTimer=setTimeout(()=>{this.sendTypingStop(e)},3e3)}sendTypingStop(e){this.typingTimer&&(clearTimeout(this.typingTimer),this.typingTimer=null),this.send({type:y.TYPING_STOP,conversationId:e})}joinConversation(e){return this.send({type:y.JOIN_CONVERSATION,conversationId:e})}leaveConversation(e){return this.send({type:y.LEAVE_CONVERSATION,conversationId:e})}markRead(e){return this.send({type:y.MARK_READ,sessionId:e})}startHeartbeat(){this.heartbeatTimer=setInterval(()=>{this.isConnected&&this.send({type:"ping"})},this.options.heartbeatInterval)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}scheduleReconnect(){if(this.reconnectCount>=this.options.reconnectAttempts)return console.error("Max reconnection attempts reached"),void this.options.onError(new Error("Max reconnection attempts reached"));this.reconnectCount++;const e=this.options.reconnectDelay*Math.pow(2,this.reconnectCount-1);console.log(`Reconnecting in ${e}ms (attempt ${this.reconnectCount})`),this.reconnectTimer=setTimeout(()=>{console.log(`Reconnection attempt ${this.reconnectCount}`),this.connect()},e)}reconnect(){this.disconnect(),this.reconnectCount=0,this.connect()}disconnect(){this.isConnected=!1,this.stopHeartbeat(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.typingTimer&&(clearTimeout(this.typingTimer),this.typingTimer=null),this.ws&&(this.ws.close(1e3,"Client disconnect"),this.ws=null)}getConnectionState(){if(!this.ws)return"DISCONNECTED";switch(this.ws.readyState){case WebSocket.CONNECTING:return"CONNECTING";case WebSocket.OPEN:return"CONNECTED";case WebSocket.CLOSING:return"CLOSING";case WebSocket.CLOSED:return"DISCONNECTED";default:return"UNKNOWN"}}isAnonymousUser(){return this.isAnonymous}isWsConnected(){return this.isConnected&&this.ws&&this.ws.readyState===WebSocket.OPEN}on(e,t){switch(e){case"message":this.options.onMessage=t;break;case"typing":this.options.onTyping=t;break;case"status":this.options.onStatusChange=t;break;case"error":this.options.onError=t;break;case"connect":this.options.onConnect=t;break;case"disconnect":this.options.onDisconnect=t;break;default:console.warn("Unknown event type:",e)}}destroy(){this.disconnect()}}class E{constructor(e,t={}){this.wsUrl=e,this.options=r({onUnreadCount:()=>{},onConnect:()=>{},onDisconnect:()=>{},onError:()=>{},reconnectAttempts:10,reconnectDelay:2e3,heartbeatInterval:3e4},t),this.ws=null,this.isConnected=!1,this.reconnectCount=0,this.heartbeatTimer=null,this.reconnectTimer=null,this.shouldReconnect=!0,this.connect()}connect(){if(this.shouldReconnect)try{this.ws=new WebSocket(this.wsUrl),this.attachEventListeners()}catch(e){console.error("Notification WebSocket connection failed:",e),this.options.onError(e),this.scheduleReconnect()}}attachEventListeners(){this.ws.onopen=()=>{console.log("Notification WebSocket connected"),this.isConnected=!0,this.reconnectCount=0,this.startHeartbeat(),this.requestUnreadCount(),this.options.onConnect()},this.ws.onmessage=e=>{try{const t=JSON.parse(e.data);this.handleMessage(t)}catch(t){console.error("Failed to parse notification message:",t)}},this.ws.onclose=e=>{console.log("Notification WebSocket disconnected:",e.code,e.reason),this.isConnected=!1,this.stopHeartbeat(),this.options.onDisconnect(e),console.log(e);const t=1e3!==e.code&&1006!==e.code;this.shouldReconnect&&t&&this.scheduleReconnect()},this.ws.onerror=e=>{console.error("Notification WebSocket error:",e),this.options.onError(e)}}handleMessage(e){switch(e.type){case"unread_count":this.options.onUnreadCount(e.count);break;case"pong":break;default:console.log("Unknown notification message type:",e.type)}}send(e){if(this.isConnected&&this.ws.readyState===WebSocket.OPEN)try{return this.ws.send(JSON.stringify(e)),!0}catch(t){return console.error("Failed to send notification message:",t),!1}return!1}requestUnreadCount(){return this.send({type:"get_unread_count"})}startHeartbeat(){this.heartbeatTimer=setInterval(()=>{this.isConnected&&this.send({type:"ping"})},this.options.heartbeatInterval)}stopHeartbeat(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)}scheduleReconnect(){if(!this.shouldReconnect)return;if(this.reconnectCount>=this.options.reconnectAttempts)return void console.error("Notification WebSocket: Max reconnection attempts reached");this.reconnectCount++;const e=this.options.reconnectDelay*Math.pow(1.5,this.reconnectCount-1);console.log(`Notification WebSocket: Reconnecting in ${e}ms (attempt ${this.reconnectCount})`),this.reconnectTimer=setTimeout(()=>{this.connect()},e)}disconnect(){this.shouldReconnect=!1,this.isConnected=!1,this.stopHeartbeat(),this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.ws&&(this.ws.close(1e3,"Client disconnect"),this.ws=null)}isWsConnected(){return this.isConnected&&this.ws&&this.ws.readyState===WebSocket.OPEN}destroy(){this.disconnect()}}const x="ticketping_chat_jwt";class A{constructor(e){this.config=e,this.baseURL=e.apiBase}setCookie(e,t,s){const i=new Date;i.setTime(i.getTime()+60*s*60*1e3);const n=`expires=${i.toUTCString()}`;document.cookie=`${e}=${t};${n};path=/;SameSite=Strict`}getCookie(e){const t=e+"=",s=document.cookie.split(";");for(let i=0;i<s.length;i++){let e=s[i];for(;" "===e.charAt(0);)e=e.substring(1,e.length);if(0===e.indexOf(t))return e.substring(t.length,e.length)}return null}deleteCookie(e){document.cookie=`${e}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;SameSite=Strict`}request(e){return l(this,arguments,function*(e,t={}){const s=`${this.baseURL}${e}`,i=r({"Content-Type":"application/json"},t.headers);this.config.appId&&(i["x-tpwidget-id"]=this.config.appId);const n=r({method:"GET",headers:i},t);try{const e=yield fetch(s,n);if(!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);const t=e.headers.get("content-type");return t&&t.includes("application/json")?yield e.json():yield e.text()}catch(o){throw console.error(`API request failed: ${e}`,o),this.isAuthError(o)&&this.clearChatToken(),o}})}getChatToken(){return l(this,null,function*(){const e=this.getCookie(x);if(e)try{const t=JSON.parse(atob(e.split(".")[1])),s=Math.floor(Date.now()/1e3);if(t.exp&&t.exp>s)return{chatJWT:e}}catch(i){console.log("error",i),console.warn("Invalid cached JWT format, fetching new token"),this.deleteCookie(x)}const t=new URLSearchParams({jwt:this.config.userJWT,team:this.config.teamSlug}),s=yield this.request(`${u}?${t}`,{method:"GET"});return s.jwt&&this.setCookie(x,s.jwt,168),{chatJWT:s.jwt}})}clearChatToken(){this.deleteCookie(x)}createChatSession(){return l(this,null,function*(){const{chatJWT:e}=yield this.getChatToken();return yield this.request(g,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({appId:this.config.appId,team:this.config.teamSlug,jwt:e})})})}getConversations(e=50,t=0){return l(this,null,function*(){const{chatJWT:s}=yield this.getChatToken(),i={Authorization:`Bearer ${s}`,"Content-Type":"application/json"},n=new URLSearchParams({limit:e.toString(),offset:t.toString()});return yield this.request(`${p}?${n}`,{headers:i})})}getMessages(e,t=50,s=null){return l(this,null,function*(){const i=new URLSearchParams({conversationId:e,limit:t.toString()});return s&&i.append("before",s),yield this.request(`${m}?${i}`)})}sendMessage(e){return l(this,null,function*(){return yield this.request(m,{method:"POST",body:JSON.stringify(r({conversationId:e.conversationId,text:e.text,type:e.type||"user",timestamp:e.timestamp,messageId:e.id},e.file&&{file:e.file}))})})}markAsRead(e,t){return l(this,null,function*(){return yield this.request(`${m}/${t}/read`,{method:"POST",body:JSON.stringify({conversationId:e})})})}uploadFile(e,t){return l(this,null,function*(){const s=new FormData;s.append("file",e);const i={};if(this.config.userJWT){const{chatJWT:e}=yield this.getChatToken();e&&(i.Authorization=`Bearer ${e}`)}this.config.appId&&(i["x-tpwidget-id"]=this.config.appId);try{const e=yield fetch(`${this.baseURL}${v}${this.config.teamSlug}/${t}/`,{method:"POST",headers:i,body:s});if(!e.ok)throw new Error(`Upload failed: ${e.statusText}`);return(yield e.json()).url}catch(n){throw console.error("File upload failed:",n),n}})}track(e){return l(this,arguments,function*(e,t={}){})}updateUser(e){return l(this,null,function*(){return yield this.request("/users/me",{method:"PATCH",body:JSON.stringify(e)})})}getAgentStatus(){return l(this,null,function*(){return yield this.request("/agents/status")})}getHelpArticles(e="",t=5){return l(this,null,function*(){const s=new URLSearchParams({q:e,limit:t.toString(),appId:this.config.appId});return yield this.request(`/help/articles?${s}`)})}searchHelpArticles(e){return l(this,null,function*(){return yield this.request("/help/search",{method:"POST",body:JSON.stringify({query:e,appId:this.config.appId})})})}setToken(e){this.token=e}setAppId(e){this.config.appId=e}isNetworkError(e){return e instanceof TypeError&&e.message.includes("fetch")}isAuthError(e){return e.message.includes("401")||e.message.includes("Unauthorized")}isRateLimitError(e){return e.message.includes("429")||e.message.includes("Too Many Requests")}requestWithRetry(e){return l(this,arguments,function*(e,t={},s=3){let i;for(let o=1;o<=s;o++)try{return yield this.request(e,t)}catch(n){if(i=n,this.isAuthError(n)||n.message.includes("4")&&!this.isRateLimitError(n))throw n;if(o<s){const e=1e3*Math.pow(2,o);yield new Promise(t=>setTimeout(t,e))}}throw i})}batchRequest(e){return l(this,null,function*(){return yield this.request("/batch",{method:"POST",body:JSON.stringify({requests:e})})})}getPaginatedData(e){return l(this,arguments,function*(e,t={}){const{limit:s=50,maxItems:i=200,onPage:n=()=>{}}=t,o=[];let a=0,r=!0;for(;r&&o.length<i;){const t=new URLSearchParams({limit:s.toString(),offset:a.toString()}),i=yield this.request(`${e}?${t}`),c=i.data||i.items||i;o.push(...c),n(c,a),r=c.length===s,a+=s}return o.slice(0,i)})}healthCheck(){return l(this,null,function*(){try{return yield this.request("/health"),!0}catch(e){return console.warn("Health check failed:",e.message),!1}})}getTeamWidgetSettings(){return l(this,null,function*(){return yield this.request(`${S}${this.config.teamSlug}/`)})}get(e){return l(this,arguments,function*(e,t={}){return yield this.request(e,r({method:"GET"},t))})}post(e){return l(this,arguments,function*(e,t=null,s={}){const i=r({method:"POST"},s);return t&&(i.body=JSON.stringify(t)),yield this.request(e,i)})}}class N{constructor(){this.isAvailable=this.checkStorageAvailability(),this.deviceId=this.getOrCreateDeviceId()}checkStorageAvailability(){try{const e="__storage_test__";return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return console.warn("localStorage not available, using memory storage:",e.message),this.memoryStorage=new Map,!1}}getOrCreateDeviceId(){let e=this.getItem(w.DEVICE_ID);return e||(e=this.generateUUID(),this.setItem(w.DEVICE_ID,e)),e}generateUUID(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"undefined"!=typeof crypto&&crypto.getRandomValues?"10000000-1000-4000-8000-100000000000".replace(/[018]/g,e=>(+e^crypto.getRandomValues(new Uint8Array(1))[0]&15>>+e/4).toString(16)):"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)})}getDeviceId(){return this.deviceId}setItem(e,t){try{const s=JSON.stringify(t);this.isAvailable?localStorage.setItem(e,s):this.memoryStorage.set(e,s)}catch(s){console.warn("Failed to store item:",e,s)}}getItem(e){try{let t;return t=this.isAvailable?localStorage.getItem(e):this.memoryStorage.get(e),t?JSON.parse(t):null}catch(t){return console.warn("Failed to retrieve item:",e,t),null}}removeItem(e){try{this.isAvailable?localStorage.removeItem(e):this.memoryStorage.delete(e)}catch(t){console.warn("Failed to remove item:",e,t)}}clear(){try{this.isAvailable?Object.values(w).forEach(e=>{localStorage.removeItem(e)}):this.memoryStorage.clear()}catch(e){console.warn("Failed to clear storage:",e)}}saveConversation(e){const t=this.getConversations(),s=t.findIndex(t=>t.sessionId===e.sessionId);s>=0?t[s]=e:t.push(e);t.length>50&&(t.sort((e,t)=>new Date(t.modified||t.created)-new Date(e.modified||e.created)),t.splice(50)),this.setItem(w.CONVERSATIONS,t)}getConversations(){return this.getItem(w.CONVERSATIONS)||[]}clearConversations(){this.removeItem(w.CONVERSATIONS)}deleteConversation(e){const t=this.getConversations().filter(t=>t.sessionId!==e);this.setItem(w.CONVERSATIONS,t)}saveUnreadConversations(e){this.setItem(w.UNREAD_CONVERSATIONS,e)}getUnreadConversations(){return this.getItem(w.UNREAD_CONVERSATIONS)||[]}clearUnreadConversations(){this.removeItem(w.UNREAD_CONVERSATIONS)}setUser(e){this.setItem(w.USER_DATA,c(r({},e),{lastSeen:(new Date).toISOString()}))}getUser(){return this.getItem(w.USER_DATA)}clearUser(){this.removeItem(w.USER_DATA)}saveSettings(e){const t=this.getSettings();this.setItem(w.SETTINGS,r(r({},t),e))}setSettings(e){return this.saveSettings(e)}getSettings(){return this.getItem(w.SETTINGS)||{}}getSetting(e,t=null){const s=this.getSettings();return void 0!==s[e]?s[e]:t}setSetting(e,t){const s=this.getSettings();s[e]=t,this.setItem(w.SETTINGS,s)}cleanupOldData(e=30){const t=this.getConversations(),s=new Date;s.setDate(s.getDate()-e);const i=t.filter(e=>new Date(e.modified||e.created)>s);i.length!==t.length&&(this.setItem(w.CONVERSATIONS,i),console.log(`Cleaned up ${t.length-i.length} old conversations`))}exportData(){return{conversations:this.getConversations(),user:this.getUser(),settings:this.getSettings(),deviceId:this.deviceId,exportedAt:(new Date).toISOString()}}importData(e){try{return e.conversations&&this.setItem(w.CONVERSATIONS,e.conversations),e.user&&this.setItem(w.USER_DATA,e.user),e.settings&&this.setItem(w.SETTINGS,e.settings),!0}catch(t){return console.error("Failed to import data:",t),!1}}getStorageSize(){if(!this.isAvailable)return 0;let e=0;return Object.values(w).forEach(t=>{const s=localStorage.getItem(t);s&&(e+=s.length)}),e}getStorageSizeHuman(){const e=this.getStorageSize();if(0===e)return"0 B";const t=Math.floor(Math.log(e)/Math.log(1024));return parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+["B","KB","MB"][t]}migrateData(e,t){if(console.log(`Migrating storage from version ${e} to ${t}`),"1.0.0"===e&&"1.1.0"===t){const e=this.getConversations().map(e=>c(r({},e),{version:"1.1.0"}));this.setItem(w.CONVERSATIONS,e)}}clearPersonalData(){this.clearUser();const e=this.getConversations().map(e=>c(r({},e),{messages:e.messages.map(e=>c(r({},e),{text:"user"===e.type?"[User message removed]":e.text}))}));this.setItem(w.CONVERSATIONS,e)}hasData(){return this.getConversations().length>0||null!==this.getUser()}getDataSummary(){return{conversationCount:this.getConversations().length,hasUser:null!==this.getUser(),storageSize:this.getStorageSizeHuman(),deviceId:this.deviceId}}}class L{constructor(e={}){this.config=r(r({},d),e),this.isInitialized=!1,this.isOpen=!1,this.currentUser=null,this.api=new A(this.config),this.storage=new N,this.ws=null,this.notifiWs=null,this.chatBubble=null,this.chatWindow=null,this.widgetContainer=null,this.conversations=new Map,this.isChatSessionActive=!1,this.currentChatSession=null,this.unreadCount=0,this.unreadConversations=new Set,this.teamSettings=null,this.init()}init(){return l(this,null,function*(){if(this.isInitialized)console.warn("TicketpingChat already initialized");else try{const e=function(e){const t=[];if(!e)return t.push("Configuration is required"),{isValid:!1,errors:t};if(e.appId?"string"!=typeof e.appId&&t.push("appId must be a string"):t.push("appId is required"),e.teamSlug?"string"!=typeof e.teamSlug&&t.push("teamSlug must be a string"):t.push("teamSlug is required"),void 0!==e.apiBase&&"string"!=typeof e.apiBase&&t.push("apiBase must be a string"),void 0!==e.wsUrl&&"string"!=typeof e.wsUrl&&t.push("wsUrl must be a string"),void 0!==e.userJWT&&"string"!=typeof e.userJWT&&t.push("userJWT must be a string"),void 0!==e.autoStart&&"boolean"!=typeof e.autoStart&&t.push("autoStart must be a boolean"),void 0!==e.position){const s=["bottom-right","bottom-left","top-right","top-left"];"string"==typeof e.position&&s.includes(e.position)||t.push(`position must be one of: ${s.join(", ")}`)}if(void 0!==e.theme&&"object"!=typeof e.theme){const s=["default","dark","light"];"string"!=typeof e.theme||s.includes(e.theme)||t.push(`theme must be one of: ${s.join(", ")}`)}return void 0!==e.maxFileSize&&("number"!=typeof e.maxFileSize?t.push("maxFileSize must be a number"):e.maxFileSize>10485760&&t.push("maxFileSize cannot exceed 10MB")),void 0===e.allowedFileTypes||Array.isArray(e.allowedFileTypes)||t.push("allowedFileTypes must be an array"),{isValid:0===t.length,errors:t}}(this.config);if(!e.isValid)throw new Error(`Invalid configuration: ${e.errors.join(", ")}`);yield this.fetchTeamSettings(),this.createWidgetContainer(),this.applyWidgetPosition(),this.chatBubble=new k(this.widgetContainer,{onClick:()=>this.toggle(),iconColor:this.getIconColor()}),this.shouldShowBubble()||(this.chatBubble.hide(),this.track("widget_bubble_hidden_by_settings")),this.chatWindow=new T(this.widgetContainer,{onClose:()=>this.close(),onTabSwitch:e=>this.handleTabSwitch(e),onSendMessage:e=>this.sendMessage(e),onFileUpload:e=>this.handleFileUpload(e),onConversationSelect:e=>this.loadConversation(e),onBackButtonClick:()=>this.backToList(),teamLogoIcon:this.getTeamLogoIcon(),teamSettings:this.teamSettings}),yield this.loadStoredConversations(),this.initNotificationWebSocket(),this.isInitialized=!0,this.track("widget_initialized",{appId:this.config.appId,version:"1.0.0"})}catch(e){console.error("Failed to initialize TicketpingChat:",e),this.track("widget_init_error",{error:e.message})}})}fetchTeamSettings(){return l(this,null,function*(){var e,t;try{this.teamSettings=yield this.api.getTeamWidgetSettings(),this.track("team_settings_loaded",{teamSlug:null==(e=this.teamSettings)?void 0:e.teamSlug,isAvailable:null==(t=this.teamSettings)?void 0:t.isAvailable})}catch(s){console.warn("Failed to fetch team settings, using defaults:",s),this.teamSettings=null}})}getTeamLogoIcon(){var e;return this.config.teamLogoIcon||(null==(e=this.teamSettings)?void 0:e.logoUrl)||null}shouldShowBubble(){return!this.teamSettings||void 0===this.teamSettings.widgetBubbleVisible||this.teamSettings.widgetBubbleVisible}applyWidgetPosition(){var e;if(!this.widgetContainer)return;const t="left"===((null==(e=this.teamSettings)?void 0:e.widgetPosition)||this.config.position||"bottom-right")?"bottom-left":"bottom-right";this.widgetContainer.classList.remove("position-bottom-left","position-bottom-right"),"bottom-left"===t&&this.widgetContainer.classList.add("position-bottom-left")}backToList(){this.isChatSessionActive=!1,this.currentChatSession=null,this.ws&&this.ws.disconnect(),this.chatWindow.setConversations(Array.from(this.conversations.values()),this.unreadConversations),this.track("back_to_list")}startConversation(){return l(this,null,function*(){const e=yield this.api.createChatSession();this.currentChatSession=e.sessionId,yield this.initWsConversation(e.sessionId),this.isChatSessionActive=!0})}initWsConversation(e){return l(this,null,function*(){try{this.config.userJWT?yield this.initAuthWsConversation(e):yield this.initAnonWsConversation(e)}catch(t){throw console.warn("WebSocket initialization failed:",t),this.track("websocket_init_error",{error:t.message}),t}})}initAnonWsConversation(e){return l(this,null,function*(){return new Promise((t,s)=>{try{let i=`${this.config.wsBase}/ws/chat/${this.config.teamSlug}/`;e&&(i=`${this.config.wsBase}/ws/chat/${this.config.teamSlug}/${e}/`),this.ws=new I(i,null,{onSessionState:e=>{this.handleSessionState(e),t()},onMessage:e=>this.handleWebSocketMessage(e),onFileAttachment:e=>this.handleWebSocketMessage(e),onMessageHistory:e=>this.handleMessageHistory(e),onTyping:e=>this.handleTypingIndicator(e),onStatusChange:e=>this.handleAgentStatus(e),onError:e=>{this.handleWebSocketError(e),s(e)}}),setTimeout(()=>{this.ws&&!this.ws.isWsConnected()&&t()},5e3)}catch(i){console.warn("WebSocket initialization failed:",i),this.track("websocket_init_error",{error:i.message}),s(i)}})})}initAuthWsConversation(e){return l(this,null,function*(){return new Promise((t,s)=>l(this,null,function*(){try{const{chatJWT:i}=yield this.api.getChatToken();let n=`${this.config.wsBase}/ws/chat/${this.config.teamSlug}/?jwt=${i}`;e&&(n=`${this.config.wsBase}/ws/chat/${this.config.teamSlug}/${e}/?jwt=${i}`),this.ws=new I(n,i,{onSessionState:e=>{this.handleSessionState(e),t()},onMessage:e=>this.handleWebSocketMessage(e),onFileAttachment:e=>this.handleWebSocketMessage(e),onMessageHistory:e=>this.handleMessageHistory(e),onTyping:e=>this.handleTypingIndicator(e),onStatusChange:e=>this.handleAgentStatus(e),onError:e=>{this.handleWebSocketError(e),s(e)}}),setTimeout(()=>{this.ws&&!this.ws.isWsConnected()&&t()},5e3)}catch(i){console.warn("WebSocket auth initialization failed:",i),this.track("websocket_auth_init_error",{error:i.message}),s(i)}}))})}initNotificationWebSocket(){this.notifiWs&&this.notifiWs.disconnect();const e=`${this.config.wsBase}/ws/customer-notifs/${this.config.teamSlug}/`;this.notifiWs=new E(e,{onUnreadCount:e=>this.handleUnreadCountUpdate(e),onConnect:()=>{console.log("Notification WebSocket connected"),this.track("notification_ws_connected")},onDisconnect:()=>{console.log("Notification WebSocket disconnected")},onError:e=>{console.warn("Notification WebSocket error:",e)}})}handleUnreadCountUpdate(e){this.unreadCount=e,e>0&&!this.isOpen?this.chatBubble.showNotificationBadge(e):this.chatBubble.hideNotificationBadge(),this.chatWindow.setMessagesTabUnread(e>0),this.refreshConversations(),this.track("unread_count_updated",{count:e})}refreshConversations(){return l(this,null,function*(){try{if(this.config.userJWT){const e=yield this.api.getConversations();e&&e.results&&(this.unreadConversations.clear(),e.results.forEach(e=>{const t=this.conversations.get(e.sessionId),s=(null==t?void 0:t.messages)||e.messages||[];this.conversations.set(e.sessionId,c(r({},e),{messages:s})),e.hasUnread&&this.unreadConversations.add(e.sessionId)}),this.chatWindow.setConversations(Array.from(this.conversations.values()),this.unreadConversations))}}catch(e){console.warn("Failed to refresh conversations:",e)}})}createWidgetContainer(){const e=document.querySelector(".ticketping-widget");e&&e.remove(),this.widgetContainer=h("div",{className:"ticketping-widget","data-version":"1.0.0"}),this.applyCustomTheme(),document.body.appendChild(this.widgetContainer)}applyCustomTheme(){if(!this.config.theme)return;const e=this.config.theme,t=document.documentElement;Object.entries({primaryColor:"--tp-primary-color",primaryButtonText:"--tp-primary-button-text",primaryHover:"--tp-primary-hover",textPrimary:"--tp-text-primary",textSecondary:"--tp-text-secondary",textMuted:"--tp-text-muted",background:"--tp-background",backgroundSecondary:"--tp-background-secondary",backgroundTertiary:"--tp-background-tertiary",border:"--tp-border",borderLight:"--tp-border-light",notificationBg:"--tp-notification-bg",successColor:"--tp-success-color",offlineColor:"--tp-offline-color",errorBg:"--tp-error-bg",errorText:"--tp-error-text",errorBorder:"--tp-error-border",shadowLight:"--tp-shadow-light",shadowMedium:"--tp-shadow-medium",shadowDark:"--tp-shadow-dark",iconColor:"--tp-icon-color"}).forEach(([s,i])=>{e[s]&&t.style.setProperty(i,e[s])})}getIconColor(){return this.config.theme&&"object"==typeof this.config.theme?this.config.theme.iconColor:null}open(){this.isInitialized&&(this.isOpen=!0,this.chatBubble.setOpen(!0),this.chatWindow.show(),this.clearUnreadNotification(),this.track("widget_opened"))}clearUnreadNotification(){this.unreadCount=0,this.chatBubble.hideNotificationBadge()}markConversationAsRead(e){this.unreadConversations.has(e)&&(this.unreadConversations.delete(e),this.chatWindow.setConversations(Array.from(this.conversations.values()),this.unreadConversations),this.ws&&this.ws.isWsConnected()&&this.ws.markRead(e))}close(){this.isInitialized&&(this.ws&&this.ws.disconnect(),this.isOpen=!1,this.chatBubble.setOpen(!1),this.chatWindow.hide(),this.track("widget_closed"))}toggle(){this.isOpen?this.close():this.open()}identify(e){return l(this,null,function*(){if(this.currentUser=e,this.storage.setUser(e),e.userJWT&&"your-actual-jwt-token-here"!==e.userJWT){this.config.userJWT=e.userJWT;try{yield this.loadAuthenticatedUserData(),yield this.reinitializeWebSocketIfNeeded(),this.track("user_identified",{userId:e.id||e.email||"unknown",hasJWT:!!e.userJWT})}catch(t){console.warn("Failed to initialize authenticated user features:",t),this.track("user_identify_error",{error:t.message})}}})}sendMessage(e){return l(this,null,function*(){if(console.log("sendMessage",e),!this.currentChatSession)throw new Error("No conversation started!");const t=r({sessionId:this.currentChatSession,type:"user_message",sender:"USER",messageText:e.text,created:(new Date).toISOString()},e);console.log("message",t),this.addMessageToConversation(this.currentChatSession,t),this.chatWindow.addMessage(t),this.ws&&this.ws.isWsConnected()?this.ws.sendMessage(t):yield this.api.sendMessage(t),this.track("message_sent",{chatSessionId:this.currentChatSession,messageType:t.type,hasAttachment:!!t.file})})}handleFileUpload(e){return l(this,null,function*(){try{if(e.size>this.config.maxFileSize)throw new Error(`File size exceeds ${this.config.maxFileSize/1024/1024}MB limit`);yield this.api.uploadFile(e,this.currentChatSession)}catch(t){console.error("File upload failed:",t),this.chatWindow.showError("Failed to upload file: "+t.message),this.track("file_upload_error",{error:t.message})}})}handleSessionState(e){console.log("handleSessionState",e),this.currentChatSession=e.sessionId,this.conversations.set(e.sessionId,{sessionId:e.sessionId,messages:[],created:e.created}),this.chatWindow.showConversationItem(this.currentChatSession)}handleWebSocketMessage(e){if(this.addMessageToConversation(e.sessionId,e),e.sessionId===this.currentChatSession&&this.chatWindow.addMessage(e),"USER"!==e.sender){this.isOpen&&e.sessionId===this.currentChatSession||(this.unreadConversations.add(e.sessionId),this.chatWindow.setConversations(Array.from(this.conversations.values()),this.unreadConversations))}}handleMessageHistory(e){console.log("handleMessageHistory",e),console.log("this.conversations",this.conversations),this.conversations.set(e.sessionId,{sessionId:e.sessionId,messages:e.messages,created:e.created}),this.chatWindow.setMessages(e.messages)}handleTabSwitch(e){this.track("tab_switched",{tab:e})}loadConversation(e){return l(this,null,function*(){try{if(!e||"new"===e)return this.chatWindow.switchTab("messages"),this.chatWindow.showLoadingState(),yield this.startConversation(),void this.chatWindow.showConversationItem();this.chatWindow.switchTab("messages"),this.chatWindow.showLoadingState(),yield this.initWsConversation(e),this.isChatSessionActive=!0,this.markConversationAsRead(e),this.chatWindow.showConversationItem(),this.track("conversation_loaded",{chatSessionId:e})}catch(t){console.error("Failed to load conversation:",t),this.chatWindow.hideLoadingState(),this.chatWindow.showError("Failed to load conversation")}})}loadStoredConversations(){return l(this,null,function*(){try{if(this.storage.getConversations().forEach(e=>this.conversations.set(e.sessionId,e)),this.config.userJWT){(yield this.api.getConversations()).results.forEach(e=>{this.conversations.set(e.sessionId,e),this.storage.saveConversation(e),e.hasUnread&&this.unreadConversations.add(e.sessionId)})}this.chatWindow.setConversations(Array.from(this.conversations.values()),this.unreadConversations)}catch(e){console.warn("Failed to load conversations:",e)}})}loadAuthenticatedUserData(){return l(this,null,function*(){if(this.config.userJWT)try{const e=yield this.api.getConversations();e&&e.results&&(this.conversations.clear(),this.unreadConversations.clear(),e.results.forEach(e=>{this.conversations.set(e.sessionId,e),this.storage.saveConversation(e),e.hasUnread&&this.unreadConversations.add(e.sessionId)}),this.chatWindow&&this.chatWindow.setConversations(Array.from(this.conversations.values()),this.unreadConversations),console.log(`Loaded ${e.results.length} conversations for authenticated user`))}catch(e){throw console.warn("Failed to load authenticated user data:",e),yield this.loadStoredConversations(),e}})}reinitializeWebSocketIfNeeded(){return l(this,null,function*(){if(this.isChatSessionActive&&this.currentChatSession)try{console.log("Reinitializing WebSocket with authentication..."),this.ws&&(this.ws.disconnect(),this.ws=null),yield this.initWsConversation(this.currentChatSession),console.log("WebSocket reinitialized with authentication successfully"),this.track("websocket_reinitialized",{sessionId:this.currentChatSession,authenticated:!0})}catch(e){console.error("Failed to reinitialize WebSocket:",e),this.track("websocket_reinit_error",{error:e.message,sessionId:this.currentChatSession})}})}addMessageToConversation(e,t){const s=this.conversations.get(e);console.log("addMessageToConversation",s,e,t),s&&(s.messages.push(t),s.modified=new Date,this.storage.saveConversation(s))}track(e,t={}){this.config.analytics&&this.api.track(e,c(r({},t),{timestamp:(new Date).toISOString(),appId:this.config.appId,version:"1.0.0"}))}handleWebSocketError(e){console.warn("WebSocket error:",e),this.track("websocket_error",{error:e.message})}handleAgentStatus(e){this.chatWindow.updateAgentStatus(e)}handleAgentJoined(e){this.chatWindow.showAgentJoined(e.agent)}handleTypingIndicator(e){e.sessionId===this.currentChatSession&&this.chatWindow.showTypingIndicator(e.typing)}destroy(){this.ws&&this.ws.disconnect(),this.notifiWs&&this.notifiWs.disconnect(),this.widgetContainer&&this.widgetContainer.remove(),this.isInitialized=!1,this.isChatSessionActive=!1,this.currentChatSession=null,this.currentUser=null,this.track("widget_destroyed")}}return window.TicketpingChat={instance:null,init(e={}){return this.instance?(console.warn("TicketpingChat already initialized"),this.instance):(this.instance=new L(e),this.instance)},identify(e){if(this.instance)return this.instance.identify(e)},open(){this.instance&&this.instance.open()},close(){this.instance&&this.instance.close()},startConversation(){if(this.instance)return this.instance.startConversation()},destroy(){this.instance&&(this.instance.destroy(),this.instance=null)},version:"1.0.0"},window.ticketpingConfig&&window.TicketpingChat.init(window.ticketpingConfig),L}();
//# sourceMappingURL=widget.min.js.map