UNPKG

@helping-desk/web-sdk

Version:

Web SDK for Helping Desk - Ticket creation and support widget integration

1 lines 12.6 kB
!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.HelpingDeskSDK=n():e.HelpingDeskSDK=n()}(this,()=>(()=>{"use strict";var e={};class n{constructor(e,n){this.container=null,this.bubble=null,this.widget=null,this.isOpen=!1,this.stylesInjected=!1,this.config={position:e.position||"bottom-right",primaryColor:e.primaryColor||"#667eea",bubbleIcon:e.bubbleIcon||"💬"},this.onCreateTicket=n}init(){this.container||(this.injectStyles(),this.createWidget(),this.attachEventListeners())}injectStyles(){if(this.stylesInjected)return;const e="helping-desk-widget-styles";if(document.getElementById(e))return void(this.stylesInjected=!0);const n=document.createElement("style");n.id=e,n.textContent=this.getStyles(),document.head.appendChild(n),this.stylesInjected=!0}getStyles(){const e=this.config.primaryColor||"#667eea";return`\n .helping-desk-widget-container {\n position: fixed;\n z-index: 9999;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n }\n \n .helping-desk-widget-container.bottom-right {\n bottom: 20px;\n right: 20px;\n }\n \n .helping-desk-widget-container.bottom-left {\n bottom: 20px;\n left: 20px;\n }\n \n .helping-desk-widget-container.top-right {\n top: 20px;\n right: 20px;\n }\n \n .helping-desk-widget-container.top-left {\n top: 20px;\n left: 20px;\n }\n \n .helping-desk-bubble {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: ${e};\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n transition: transform 0.2s, box-shadow 0.2s;\n position: relative;\n }\n \n .helping-desk-bubble:hover {\n transform: scale(1.1);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);\n }\n \n .helping-desk-widget {\n position: absolute;\n bottom: 80px;\n right: 0;\n width: 380px;\n max-width: calc(100vw - 40px);\n height: 600px;\n max-height: calc(100vh - 100px);\n background: white;\n border-radius: 16px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);\n display: none;\n flex-direction: column;\n overflow: hidden;\n animation: slideUp 0.3s ease-out;\n }\n \n .helping-desk-widget-container.bottom-left .helping-desk-widget {\n right: auto;\n left: 0;\n }\n \n .helping-desk-widget-container.top-right .helping-desk-widget {\n bottom: auto;\n top: 80px;\n }\n \n .helping-desk-widget-container.top-left .helping-desk-widget {\n bottom: auto;\n top: 80px;\n right: auto;\n left: 0;\n }\n \n .helping-desk-widget.open {\n display: flex;\n }\n \n @keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n \n .helping-desk-widget-header {\n background: ${e};\n color: white;\n padding: 20px;\n border-radius: 16px 16px 0 0;\n }\n \n .helping-desk-widget-title {\n font-size: 18px;\n font-weight: 600;\n margin: 0;\n }\n \n .helping-desk-widget-subtitle {\n font-size: 12px;\n opacity: 0.9;\n margin: 4px 0 0 0;\n }\n \n .helping-desk-widget-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n }\n \n .helping-desk-ticket-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n \n .helping-desk-form-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n \n .helping-desk-form-label {\n font-size: 14px;\n font-weight: 500;\n color: #333;\n }\n \n .helping-desk-form-input,\n .helping-desk-form-textarea,\n .helping-desk-form-select {\n padding: 10px;\n border: 2px solid #e0e0e0;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n transition: border-color 0.2s;\n }\n \n .helping-desk-form-input:focus,\n .helping-desk-form-textarea:focus,\n .helping-desk-form-select:focus {\n outline: none;\n border-color: ${e};\n }\n \n .helping-desk-form-textarea {\n resize: vertical;\n min-height: 120px;\n }\n \n .helping-desk-form-button {\n padding: 12px;\n background: ${e};\n color: white;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.2s, transform 0.2s;\n }\n \n .helping-desk-form-button:hover:not(:disabled) {\n background: ${e}dd;\n transform: translateY(-1px);\n }\n \n .helping-desk-form-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n \n .helping-desk-message {\n padding: 12px;\n border-radius: 8px;\n margin-bottom: 12px;\n font-size: 14px;\n }\n \n .helping-desk-message.success {\n background: #d4edda;\n color: #155724;\n border: 1px solid #c3e6cb;\n }\n \n .helping-desk-message.error {\n background: #f8d7da;\n color: #721c24;\n border: 1px solid #f5c6cb;\n }\n \n @media (max-width: 480px) {\n .helping-desk-widget {\n width: calc(100vw - 20px);\n height: calc(100vh - 100px);\n border-radius: 16px 16px 0 0;\n bottom: 0;\n right: 10px;\n }\n \n .helping-desk-widget-container.bottom-left .helping-desk-widget {\n left: 10px;\n }\n }\n `}createWidget(){this.container=document.createElement("div"),this.container.className=`helping-desk-widget-container ${this.config.position||"bottom-right"}`,this.bubble=document.createElement("div"),this.bubble.className="helping-desk-bubble",this.bubble.textContent=this.config.bubbleIcon||"💬",this.bubble.setAttribute("aria-label","Open support widget"),this.widget=document.createElement("div"),this.widget.className="helping-desk-widget",this.widget.innerHTML=this.getWidgetHTML(),this.container.appendChild(this.bubble),this.container.appendChild(this.widget),document.body.appendChild(this.container)}getWidgetHTML(){return`\n <div class="helping-desk-widget-header">\n <h3 class="helping-desk-widget-title">Need Help?</h3>\n <p class="helping-desk-widget-subtitle">We're here to assist you</p>\n </div>\n <div class="helping-desk-widget-content">\n ${this.getTicketFormHTML()}\n </div>\n `}getTicketFormHTML(){return'\n <form class="helping-desk-ticket-form" id="helping-desk-ticket-form">\n <div class="helping-desk-form-group">\n <label class="helping-desk-form-label">Title *</label>\n <input \n type="text" \n class="helping-desk-form-input" \n name="title" \n placeholder="Brief description of your issue" \n required\n />\n </div>\n <div class="helping-desk-form-group">\n <label class="helping-desk-form-label">Description *</label>\n <textarea \n class="helping-desk-form-textarea" \n name="description" \n placeholder="Please provide detailed information about your issue..." \n required\n ></textarea>\n </div>\n <div class="helping-desk-form-group">\n <label class="helping-desk-form-label">Priority</label>\n <select class="helping-desk-form-select" name="priority">\n <option value="low">Low</option>\n <option value="medium" selected>Medium</option>\n <option value="high">High</option>\n <option value="urgent">Urgent</option>\n </select>\n </div>\n <div class="helping-desk-form-group">\n <label class="helping-desk-form-label">Category</label>\n <select class="helping-desk-form-select" name="category">\n <option value="general" selected>General</option>\n <option value="technical">Technical</option>\n <option value="billing">Billing</option>\n <option value="feature_request">Feature Request</option>\n <option value="bug_report">Bug Report</option>\n </select>\n </div>\n <button type="submit" class="helping-desk-form-button" id="helping-desk-submit-btn">\n Submit Ticket\n </button>\n </form>\n '}attachEventListeners(){this.bubble&&this.bubble.addEventListener("click",()=>this.toggleWidget());const e=this.widget?.querySelector("#helping-desk-ticket-form");e?.addEventListener("submit",n=>{n.preventDefault(),this.handleFormSubmit(e)})}toggleWidget(){this.isOpen?this.closeWidget():this.openWidget()}openWidget(){this.widget&&(this.widget.classList.add("open"),this.isOpen=!0)}closeWidget(){this.widget&&(this.widget.classList.remove("open"),this.isOpen=!1)}async handleFormSubmit(e){const n=e.querySelector("#helping-desk-submit-btn"),t=new FormData(e),i=t.get("title"),o=t.get("description"),s=t.get("priority"),r=t.get("category");n.disabled=!0,n.textContent="Submitting...",e.querySelectorAll(".helping-desk-message").forEach(e=>e.remove());try{const n=await this.onCreateTicket({title:i,description:o,priority:s,category:r}),t=document.createElement("div");t.className="helping-desk-message success",t.textContent=`✅ Ticket created successfully! Ticket ID: ${n.id}`,e.insertBefore(t,e.firstChild),e.reset(),setTimeout(()=>{this.closeWidget(),t.remove()},3e3)}catch(n){const t=document.createElement("div");t.className="helping-desk-message error",t.textContent=`❌ Error: ${n.message||"Failed to create ticket"}`,e.insertBefore(t,e.firstChild)}finally{n.disabled=!1,n.textContent="Submit Ticket"}}destroy(){this.container&&(this.container.remove(),this.container=null,this.bubble=null,this.widget=null)}}class t{constructor(e){if(this.widget=null,!e.tenantId)throw new Error("Tenant ID is required. Please provide your tenantId from your .env file.");const n=e.apiUrl||"undefined"!=typeof process&&process.env?.HELPING_DESK_API_URL||"undefined"!=typeof window&&window.HELPING_DESK_API_URL;if(!n)throw new Error("API URL is required. Please set HELPING_DESK_API_URL in your environment variables or provide apiUrl in the config.");this.config={showWidget:!1!==e.showWidget,widgetPosition:e.widgetPosition||"bottom-right",widgetColor:e.widgetColor||"#667eea",widgetIcon:e.widgetIcon||"💬",...e,apiUrl:n},this.config.showWidget&&"undefined"!=typeof window&&this.initWidget()}initWidget(){this.widget||(this.widget=new n({position:this.config.widgetPosition,primaryColor:this.config.widgetColor,bubbleIcon:this.config.widgetIcon},async e=>await this.createTicket({title:e.title,description:e.description,priority:e.priority,category:e.category})),this.widget.init())}async createTicket(e){try{const n="/api/tickets/sdk/create/",t="X-Tenant-ID",i=await fetch(`${this.config.apiUrl}${n}`,{method:"POST",headers:{"Content-Type":"application/json",[t]:this.config.tenantId},body:JSON.stringify({title:e.title,description:e.description,priority:e.priority||"medium",category:e.category||"",tags:e.tags||[]})});if(!i.ok){const e=await i.json().catch(()=>({detail:"Unknown error"}));throw{message:e.detail||e.message||"Failed to create ticket",status:i.status,details:e}}return await i.json()}catch(e){if(e&&"object"==typeof e&&"message"in e)throw e;throw{message:e instanceof Error?e.message:"Failed to create ticket",details:e}}}updateConfig(e){this.config={...this.config,...e}}getConfig(){return{...this.config}}showWidget(){this.widget||"undefined"==typeof window||this.initWidget()}hideWidget(){this.widget&&(this.widget.destroy(),this.widget=null)}}return"undefined"!=typeof window&&(window.HelpingDeskSDK=t,window.createHelpingDeskSDK=function(e){return new t(e)}),e.default})());