UNPKG

@deeprocket/deep-service-desk-widget

Version:

Widget Vue.js para integração com o sistema Deep Service Desk - Controle de visibilidade por URLs - Compatível com Vue 2.7.16 e Vue 3 - Com botão flutuante automático

1,751 lines 62.3 kB
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("vue"));
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else if(typeof exports === 'object')
		exports["deep-service-desk-widget"] = factory(require("vue"));
	else
		root["deep-service-desk-widget"] = factory(root["Vue"]);
})((typeof self !== 'undefined' ? self : this), (__WEBPACK_EXTERNAL_MODULE__274__) => {
return /******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ({

/***/ 262:
/***/ ((__unused_webpack_module, exports) => {

var __webpack_unused_export__;

__webpack_unused_export__ = ({ value: true });
// runtime helper for setting properties on components
// in a tree-shakable way
exports.A = (sfc, props) => {
    const target = sfc.__vccOpts || sfc;
    for (const [key, val] of props) {
        target[key] = val;
    }
    return target;
};


/***/ }),

/***/ 274:
/***/ ((module) => {

module.exports = __WEBPACK_EXTERNAL_MODULE__274__;

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/publicPath */
/******/ 	(() => {
/******/ 		__webpack_require__.p = "";
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);

// EXPORTS
__webpack_require__.d(__webpack_exports__, {
  FloatingTicketWidget: () => (/* reexport */ FloatingTicketWidget),
  TicketWidget: () => (/* reexport */ TicketWidget),
  "default": () => (/* binding */ entry_lib)
});

;// ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js
/* eslint-disable no-var */
// This file is imported into lib/wc client bundles.

if (typeof window !== 'undefined') {
  var currentScript = window.document.currentScript
  if (false) // removed by dead control flow
{ var getCurrentScript; }

  var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/)
  if (src) {
    __webpack_require__.p = src[1] // eslint-disable-line
  }
}

// Indicate to webpack that this file can be concatenated
/* harmony default export */ const setPublicPath = (null);

// EXTERNAL MODULE: external {"commonjs":"vue","commonjs2":"vue","root":"Vue"}
var external_commonjs_vue_commonjs2_vue_root_Vue_ = __webpack_require__(274);
;// ./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/TicketWidget.vue?vue&type=template&id=109adfc9


const _hoisted_1 = { class: "ticket-widget" }
const _hoisted_2 = { class: "popup-header" }
const _hoisted_3 = {
  key: 0,
  class: "uuid-config-section"
}
const _hoisted_4 = { class: "form-group" }
const _hoisted_5 = {
  key: 0,
  class: "error-message"
}
const _hoisted_6 = { class: "form-actions" }
const _hoisted_7 = { class: "form-group" }
const _hoisted_8 = { class: "form-group" }
const _hoisted_9 = {
  key: 0,
  class: "error-message"
}
const _hoisted_10 = { class: "form-actions" }
const _hoisted_11 = ["disabled"]

function render(_ctx, _cache, $props, $setup, $data, $options) {
  return ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", _hoisted_1, [
    ($data.showPopup)
      ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", {
          key: 0,
          class: "popup-overlay",
          onClick: _cache[10] || (_cache[10] = (...args) => ($options.closePopup && $options.closePopup(...args)))
        }, [
          (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", {
            class: "popup-content",
            onClick: _cache[9] || (_cache[9] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withModifiers)(() => {}, ["stop"]))
          }, [
            (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_2, [
              (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
                class: "close-btn",
                onClick: _cache[0] || (_cache[0] = (...args) => ($options.closePopup && $options.closePopup(...args)))
              }, "×")
            ]),
            (!$options.computedClientUuid)
              ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", _hoisted_3, [
                  _cache[12] || (_cache[12] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createStaticVNode)("<div class=\"content-header\"><h3>Precisa de ajuda?</h3><p>Fale com um de nossos especialistas</p></div><div class=\"config-header\"><span class=\"config-icon\">🔧</span><div class=\"config-details\"><div class=\"config-title\">Configuração Necessária</div><div class=\"config-subtitle\">Configure o UUID do cliente para continuar</div></div></div>", 2)),
                  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_4, [
                    _cache[11] || (_cache[11] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("label", { for: "uuidInput" }, "UUID do Cliente *", -1)),
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withDirectives)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("input", {
                      id: "uuidInput",
                      "onUpdate:modelValue": _cache[1] || (_cache[1] = $event => (($data.uuidInput) = $event)),
                      type: "text",
                      placeholder: "Digite o UUID do cliente (ex: 1c9eb621-b56c-43e4-b04b-b1a91b0a1809)",
                      class: "form-input uuid-input",
                      style: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeStyle)($options.inputFocusStyle),
                      onKeypress: _cache[2] || (_cache[2] = (...args) => ($options.handleUuidKeypress && $options.handleUuidKeypress(...args)))
                    }, null, 36), [
                      [external_commonjs_vue_commonjs2_vue_root_Vue_.vModelText, $data.uuidInput]
                    ])
                  ]),
                  ($data.uuidError)
                    ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", _hoisted_5, (0,external_commonjs_vue_commonjs2_vue_root_Vue_.toDisplayString)($data.uuidError), 1))
                    : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true),
                  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_6, [
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
                      type: "button",
                      onClick: _cache[3] || (_cache[3] = (...args) => ($options.closePopup && $options.closePopup(...args))),
                      class: "btn btn-cancel"
                    }, " Cancelar "),
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
                      type: "button",
                      onClick: _cache[4] || (_cache[4] = (...args) => ($options.setClientUuid && $options.setClientUuid(...args))),
                      class: "btn btn-submit",
                      style: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeStyle)($options.submitButtonStyle)
                    }, " ✅ Configurar UUID ", 4)
                  ])
                ]))
              : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true),
            ($options.computedClientUuid)
              ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("form", {
                  key: 1,
                  onSubmit: _cache[8] || (_cache[8] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withModifiers)((...args) => ($options.submitTicket && $options.submitTicket(...args)), ["prevent"])),
                  class: "ticket-form"
                }, [
                  _cache[15] || (_cache[15] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", { class: "content-header" }, [
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("h3", null, "Precisa de ajuda?"),
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("p", null, "Fale com um de nossos especialistas")
                  ], -1)),
                  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_7, [
                    _cache[13] || (_cache[13] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("label", { for: "title" }, "Título *", -1)),
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withDirectives)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("input", {
                      id: "title",
                      "onUpdate:modelValue": _cache[5] || (_cache[5] = $event => (($data.ticket.title) = $event)),
                      type: "text",
                      required: "",
                      placeholder: "Digite o título do ticket",
                      class: "form-input",
                      style: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeStyle)($options.inputFocusStyle)
                    }, null, 4), [
                      [external_commonjs_vue_commonjs2_vue_root_Vue_.vModelText, $data.ticket.title]
                    ])
                  ]),
                  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_8, [
                    _cache[14] || (_cache[14] = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("label", { for: "description" }, "Descrição *", -1)),
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.withDirectives)((0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("textarea", {
                      id: "description",
                      "onUpdate:modelValue": _cache[6] || (_cache[6] = $event => (($data.ticket.description) = $event)),
                      required: "",
                      placeholder: "Descreva o problema ou solicitação",
                      class: "form-textarea",
                      style: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeStyle)($options.inputFocusStyle),
                      rows: "4"
                    }, null, 4), [
                      [external_commonjs_vue_commonjs2_vue_root_Vue_.vModelText, $data.ticket.description]
                    ])
                  ]),
                  ($data.errorMessage)
                    ? ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", _hoisted_9, (0,external_commonjs_vue_commonjs2_vue_root_Vue_.toDisplayString)($data.errorMessage), 1))
                    : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true),
                  (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("div", _hoisted_10, [
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
                      type: "button",
                      onClick: _cache[7] || (_cache[7] = (...args) => ($options.closePopup && $options.closePopup(...args))),
                      class: "btn btn-cancel"
                    }, " Cancelar "),
                    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementVNode)("button", {
                      type: "submit",
                      class: "btn btn-submit",
                      disabled: $data.isSubmitting,
                      style: (0,external_commonjs_vue_commonjs2_vue_root_Vue_.normalizeStyle)($options.submitButtonStyle)
                    }, (0,external_commonjs_vue_commonjs2_vue_root_Vue_.toDisplayString)($data.isSubmitting ? 'Enviando...' : 'Criar Ticket'), 13, _hoisted_11)
                  ])
                ], 32))
              : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true)
          ])
        ]))
      : (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createCommentVNode)("", true)
  ]))
}
;// ./src/components/TicketWidget.vue?vue&type=template&id=109adfc9

;// ./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/TicketWidget.vue?vue&type=script&lang=js

/* harmony default export */ const TicketWidgetvue_type_script_lang_js = ({
  name: 'TicketWidget',
  inject: {
    deepServiceDeskConfig: {
      from: 'deepServiceDeskConfig',
      default: () => ({})
    }
  },
  props: {
    clientUuid: {
      type: String,
      default: null
    },
    brandColor: {
      type: String,
      default: '#3b82f6'
    }
  },
  data() {
    return {
      showPopup: false,
      isSubmitting: false,
      userToken: null,
      userEmail: null,
      client: null,
      errorMessage: '',
      ticket: {
        title: '',
        description: '',
        type: 'support',
        priority: 'medium'
      },
      uuidInput: '',
      uuidError: null,
      configuredClientUuid: null
    }
  },
  computed: {
    // URL da API - sempre fixa
    computedApiUrl() {
      return 'https://servicedesk.deeprocket.com.br/api';
    },
    
    // Cores derivadas do brandColor
    computedBrandColor() {
      return this.brandColor || '#3b82f6';
    },
    
    computedBrandColorHover() {
      // Criar uma versão mais escura da cor para hover
      return this.darkenColor(this.computedBrandColor, 0.1);
    },
    
    computedBrandColorFocus() {
      // Criar uma versão com transparência para o foco
      return this.hexToRgba(this.computedBrandColor, 0.1);
    },
    
    // Estilos dinâmicos para os botões
    submitButtonStyle() {
      return {
        backgroundColor: this.computedBrandColor,
        borderColor: this.computedBrandColor
      };
    },
    
    inputFocusStyle() {
      return {
        '--brand-color': this.computedBrandColor,
        '--brand-color-focus': this.computedBrandColorFocus
      };
    },
    
    // UUID do cliente com prioridade: configurado manualmente > prop > config global > variável de ambiente
    computedClientUuid() {
      let clientUuid = this.configuredClientUuid || this.clientUuid || this.deepServiceDeskConfig.clientUuid;
      
      if (!clientUuid) {
        // Verificar variáveis de ambiente de forma segura
        if (false) // removed by dead control flow
{}
        
        if (!clientUuid && typeof window !== 'undefined') {
          clientUuid = window.DEEP_SERVICE_DESK_CLIENT_UUID;
        }
        
        if (!clientUuid && typeof process !== 'undefined' && ({"NODE_ENV":"production","BASE_URL":"/"})) {
          clientUuid = ({"NODE_ENV":"production","BASE_URL":"/"}).VUE_APP_CLIENT_UUID || ({"NODE_ENV":"production","BASE_URL":"/"}).VITE_CLIENT_UUID;
        }
      }
      
      return clientUuid || null;
    }
  },
  mounted() {
    // Escuta o evento 'new-ticket' para abrir o popup
    window.addEventListener('new-ticket', this.handleNewTicketEvent)
    
    // Tentar carregar UUID de variáveis de ambiente (opcional)
    this.loadClientUuidFromEnv()
  },
  beforeDestroy() {
    window.removeEventListener('new-ticket', this.handleNewTicketEvent)
  },
  methods: {
    // Função para obter token de autenticação do sistema externo
    getAuthTokenFromExternalSystem() {
      try {
        // Busca tokens em ordem de prioridade
        const tokenTc = localStorage.getItem('token-tc');
        if (tokenTc) return tokenTc;
        
        const tokenDeep = localStorage.getItem('token-deep');
        if (tokenDeep) return tokenDeep;
        
        const authToken = localStorage.getItem('authToken');
        if (authToken) return authToken;
        
        return null;
      } catch (error) {
        console.error('Erro ao acessar token:', error);
        return null;
      }
    },

    // Função para obter email do usuário do sistema externo
    getUserEmailFromExternalSystem() {
      try {
        // Busca o usuário do sistema externo (user-tc)
        const userTcToken = localStorage.getItem('user-tc');
        
        if (userTcToken) {
          try {
            const userData = JSON.parse(atob(userTcToken));
            return userData.email || null;
          } catch (decodeError) {
            // Silenciar erro de decodificação
          }
        }
        
        // Fallback para outros sistemas
        const userDeep = localStorage.getItem('user-deep');
        if (userDeep) {
          try {
            const userData = JSON.parse(atob(userDeep));
            return userData.email || null;
          } catch (decodeError) {
            // Silenciar erro de decodificação
          }
        }
        
        return null;
      } catch (error) {
        console.error('Erro ao acessar dados do usuário:', error);
        return null;
      }
    },

    // Função para buscar cliente pelo UUID
    async fetchClientByUuid() {
      if (!this.userToken || !this.computedClientUuid) return null;

      try {
        const response = await fetch(`${this.computedApiUrl}/clients/find-by-uuid?uuid=${encodeURIComponent(this.computedClientUuid)}`, {
          headers: {
            'Authorization': `Bearer ${this.userToken}`,
            'Content-Type': 'application/json'
          }
        });

        if (response.ok) {
          const client = await response.json();
          return client;
        } else if (response.status === 404) {
          return null;
        } else {
          return null;
        }
      } catch (error) {
        console.error('Erro ao buscar cliente por UUID:', error);
        return null;
      }
    },

    // Função para buscar cliente pelo email
    async findClientByEmail(email) {
      if (!email || !this.userToken) return null;

      try {
        const response = await fetch(`${this.computedApiUrl}/clients/find-by-email?email=${encodeURIComponent(email)}`, {
          headers: {
            'Authorization': `Bearer ${this.userToken}`,
            'Content-Type': 'application/json'
          }
        });

        if (response.ok) {
          const client = await response.json();
          return client;
        } else if (response.status === 404) {
          // Cliente não encontrado - isso é normal
          return null;
        } else {
          return null;
        }
      } catch (error) {
        console.error('Erro ao buscar cliente por email:', error);
        return null;
      }
    },

    // Função para buscar clientes
    async fetchClients() {
      if (!this.userToken) return

      try {
        const response = await fetch(`${this.computedApiUrl}/clients`, {
          headers: {
            'Authorization': `Bearer ${this.userToken}`,
            'Content-Type': 'application/json'
          }
        })

        if (response.ok) {
          const data = await response.json()
          this.clients = data.data || data
        }
      } catch (error) {
        console.error('Erro ao buscar clientes:', error)
      }
    },

    // Função para abrir o popup
    async openPopup() {
      // Se UUID não estiver configurado, apenas abre o popup para configuração
      if (!this.computedClientUuid) {
        this.errorMessage = '';
        this.showPopup = true;
        return;
      }
      
      // Se UUID já estiver configurado, inicializa o widget
      await this.initializeWidget();
      
      if (this.client) {
        this.errorMessage = '';
        this.showPopup = true;
      } else {
        this.errorMessage = 'Erro ao configurar widget. Verifique o UUID e autenticação.';
      }
    },

    // Função para fechar o popup
    closePopup() {
      this.showPopup = false
      this.resetForm()
      this.errorMessage = ''
    },

    // Função para resetar o formulário
    resetForm() {
      this.ticket.title = ''
      this.ticket.description = ''
      this.ticket.type = 'support'
      this.ticket.priority = 'medium'
    },

    // Função para submeter o ticket
    async submitTicket() {
      if (!this.userToken) {
        this.errorMessage = 'Token de autenticação não encontrado';
        return;
      }

      if (!this.client) {
        this.errorMessage = 'Cliente não configurado';
        return;
      }

      this.isSubmitting = true;
      this.errorMessage = '';

      try {
        const ticketData = {
          title: this.ticket.title.trim(),
          description: this.ticket.description.trim(),
          type: this.ticket.type,
          priority: this.ticket.priority,
          status: 'open',
          clientId: this.client.id
        };

        // Adicionar informações do usuário se disponível
        if (this.userEmail) {
          ticketData.description += `\n\n--- Informações do Usuário ---\nEmail: ${this.userEmail}`;
        }

        const response = await fetch(`${this.computedApiUrl}/tickets`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${this.userToken}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(ticketData)
        });

        const responseData = await response.json();

        if (response.ok) {
          // Sucesso - emite evento com dados do ticket criado
          this.$emit('ticket-created', {
            ...responseData,
            success: true,
            message: 'Ticket criado com sucesso!'
          });
          
          // Fecha o popup e reseta o form
          this.closePopup();
        } else {
          // Erro da API
          const errorMsg = responseData.error || 'Erro ao criar ticket';
          this.errorMessage = errorMsg;
          this.$emit('ticket-error', { 
            message: errorMsg,
            details: responseData
          });
        }
        
      } catch (error) {
        console.error('Erro ao criar ticket:', error);
        const errorMsg = 'Erro de conexão. Verifique sua internet e tente novamente.';
        this.errorMessage = errorMsg;
        this.$emit('ticket-error', { 
          message: errorMsg,
          details: error.message
        });
      } finally {
        this.isSubmitting = false;
      }
    },

    // Handler para o evento customizado
    handleNewTicketEvent() {
      this.openPopup()
    },

    // Método público para verificar se está aberto (para uso via ref)
    isOpen() {
      return this.showPopup
    },

    // Método para carregar o UUID do cliente de variáveis de ambiente
    loadClientUuidFromEnv() {
      // Tentar carregar de diferentes fontes de variáveis de ambiente
      let envUuid = null;
      
      // Verificar se estamos em ambiente de desenvolvimento com Vite
      if (false) // removed by dead control flow
{}
      
      // Verificar variável global do window
      if (!envUuid && typeof window !== 'undefined') {
        envUuid = window.DEEP_SERVICE_DESK_CLIENT_UUID;
      }
      
      // Verificar se process está disponível (apenas em desenvolvimento)
      if (!envUuid && typeof process !== 'undefined' && ({"NODE_ENV":"production","BASE_URL":"/"})) {
        envUuid = ({"NODE_ENV":"production","BASE_URL":"/"}).VUE_APP_CLIENT_UUID || ({"NODE_ENV":"production","BASE_URL":"/"}).VITE_CLIENT_UUID;
      }
      
      if (!envUuid) {
        return;
      }
      
      // Validação básica de UUID
      const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
      if (!uuidRegex.test(envUuid)) {
        console.error('❌ UUID do cliente inválido:', envUuid);
        return;
      }
      
      this.configuredClientUuid = envUuid;
      
      // Inicializar widget automaticamente se UUID for carregado de variável de ambiente
      this.initializeWidget();
    },

    handleUuidKeypress(event) {
      if (event.key === 'Enter') {
        this.setClientUuid();
      }
    },

    setClientUuid() {
      const uuid = this.uuidInput.trim();
      
      if (!uuid) {
        this.uuidError = 'Por favor, digite um UUID';
        return;
      }
      
      // Validação básica de UUID
      const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
      if (!uuidRegex.test(uuid)) {
        this.uuidError = 'UUID inválido. Formato esperado: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
        return;
      }
      
      this.configuredClientUuid = uuid;
      this.uuidInput = '';
      this.uuidError = null;
      
      // Buscar cliente automaticamente após configurar UUID
      this.initializeWidget();
    },

    async initializeWidget() {
      // Busca token de autenticação
      this.userToken = this.getAuthTokenFromExternalSystem();
      
      if (!this.userToken) {
        this.uuidError = 'Token de autenticação não encontrado. Faça login no sistema.';
        this.configuredClientUuid = null;
        return;
      }
      
      // Busca email do usuário
      this.userEmail = this.getUserEmailFromExternalSystem();
      
      // Busca cliente pelo UUID
      this.client = await this.fetchClientByUuid();
      
      if (!this.client) {
        this.uuidError = 'Cliente não encontrado. Verifique se o UUID está correto.';
        this.configuredClientUuid = null;
        return;
      }
    },

    resetUuid() {
      this.configuredClientUuid = null;
      this.client = null;
      this.userToken = null;
      this.userEmail = null;
      this.uuidInput = '';
      this.uuidError = null;
      this.errorMessage = '';
    },
    
    // Métodos para manipulação de cores
    hexToRgba(hex, alpha = 1) {
      const r = parseInt(hex.slice(1, 3), 16);
      const g = parseInt(hex.slice(3, 5), 16);
      const b = parseInt(hex.slice(5, 7), 16);
      return `rgba(${r}, ${g}, ${b}, ${alpha})`;
    },
    
    darkenColor(hex, amount) {
      const num = parseInt(hex.replace('#', ''), 16);
      const amt = Math.round(2.55 * amount * 100);
      const R = (num >> 16) - amt;
      const G = (num >> 8 & 0x00FF) - amt;
      const B = (num & 0x0000FF) - amt;
      return '#' + (0x1000000 + (R < 0 ? 0 : R) * 0x10000 + (G < 0 ? 0 : G) * 0x100 + (B < 0 ? 0 : B)).toString(16).slice(1);
    }
  }
});

;// ./src/components/TicketWidget.vue?vue&type=script&lang=js
 
;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-52.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-52.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-52.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/TicketWidget.vue?vue&type=style&index=0&id=109adfc9&lang=css
// extracted by mini-css-extract-plugin

;// ./src/components/TicketWidget.vue?vue&type=style&index=0&id=109adfc9&lang=css

// EXTERNAL MODULE: ./node_modules/vue-loader/dist/exportHelper.js
var exportHelper = __webpack_require__(262);
;// ./src/components/TicketWidget.vue




;


const __exports__ = /*#__PURE__*/(0,exportHelper/* default */.A)(TicketWidgetvue_type_script_lang_js, [['render',render]])

/* harmony default export */ const TicketWidget = (__exports__);
;// ./node_modules/vue-loader/dist/templateLoader.js??ruleSet[1].rules[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/FloatingTicketWidget.vue?vue&type=template&id=f38110dc


const FloatingTicketWidgetvue_type_template_id_f38110dc_hoisted_1 = { class: "floating-ticket-widget" }

function FloatingTicketWidgetvue_type_template_id_f38110dc_render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_TicketWidget = (0,external_commonjs_vue_commonjs2_vue_root_Vue_.resolveComponent)("TicketWidget")

  return ((0,external_commonjs_vue_commonjs2_vue_root_Vue_.openBlock)(), (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createElementBlock)("div", FloatingTicketWidgetvue_type_template_id_f38110dc_hoisted_1, [
    (0,external_commonjs_vue_commonjs2_vue_root_Vue_.createVNode)(_component_TicketWidget, {
      ref: "ticketWidget",
      "brand-color": $props.brandColor,
      onTicketCreated: $options.onTicketCreated,
      onTicketError: $options.onTicketError
    }, null, 8, ["brand-color", "onTicketCreated", "onTicketError"])
  ]))
}
;// ./src/components/FloatingTicketWidget.vue?vue&type=template&id=f38110dc

;// ./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/FloatingTicketWidget.vue?vue&type=script&lang=js



/* harmony default export */ const FloatingTicketWidgetvue_type_script_lang_js = ({
  name: 'FloatingTicketWidget',
  components: {
    TicketWidget: TicketWidget
  },
  props: {
    brandColor: {
      type: String,
      default: '#3b82f6'
    }
  },
  inject: {
    deepServiceDeskConfig: {
      from: 'deepServiceDeskConfig',
      default: () => ({})
    }
  },
  mounted() {
    // Escutar evento global para abrir o widget
    window.addEventListener('new-ticket', this.openWidget)
  },
  beforeDestroy() {
    window.removeEventListener('new-ticket', this.openWidget)
  },
  methods: {
    openWidget() {
      if (this.$refs.ticketWidget) {
        this.$refs.ticketWidget.openPopup()
      }
    },
    onTicketCreated(data) {
      // Emitir evento global para que a aplicação possa escutar
      window.dispatchEvent(new CustomEvent('ticket-created', { detail: data }))
      
      // Mostrar notificação de sucesso
      this.showNotification('Ticket criado com sucesso!', 'success')
    },
    onTicketError(error) {
      // Emitir evento global para que a aplicação possa escutar
      window.dispatchEvent(new CustomEvent('ticket-error', { detail: error }))
      
      // Mostrar notificação de erro
      this.showNotification(error.message || 'Erro ao criar ticket', 'error')
    },
    showNotification(message, type = 'info') {
      // Criar notificação toast simples
      const notification = document.createElement('div')
      notification.className = `deep-service-desk-notification ${type}`
      notification.textContent = message
      
      notification.style.cssText = `
        position: fixed;
        top: 20px;
        right: 20px;
        background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
        color: white;
        padding: 12px 20px;
        border-radius: 8px;
        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
        z-index: 10000;
        font-size: 14px;
        font-weight: 500;
        max-width: 300px;
        word-wrap: break-word;
        animation: slideInRight 0.3s ease;
      `
      
      // Adicionar animação CSS
      if (!document.getElementById('deep-service-desk-notification-styles')) {
        const style = document.createElement('style')
        style.id = 'deep-service-desk-notification-styles'
        style.textContent = `
          @keyframes slideInRight {
            from {
              transform: translateX(100%);
              opacity: 0;
            }
            to {
              transform: translateX(0);
              opacity: 1;
            }
          }
          @keyframes slideOutRight {
            from {
              transform: translateX(0);
              opacity: 1;
            }
            to {
              transform: translateX(100%);
              opacity: 0;
            }
          }
        `
        document.head.appendChild(style)
      }
      
      document.body.appendChild(notification)
      
      // Remover após 5 segundos
      setTimeout(() => {
        notification.style.animation = 'slideOutRight 0.3s ease'
        setTimeout(() => {
          if (notification.parentNode) {
            notification.parentNode.removeChild(notification)
          }
        }, 300)
      }, 5000)
    }
  }
});

;// ./src/components/FloatingTicketWidget.vue?vue&type=script&lang=js
 
;// ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-52.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-52.use[1]!./node_modules/vue-loader/dist/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-52.use[2]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/FloatingTicketWidget.vue?vue&type=style&index=0&id=f38110dc&lang=css
// extracted by mini-css-extract-plugin

;// ./src/components/FloatingTicketWidget.vue?vue&type=style&index=0&id=f38110dc&lang=css

;// ./src/components/FloatingTicketWidget.vue




;


const FloatingTicketWidget_exports_ = /*#__PURE__*/(0,exportHelper/* default */.A)(FloatingTicketWidgetvue_type_script_lang_js, [['render',FloatingTicketWidgetvue_type_template_id_f38110dc_render]])

/* harmony default export */ const FloatingTicketWidget = (FloatingTicketWidget_exports_);
;// ./src/index.js



// Variável global para armazenar a configuração
let globalConfig = null

// Variável para controlar se o monitoramento já foi configurado
let urlMonitoringConfigured = false

// Função global para forçar verificação de visibilidade (pode ser chamada externamente)
window.deepServiceDeskUpdateVisibility = function() {
  if (globalConfig) {
    updateButtonVisibility(globalConfig)
  
  }
}

// Função para detectar a versão do Vue
function getVueVersion() {
  if (typeof window !== 'undefined' && window.Vue) {
    return window.Vue.version || '2'
  }
  // Em ambiente de build, tentar detectar pela estrutura
  return '3' // Padrão para Vue 3
}

// Função para verificar se a URL atual deve ocultar o botão
function shouldHideButtonOnCurrentUrl(hiddenUrls) {
  if (!hiddenUrls || !Array.isArray(hiddenUrls) || hiddenUrls.length === 0) {
    return false
  }

  const currentUrl = window.location.href
  const currentPath = window.location.pathname

  return hiddenUrls.some(urlPattern => {
    // Se é uma string simples, verificar se é substring da URL ou path
    if (typeof urlPattern === 'string') {
      return currentUrl.includes(urlPattern) || currentPath.includes(urlPattern)
    }
    
    // Se é uma expressão regular
    if (urlPattern instanceof RegExp) {
      return urlPattern.test(currentUrl) || urlPattern.test(currentPath)
    }
    
    return false
  })
}

// Função para criar o botão flutuante
function createFloatingButton(config) {
  // Verificar se o botão já existe
  if (document.getElementById('deep-service-desk-floating-btn')) {
    // Se o botão já existe, apenas atualizar a visibilidade
    updateButtonVisibility(config)
    return
  }

  // SEMPRE criar o botão, mas definir visibilidade inicial baseada na URL
  const shouldHideInitially = shouldHideButtonOnCurrentUrl(config.hiddenUrls)

  // Criar o botão flutuante
  const button = document.createElement('button')
  button.id = 'deep-service-desk-floating-btn'
  button.innerHTML = `
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path d="M20 2H4C2.9 2 2 2.9 2 4V22L6 18H20C21.1 18 22 17.1 22 16V4C22 2.9 21.1 2 20 2ZM20 16H5.17L4 17.17V4H20V16Z" fill="currentColor"/>
      <path d="M7 9H17V11H7V9ZM7 12H17V14H7V12ZM7 6H17V8H7V6Z" fill="currentColor"/>
    </svg>
  `
  
  // Estilos do botão (incluindo visibilidade inicial)
  const brandColor = config.brandColor || '#3b82f6'
  button.style.cssText = `
    position: fixed;
    bottom: 20px;
    right: 20px;
    width: 60px;
    height: 60px;
    background: ${brandColor};
    border: none;
    border-radius: 50%;
    color: white;
    cursor: pointer;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    z-index: 9998;
    display: ${shouldHideInitially ? 'none' : 'flex'};
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease;
    font-size: 0;
  `

  // Efeitos hover
  button.addEventListener('mouseenter', () => {
    button.style.transform = 'scale(1.1)'
    button.style.boxShadow = '0 6px 25px rgba(0, 0, 0, 0.2)'
  })

  button.addEventListener('mouseleave', () => {
    button.style.transform = 'scale(1)'
    button.style.boxShadow = '0 4px 20px rgba(0, 0, 0, 0.15)'
  })

  // Evento de clique
  button.addEventListener('click', () => {
    window.dispatchEvent(new CustomEvent('new-ticket'))
  })

  // Adicionar tooltip
  button.title = 'Abrir Suporte'

  // Inserir no DOM
  document.body.appendChild(button)

  // Adicionar estilos responsivos
  const style = document.createElement('style')
  style.textContent = `
    @media (max-width: 768px) {
      #deep-service-desk-floating-btn {
        bottom: 15px !important;
        right: 15px !important;
        width: 50px !important;
        height: 50px !important;
      }
    }
  `
  document.head.appendChild(style)

  // SEMPRE configurar monitoramento de URL (não apenas quando há hiddenUrls)
  setupUrlMonitoring(config, button)
}

// Função para atualizar visibilidade do botão
function updateButtonVisibility(config) {
  const button = document.getElementById('deep-service-desk-floating-btn')
  if (button) {
    // SEMPRE verificar - se não há hiddenUrls, o botão deve ser visível
    const shouldHide = shouldHideButtonOnCurrentUrl(config.hiddenUrls)
    button.style.display = shouldHide ? 'none' : 'flex'
    
    // Debug apenas em localhost
    if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
      console.log('[Deep Service Desk] updateButtonVisibility:')
      console.log('  URL atual:', window.location.href)
      console.log('  hiddenUrls:', config.hiddenUrls)
      console.log('  shouldHide:', shouldHide)
      console.log('  display:', button.style.display)
    }
  }
}

// Função separada para configurar monitoramento de URL
function setupUrlMonitoring(config, button) {
  // Se não há URLs ocultas, não precisa monitorar
  if (!config.hiddenUrls || config.hiddenUrls.length === 0) {
    return
  }

  // Se monitoramento já foi configurado, não configurar novamente
  if (urlMonitoringConfigured) {
    return
  }
  
  urlMonitoringConfigured = true
    let lastUrl = window.location.href
    
    const checkUrlAndToggleButton = () => {
      const currentUrl = window.location.href
      
      // Só verificar se a URL realmente mudou
      if (currentUrl !== lastUrl) {
        lastUrl = currentUrl
      }
      
      // Usar a função unificada para atualizar visibilidade
      updateButtonVisibility(config)
    }

    // Múltiplas estratégias para detectar mudanças de URL

    // 1. Interceptar pushState e replaceState
    const originalPushState = history.pushState
    const originalReplaceState = history.replaceState

    history.pushState = function() {
      originalPushState.apply(history, arguments)
      setTimeout(checkUrlAndToggleButton, 50)
      setTimeout(checkUrlAndToggleButton, 200) // Fallback adicional
    }

    history.replaceState = function() {
      originalReplaceState.apply(history, arguments)
      setTimeout(checkUrlAndToggleButton, 50)
      setTimeout(checkUrlAndToggleButton, 200) // Fallback adicional
    }

    // 2. Escutar eventos de navegação
    window.addEventListener('popstate', () => {
      setTimeout(checkUrlAndToggleButton, 50)
    })
    
    window.addEventListener('hashchange', () => {
      setTimeout(checkUrlAndToggleButton, 50)
    })
    
    // 3. Observer para mudanças no DOM (pode indicar mudança de página)
    if (typeof MutationObserver !== 'undefined') {
      const observer = new MutationObserver(() => {
        // Verificar se a URL mudou
        if (window.location.href !== lastUrl) {
          setTimeout(checkUrlAndToggleButton, 100)
        }
      })
      
      observer.observe(document.body, {
        subtree: true,
        childList: true
      })
    }
    
    // 4. Verificação periódica como fallback (a cada 2 segundos)
    setInterval(() => {
      if (window.location.href !== lastUrl) {
        checkUrlAndToggleButton()
      }
    }, 2000)
    
    // 5. Escutar eventos customizados que podem indicar navegação
    window.addEventListener('beforeunload', checkUrlAndToggleButton)
    window.addEventListener('load', () => {
      setTimeout(checkUrlAndToggleButton, 100)
    })
    
    // 6. Detectar frameworks populares e escutar eventos específicos
    // Vue Router
    if (window.Vue || document.querySelector('[data-v-]')) {
      // Escutar eventos do Vue Router
      window.addEventListener('vue-router-navigation', () => {
        setTimeout(checkUrlAndToggleButton, 50)
      })
    }
    
    // React Router
    if (window.React || document.querySelector('[data-reactroot]')) {
      // Escutar mudanças no React
      const checkReactNavigation = () => {
        setTimeout(checkUrlAndToggleButton, 50)
      }
      window.addEventListener('react-router-navigation', checkReactNavigation)
    }
    
    // 7. Interceptar fetch e XMLHttpRequest para detectar possíveis navegações AJAX
    const originalFetch = window.fetch
    if (originalFetch) {
      window.fetch = function() {
        const result = originalFetch.apply(this, arguments)
        result.then(() => {
          // Verificar após requests AJAX (pode indicar mudança de página)
          setTimeout(() => {
            if (window.location.href !== lastUrl) {
              checkUrlAndToggleButton()
            }
          }, 300)
        }).catch(() => {
          // Mesmo em caso de erro, verificar
          setTimeout(() => {
            if (window.location.href !== lastUrl) {
              checkUrlAndToggleButton()
            }
          }, 300)
        })
        return result
      }
    }
    
    // Verificação inicial
    setTimeout(checkUrlAndToggleButton, 100)
}

// Função para remover o botão flutuante
function removeFloatingButton() {
  const button = document.getElementById('deep-service-desk-floating-btn')
  if (button) {
    button.remove()
  }
}

// Variável global para armazenar a instância do Vue
let globalVueInstance = null

// Função para criar a instância global do widget
function createGlobalWidget(config, isVue3, vueApp) {
  // Verificar se já existe
  if (document.getElementById('deep-service-desk-global-widget')) {
    return
  }

  // Criar container para o widget
  const container = document.createElement('div')
  container.id = 'deep-service-desk-global-widget'
  document.body.appendChild(container)

  // SEMPRE usar o widget independente com formulário completo
  // Isso garante que o formulário sempre funcione, independente do Vue
  createIndependentWidget(config)
}

// Função para criar um widget independente (sem Vue)
function createIndependentWidget(config) {
  // Garantir que temos acesso à configuração global
  const finalConfig = config || globalConfig
  
  if (!finalConfig || !finalConfig.clientUuid) {
    console.error('❌ ERRO CRÍTICO: Configuração não possui clientUuid!')
    console.error('❌ Config recebida:', config)
    console.error('❌ Global config:', globalConfig)
    return
  }
  
  const container = document.getElementById('deep-service-desk-global-widget')
  if (!container) return
  
  // Criar HTML do widget com formulário completo
  container.innerHTML = `
    <div id="independent-ticket-widget" style="display: none;">
      <!-- Overlay do modal -->
      <div class="widget-overlay" style="
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
      ">
        <div class="widget-modal" style="
          background: white;
          border-radius: 8px;
          width: 90%;
          max-width: 500px;
          max-height: 90vh;
          overflow-y: auto;
          box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
        ">
          <!-- Header simplificado -->
          <div class="widget-header" style="
            display: flex;
            justify-content: flex-end;
            align-items: center;
            padding: 15px 20px;
            border-bottom: 1px solid #e5e7eb;
            background-color: #f9fafb;
            border-radius: 8px 8px 0 0;
          ">
            <button class="widget-close" style="
              background: none;
              border: none;
              font-size: 24px;
              cursor: pointer;
              color: #6b7280;
              padding: 0;
              width: 30px;
              height: 30px;
              display: flex;
              align-items: center;
              justify-content: center;
              border-radius: 4px;
              transition: background-color 0.2s;
            ">&times;</button>
          </div>
          
          <!-- Formulário de Ticket -->
          <div class="widget-form" style="padding: 24px;">
            <!-- Título e subtítulo dentro do conteúdo -->
            <div style="text-align: center; margin-bottom: 24px;">
              <h3 style="margin: 0 0 8px 0; color: #1f2937; font-size: 20px; font-weight: 600;">Precisa de ajuda?</h3>
              <p style="margin: 0; color: #6b7280; font-size: 14px;">Fale com um de nossos especialistas</p>
            </div>
            
            <form id="ticket-form">
              <!-- Título -->
              <div style="margin-bottom: 16px;">
                <label style="display: block; margin-bottom: 6px; font-weight: 500; color: #374151; font-size: 14px;">
                  Título *
                </label>
                <input 
                  type="text" 
                  id="ticket-title" 
                  required
                  style="
                    width: 100%;
                    padding: 10px 12px;
                    border: 1px solid #d1d5db;
                    border-radius: 6px;
                    font-size: 14px;
                    box-sizing: border-box;
                    transition: border-color 0.2s, box-shadow 0.2s;
                  "
                  placeholder="Resumo do problema ou solicitação"
                />
              </div>
              
              <!-- Descrição -->
              <div style="margin-bottom: 20px;">
                <label style="display: block; margin-bottom: 6px; font-weight: 500; color: #374151; font-size: 14px;">
                  Descrição *
                </label>
                <textarea 
                  id="ticket-description" 
                  required
                  rows="6"
                  style="
                    width: 100%;
                    padding: 10px 12px;
                    border: 1px solid #d1d5db;
                    border-radius: 6px;
                    font-size: 14px;
                    box-sizing: border-box;
                    resize: vertical;
                    min-height: 120px;
                    transition: border-color 0.2s, box-shadow 0.2s;
                  "
                  placeholder="Descreva detalhadamente o problema ou solicitação..."
                ></textarea>
              </div>
              
              <!-- Loading indicator -->
              <div id="form-loading" style="display: none; text-align: center; margin: 16px 0;">
                <div style="
                  display: inline-block;
                  width: 20px;
                  height: 20px;
                  border: 2px solid #e5e7eb;
                  border-top: 2px solid #3b82f6;
                  border-radius: 50%;
                  animation: spin 1s linear infinite;
                "></div>
                <span style="margin-left: 8px; color: #6b7280; font-size: 14px;">Enviando...</span>
              </div>
              
              <!-- Botões -->
              <div style="
                display: flex;
                gap: 12px;
                justify-content: flex-end;
                margin-top: 20px;
              ">
                <button 
                  type="button" 
                  class="widget-close" 
                  style="
                    padding: 10px 20px;
                    border: 1px solid #d1d5db;
                    background-color: white;
                    color: #374151;
                    border-radius: 6px;
                    cursor: pointer;
                    font-size: 14px;
                    font-weight: 500;
                  "
                >
                  Cancelar
                </button>
                <button 
                  type="submit" 
                  id="submit-ticket"
                  style="
                    padding: 10px 20px;
                    border: none;
                    background-color: ${finalConfig.brandColor || '#3b82f6'};
                    color: white;
                    border-radius: 6px;
                    cursor: pointer;
                    font-size: 14px;
                    font-weight: 500;
                  "
                >
                  Enviar Ticket
                </button>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
    
    <!-- CSS para animação de loading e estilos dinâmicos -->
    <style>
      @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
      
      /* Hover effect no botão close */
      .widget-close:hover {
        background-color: #f3f4f6 !important;
      }
      
      /* Focus states com brand color */
      #ticket-title:focus, #ticket-description:focus {
        outline: none !important;
        border-color: ${finalConfig.brandColor || '#3b82f6'} !important;
        box-shadow: 0 0 0 3px ${finalConfig.brandColor || '#3b82f6'}20 !important;
      }
    </style>
  `
  
  // Adicionar event listeners
  const widget = container.querySelector('#independent-ticket-widget')
  const overlay = container.querySelector('.widget-overlay')
  const closeButtons = container.querySelectorAll('.widget-close')
  const form = container.querySelector('#ticket-form')
  const loadingDiv = container.querySelector('#form-loading')
  const submitButton = container.querySelector('#submit-ticket')
  
  // Função para fechar o widget
  const closeWidget = () => {
    widget.style.display = 'none'
    // Limpar formulário
    form.reset()
    loadingDiv.style.display = 'none'
    submitButton.disabled = false
  }
  
  // Event listeners para fechar
  closeButtons.forEach(btn => {
    btn.addEventListener('click', closeWidget)
  })
  
  overlay.addEventListener('click', (e) => {
    if (e.target === overlay) closeWidget()
  })
  
  // Event listener para envio do formulário
  form.addEventListener('submit', async (e) => {
    e.preventDefault()
    
    // Mostrar loading
    loadingDiv.style.display = 'block'
    submitButton.disabled = true
    
    // Garantir que temos a configuração mais atualizada
    const currentConfig = finalConfig || globalConfig
    
    if (!currentConfig || !currentConfig.clientUuid) {
      console.error('❌ ERRO: Não foi possível obter clientUuid!')
      console.error('❌ finalConfig:', finalConfig)
      console.error('❌ globalConfig:', globalConfig)
      
      showNotification('Erro: Configuração inválida. UUID do cliente não encontrado.', 'error')
      loadingDiv.style.display = 'none'
      submitButton.disabled = false
      return
    }
    
    // Coletar dados do formulário
    const formData = {
      title: document.getElementById('ticket-title').value,
      description: document.getElementById('ticket-description').value,
      type: 'suporte',
      status: 'pendente', 
      priority: 'media',
      clientUuid: currentConfig.clientUuid
    }
    
    try {
      // Fazer requisição para a API - sempre usar URL fixa
      const response = await fetch('https://servicedesk.deeprocket.com.br/api/tickets/external', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(formData)
      })
      
      // Verificar se a resposta é JSON válida
      const contentType = response.headers.get('content-type')
      
      if (!contentType || !contentType.includes('application/json')) {
        const textResponse = await response.text()
        console.error('❌ Resposta não é JSON:', textResponse)
        throw new Error(`Resposta inválida do servidor: ${textResponse}`)
      }
      
      if (response.ok) {
        const result = await response.json()
        
        // Mostrar notificação de sucesso
        showNotification('Ticket criado com sucesso! Você receberá uma resposta em breve.', 'success')
        
        // Fechar widget
        closeWidget()
        
        // Disparar evento global
        window.dispatchEvent(new CustomEvent('ticket-created', { detail: result }))
        
      } else {
        const errorText = await response.text()
        console.error('❌ Erro na resposta:', errorText)
        
        // Tentar fazer parse do JSON de erro
        let errorData
        try {
          errorData = JSON.parse(errorText)
        } catch (e) {
          errorData = { error: errorText }
        }
        
        throw new Error(`Erro ${response.status}: ${response.statusText} - ${errorData.error || errorText}`)
      }
      
    } catch (error) {
      console.error('❌ Erro ao criar ticket:', error)
      console.error('❌ Stack trace:', error.stack)
      console.error('❌ Dados que causaram erro:', formData)
      console.error('❌ Config usada:', currentConfig)
      
      // Mostrar notificação de erro
      showNotification(`Erro ao enviar ticket: ${error.message}`, 'error')
      
      // Disparar evento de erro
      window.dispatchEvent(new CustomEvent('ticket-error', { detail: error }))
      
    } finally {
      // Esconder loading
      loadingDiv.style.display = 'none'
      submitButton.disabled = false
    }
  })
  
  // Listener para o evento new-ticket
  window.addEventListener('new-ticket', () => {
    // Sempre mostrar o formulário completo
    widget.style.display = 'block'
    
    // Focar no primeiro campo
    setTimeout(() => {
      document.getElementById('ticket-title').focus()
    }, 100)
  })
}

// Função para mostrar notificações
function showNotification(message, type = 'info') {
  // Criar notificação toast
  const notification = document.createElement('div')
  notification.className = `deep-service-desk-notification ${type}`
  notification.textContent = message
  
  notification.style.cssText = `
    position: fixed;
    top: 20px;
    right: 20px;
    background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
    color: white;
    padding: 12px 20px;
    border-radius: 8px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    z-index: 10000;
    font-size: 14px;
    font-weight: 500;
    max-width: 300px;
    word-wrap: break-word;
    animation: slideInRight 0.3s ease;
  `
  
  // Adicionar animação CSS se não existir
  if (!document.getElementById('deep-service-desk-notification-styles')) {
    const style = document.createElement('style')
    style.id = 'deep-service-desk-notification-styles'
    style.textContent = `
      @keyframes slideInRight {
        from {
          transform: translateX(100%);
          opacity: 0;
        }
        to {
          transform: translateX(0);
          opacity: 1;
        }
      }
      @keyframes slideOutRight {
        from {
          transform: translateX(0);
          opacity: 1;
        }
        to {
          transform: translateX(100%);
          opacity: 0;
        }
      }
    `
    document.head.appendChild(style)
  }
  
  document.body.appendChild(notification)
  
  // Remover após 5 segundos
  setTimeout(() => {
    notification.style.animation = 'slideOutRight 0.3s ease'
    setTimeout(() => {
      if (notification.parentNode) {
        notification.parentNode.removeChild(notification)
      }
    }, 300)
  }, 5000)
}

// Plugin de configuração global compatível com Vue 2 e Vue 3
const DeepServiceDeskPlugin = {
  install(app, options = {}) {
    // Configurações globais - CORREÇÃO: garantir que clientUuid não seja null
    const config = {
      clientUuid: options.clientUuid || null,
      brandColor: options.brandColor || '#3b82f6',
      showFloatingButton: options.showFloatingButton !== false, // true por padrão
      hiddenUrls: options.hiddenUrls || [], // URLs onde o botão não deve aparecer
      ...options
    }

    // VALIDAÇÃO CRÍTICA: verificar se clientUuid foi fornecido
    if (!config.clientUuid) {
      console.error('❌ ERRO CRÍTICO: clientUuid é obrigatório!')
      console.error('❌ Configuração recebida:', options)
      console.error('❌ Configuração processada:', config)
      throw new Error('Deep Service Desk Widget: clientUuid é obrigatório na configuração')
    }

    // Salvar configuração globalmente
    globalConfig = config

    // Detectar versão do Vue
    const isVue3 = app.version && app.version.startsWith('3')
    
    if (isVue3) {
      // Vue 3
      app.config.globalProperties.$deepServiceDesk = config
      app.provide('deepServiceDeskConfig', config)
      app.component('TicketWidget', TicketWidget)
      app.component('DeepServiceDeskWidget', TicketWidget)
      app.component('FloatingTicketWidget', FloatingTicketWidget)
    } else {
      // Vue 2.7.16
      app.prototype.$deepServiceDesk = config
      
      // Para Vue 2, usar um mixin global para disponibilizar a configuração
      app.mixin({
        data() {
          return {
            deepServiceDeskConfig: config
          }
        },
        provide() {
          return {
            deepServiceDeskConfig: config
          }
        }
      })
      
      app.component('TicketWidget', TicketWidget)
      app.component('DeepServiceDeskWidget', TicketWidget)
      app.component('FloatingTicketWidget', FloatingTicketWidget)
    }

    // Criar o widget global sempre (independentemente do botão flutuante)
    const initializeWidget = () => {
      // Criar botão flutuante apenas se showFloatingButton for true
      if (config.showFloatingButton) {
        createFloatingButton(config)
      }
      
      // SEMPRE criar instância global do widget (necessário para openTicket funcionar)
      setTimeout(() => {
        createGlobalWidget(config, isVue3, app)
      }, 100)
    }

    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', initializeWidget)
    } else {
      initializeWidget()
    }

    // Adicionar métodos globais para controlar o botão
    const methods = {
      showFloatingButton() {
        // SEMPRE criar o botão (a função já verifica se existe)
        createFloatingButton(config)
      },
      hideFloatingButton() {
        removeFloatingButton()
      },
      openTicket() {
        window.dispatchEvent(new CustomEvent('new-ticket'))
      },
      updateUrlVisibility() {
        // Método para verificar manualmente a visibilidade baseada na URL
        updateButtonVisibility(config)
      }
    }

    if (isVue3) {
      app.config.globalProperties.$deepServiceDeskButton = methods
    } else {
      app.prototype.$deepServiceDeskButton = methods
    }
  }
}

// Exportar plugin e componentes
/* harmony default export */ const src_0 = (DeepServiceDeskPlugin);


// Auto-instalação se usado via script tag
if (typeof window !== 'undefined' && window.Vue) {
  const vueVersion = getVueVersion()
  if (vueVersion.startsWith('2')) {
    window.Vue.use(DeepServiceDeskPlugin)
  }
} 
;// ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js


/* harmony default export */ const entry_lib = (src_0);


/******/ 	return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=deep-service-desk-widget.umd.js.map