Soluções de Suporte Técnico para Empresas Inteligentes

Conecte-se com eficiência e segurança. Nossos serviços garantem que sua TI esteja sempre em boas mãos.
Bem-vindo à iQuest

Transforme a maneira como você lida com a tecnologia

A tecnologia deve ser uma aliada estratégica, impulsionando o crescimento do seu negócio. Na iQuest, oferecemos soluções que garantem eficiência contínua e segurança, permitindo que sua equipe se concentre em resultados enquanto cuidamos da infraestrutura técnica.
de Experiência
0 anos
Com uma trajetória de inovação e excelência, a iQuest transforma o suporte técnico em uma experiência descomplicada. Atendemos empresas que buscam otimizar operações, reduzir custos e eliminar preocupações com tecnologia. Nossa equipe especializada está pronta para responder rapidamente, desde a manutenção preventiva até a resolução de incidentes complexos.
Visão:

Ser referência em suporte técnico, antecipando necessidades e impulsionando a competitividade dos clientes.

Missão:

Oferecer suporte contínuo e proativo, garantindo que operações funcionem sem interrupções, com soluções preventivas e atendimento acessível.

Suporte Especializado e Rápido

Nossos serviços de suporte técnico

Na iQuest, entendemos que cada empresa tem necessidades únicas. Por isso, oferecemos um portfólio completo de serviços que mantém sua TI sempre eficiente.

Monitoramento 24/7

Acompanhe o desempenho dos sistemas em tempo real e previna problemas antes que impactem suas operações.

Gestão de Backup e Recuperação

Proteção de dados críticos e planos de recuperação para minimizar impactos.

Serviços Personalizados

Consultoria adaptada às necessidades específicas do seu negócio.

Como Funciona

Nosso processo é projetado para fornecer suporte eficiente e sem complicações, garantindo que sua empresa tenha tudo o que precisa para uma TI funcional.

Diagnóstico Rápido e Preciso

Identificação de problemas e avaliação de necessidades com agilidade.

Monitoramento Proativo

Acompanhamento contínuo para prevenir falhas.

Soluções Sob Medida

Ajuste de serviços conforme as especificidades de cada negócio.

Melhorias Contínuas

Atualizações e otimizações constantes para garantir eficiência.

A parceira ideal para empresas que buscam eficiência em TI.

vantagens de escolher a iquest

Por que escolher a iQuest?

Na iQuest, focamos em garantir segurança, eficiência e tranquilidade para nossos clientes, independentemente do tamanho do negócio.

Equipe Especializada

Profissionais experientes e atualizados, nas principais ferramentas de mercado.

Suporte 24/7

Suporte eficaz e humanizado.

Inovação e Atualização Constante

Investimento em tecnologia de ponta para otimizar sistemas.

Escolha a iQuest e leve sua tecnologia para o próximo nível com um suporte técnico que vai além das expectativas.

Depoimentos

O que nossos clientes dizem

A satisfação dos nossos clientes é o que nos motiva a continuar oferecendo suporte técnico de excelência. Veja o que alguns deles têm a dizer.

// Widget de Chat CHANNEL (function() { // Cria o elemento do widget const widgetHTML = `

WEBChat

`; // Adiciona o widget ao documento document.body.insertAdjacentHTML('beforeend', widgetHTML); // Inicializa o widget const chatButton = document.getElementById('channel-chat-button'); const chatContainer = document.getElementById('channel-chat-container'); const chatClose = document.getElementById('channel-chat-close'); const chatClear = document.getElementById('channel-chat-clear'); const messagesDiv = document.getElementById('channel-chat-messages'); const messageInput = document.getElementById('channel-chat-input'); const sendButton = document.getElementById('channel-chat-send'); const sessionSpan = document.getElementById('channel-chat-session'); const widgetDiv = document.getElementById('channel-chat-widget'); const fileInput = document.getElementById('channel-chat-file'); const attachButton = document.getElementById('channel-chat-attach'); // Variáveis globais para sessão e token let webchatId = null; let token = null; let ws = null; let chatLoaded = false; const tenantId = '28'; // Para ativar logs do widget no console: window.WEBCHAT_DEBUG = true antes do load const LOGGER_ENABLED = (typeof window !== 'undefined' && window.WEBCHAT_DEBUG === true); // Funções de controle do widget chatButton.addEventListener('click', async () => { chatContainer.classList.add('show'); if (!chatLoaded) { await loadMessageHistory(); connectWebSocket(); chatLoaded = true; } }); chatClose.addEventListener('click', () => { chatContainer.classList.remove('show'); }); // Função para gerar ID único de sessão function generateUniqueId() { const timestamp = Date.now().toString(36); const random = Math.random().toString(36).substring(2, 8); return `${timestamp}-${random}`; } function generateSessionId() { if (!sessionStorage.getItem('channelWebchatId')) { sessionStorage.setItem('channelWebchatId', generateUniqueId()); } return sessionStorage.getItem('channelWebchatId'); } // Função para registrar o usuário no backend async function registerWebchat() { webchatId = generateSessionId(); const name = 'WebChat ' + webchatId; const email = 'webchat@webchat.com'; const tenantId = '28'; const wabaId = 'a708cef4-0a43-4b09-b89b-e6f48398d759'; const websocketToken = '09e2902e-63fc-4780-84e7-a774f84b732d'; const response = await fetch(`https://api06.omniquestgo.com.br/webchat/register/${wabaId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-websocket-token': websocketToken }, body: JSON.stringify({ webchatId, name, email, tenantId }) }); const data = await response.json(); token = data.token; return { webchatId, token }; } // Renova o JWT per-sessão se faltar < 5min para expirar async function ensureFreshToken() { if (!token) { await registerWebchat(); return; } try { const parts = token.split('.'); if (parts.length < 2) { await registerWebchat(); return; } const payload = JSON.parse(atob(parts[1])); const expMs = (payload.exp || 0) * 1000; if (expMs - Date.now() < 5 * 60 * 1000) { await registerWebchat(); } } catch (e) { await registerWebchat(); } } // Exibe o ID da sessão async function showSessionId() { const { webchatId } = await registerWebchat(); sessionSpan.textContent = `Sessão: ${webchatId}`; } showSessionId(); // Função para formatar hora function formatTime(dateString) { const date = new Date(dateString); return date.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }); } // Função para formatar texto estilo WhatsApp function formatWhatsapp(text) { let formatted = String(text || ''); formatted = formatted.replace(/\*(.*?)\*/g, '$1'); formatted = formatted.replace(/NEW LINE/gi, '
'); formatted = formatted.replace(/\\n/g, '
'); formatted = formatted.replace(/\n/g, '
'); return formatted; } function escapeHtml(text) { return String(text || '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function parseMenuMessage(text) { const raw = String(text || '').trim(); if (!raw.startsWith('#MENU')) return null; const normalized = raw .replace(//gi, '\n') .replace(/NEW LINE/gi, '\n') .replace(/\\n/g, '\n'); const lines = normalized.split('\n').map(l => l.trim()).filter(Boolean); if (!lines.length) return null; const title = lines[0].replace(/^#MENU\s*/i, '').trim() || 'Escolha uma opcao'; const items = lines.slice(1).map(l => l.replace(/^\d+\.\s*/, '').trim()).filter(Boolean); if (!items.length) return null; return { title, items }; } function buildMenuHtml(menu) { const buttonsHtml = menu.items.map(item => { const safe = escapeHtml(item); return ``; }).join(''); return `
${escapeHtml(menu.title)}
${buttonsHtml}
`; } // Função para construir URL completa da mídia function buildMediaUrl(mediaUrl) { if (!mediaUrl) return null; if (mediaUrl.startsWith('http://') || mediaUrl.startsWith('https://')) { return mediaUrl; } const baseUrl = `https://api06.omniquestgo.com.br/public/${tenantId}`; return `${baseUrl}/${mediaUrl}`; } // Função para adicionar mensagem function appendMessage(text, type, time = '', ack = null, id = null, mediaType = null, mediaUrl = null) { const messageDiv = document.createElement('div'); if (id) messageDiv.id = 'msg-' + id; messageDiv.className = `channel-message ${type}`; let ackHtml = ''; if (type === 'channel-sent' && ack !== null && ack !== undefined) { ackHtml = `${getAckIcon(ack)}`; } let contentHtml = ''; let caption = ''; if (text && text.startsWith('caption: ')) { caption = text.substring(9); text = ''; } if (mediaType === 'location') { const mapsUrl = (text && /^https?:\/\//i.test(text)) ? text : ''; contentHtml = ` 📍 Localização${mapsUrl ? '
Abrir no mapa' : ''}
`; } else if (mediaType === 'vcard') { const fnMatch = String(text || '').match(/FN:([^\n]+)/); const telMatch = String(text || '').match(/TEL[^:]*:([^\n]+)/); const fn = fnMatch ? fnMatch[1].trim() : 'Contato'; const tel = telMatch ? telMatch[1].trim() : ''; contentHtml = `
👤 ${fn}${tel ? '
' + tel + '' : ''}
`; } else if (mediaType && mediaUrl) { const fullMediaUrl = buildMediaUrl(mediaUrl); switch (mediaType.toLowerCase()) { case 'image': contentHtml = `
Imagem ${caption ? `
${formatWhatsapp(caption)}
` : ''}
`; break; case 'video': contentHtml = `
${caption ? `
${formatWhatsapp(caption)}
` : ''}
`; break; case 'audio': contentHtml = `
${caption ? `
${formatWhatsapp(caption)}
` : ''}
`; break; case 'document': contentHtml = ` 📄${caption || 'Documento'} `; break; default: contentHtml = `${formatWhatsapp(text)}`; } } else { const menuData = parseMenuMessage(text); if (menuData) { contentHtml = buildMenuHtml(menuData); } else { contentHtml = `${formatWhatsapp(text)}`; } } messageDiv.innerHTML = `${contentHtml}
${time} ${ackHtml}`; messagesDiv.appendChild(messageDiv); messageDiv.querySelectorAll('[data-menu-send]').forEach(btn => { btn.addEventListener('click', () => { messageInput.value = btn.getAttribute('data-menu-send'); sendButton.click(); }); }); messagesDiv.scrollTop = messagesDiv.scrollHeight; } // Função para atualizar o ack de uma mensagem function updateMessageAck(messageId, ack) { const msgDiv = document.getElementById('msg-' + messageId); if (msgDiv) { const ackSpan = msgDiv.querySelector('.channel-ack'); if (ackSpan) { ackSpan.innerHTML = getAckIcon(ack); } } } // Função para obter ícone do ack function getAckIcon(ack) { if (ack === 0) return '🕓'; if (ack === 1) return '✔️'; if (ack === 2) return '✔️'; if (ack === 3) return '✔️✔️'; if (ack === -1) return '❌'; return ''; } // Função para renderizar o histórico completo function renderHistory(messages) { messagesDiv.innerHTML = ''; messages.forEach(msg => { appendMessage( msg.body, msg.fromMe ? 'channel-received' : 'channel-sent', formatTime(msg.createdAt), msg.ack, msg.id, msg.mediaType, msg.mediaUrl ); }); } // Função para carregar histórico de mensagens async function loadMessageHistory() { try { await ensureFreshToken(); const wabaId = 'a708cef4-0a43-4b09-b89b-e6f48398d759'; const response = await fetch(`https://api06.omniquestgo.com.br/webchat/messages/${wabaId}?from=${webchatId}&tenantId=28`, { headers: { 'Authorization': 'Bearer ' + token } }); const data = await response.json(); if (Array.isArray(data)) { renderHistory(data); } else { LOGGER_ENABLED && console.warn('[WebChat] Resposta da API não é um array:', data); } } catch (error) { LOGGER_ENABLED && console.error('[WebChat] Erro ao carregar histórico:', error); } } // Função para gerar um ID temporário para mensagens enviadas function generateTempId() { return 'temp-' + Math.random().toString(36).substr(2, 9); } // Função para atualizar o ID de uma mensagem no DOM function updateMessageId(tempId, realId) { const tempDiv = document.getElementById('msg-' + tempId); if (tempDiv) { tempDiv.id = 'msg-' + realId; } } // Função para sanitizar o nome do arquivo function sanitizeFileName(filename) { if (!filename) return ''; return filename .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .replace(/[^a-zA-Z0-9.\-_]/g, '_') .replace(/_+/g, '_') .replace(/^_+|_+$/g, ''); } // Classifica o file.type em image/video/audio/document (PDF, doc, etc. caem em document) function classifyMediaType(file) { const t = (file && file.type ? String(file.type) : '').toLowerCase(); if (t.indexOf('image/') === 0) return 'image'; if (t.indexOf('video/') === 0) return 'video'; if (t.indexOf('audio/') === 0) return 'audio'; return 'document'; } // Função para enviar mídia async function sendMedia(file) { const sanitizedFileName = sanitizeFileName(file.name); const formData = new FormData(); formData.append('medias', file, sanitizedFileName); const data = { body: 'caption: ' + (messageInput.value.trim() || 'Mídia enviada'), from: webchatId, name: webchatId, email: webchatId + '@webchat.com', tenantId: '28', event: 'messages.upsert', fromMe: false, channel: 'webchat', type: 'webchat', webchatId: webchatId, mediaType: classifyMediaType(file), fileName: sanitizedFileName }; formData.append('data', JSON.stringify(data)); try { await ensureFreshToken(); const wabaId = 'a708cef4-0a43-4b09-b89b-e6f48398d759'; const response = await fetch(`https://api06.omniquestgo.com.br/webchat-webhook/${wabaId}`, { method: 'POST', headers: { 'Authorization': 'Bearer ' + token }, body: formData }); const responseText = await response.text(); let respData = {}; if (responseText) { try { respData = JSON.parse(responseText); } catch (parseError) { LOGGER_ENABLED && console.error('[WebChat] Erro ao fazer parse da resposta:', parseError); throw new Error('Resposta inválida do servidor'); } } if (!response.ok) { throw new Error(respData.message || 'Erro ao enviar mídia'); } messageInput.value = ''; const tempId = generateTempId(); appendMessage( data.body, 'channel-sent', formatTime(new Date().toISOString()), 0, tempId, data.mediaType, null ); await loadMessageHistory(); } catch (error) { LOGGER_ENABLED && console.error('[WebChat] Erro detalhado ao enviar mídia:', { mensagem: error.message, stack: error.stack, erro: error }); alert('Erro ao enviar mídia. Por favor, tente novamente.'); } } // Event listeners para envio de mensagem sendButton.addEventListener('click', async () => { const message = messageInput.value.trim(); if (message) { const tempId = generateTempId(); appendMessage(message, 'channel-sent', formatTime(new Date().toISOString()), 0, tempId); messageInput.value = ''; const data = { body: message, from: webchatId, name: webchatId, email: webchatId + '@webchat.com', tenantId: '28', event: 'messages.upsert', fromMe: false, channel: 'webchat', type: 'webchat', webchatId: webchatId }; try { await ensureFreshToken(); const wabaId = 'a708cef4-0a43-4b09-b89b-e6f48398d759'; const response = await fetch(`https://api06.omniquestgo.com.br/webchat-webhook/${wabaId}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }, body: JSON.stringify(data) }); const respData = await response.json(); if (respData && respData.id) { updateMessageId(tempId, respData.id); } if (respData && respData.mediaUrl) { appendMessage( respData.body, 'channel-sent', formatTime(new Date().toISOString()), 0, respData.id || tempId, respData.mediaType, respData.mediaUrl ); } await loadMessageHistory(); } catch (error) { LOGGER_ENABLED && console.error('[WebChat] Erro ao enviar mensagem:', error); } } }); messageInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') { sendButton.click(); } }); // Event listener para o botão de anexo attachButton.addEventListener('click', () => { fileInput.click(); }); // Event listener para seleção de arquivo fileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { sendMedia(file); } fileInput.value = ''; }); // WebSocket para receber mensagens e ack em tempo real function connectWebSocket() { if (!webchatId || !token) return; let pingInterval; let historyInterval; let reconnectAttempts = 0; const MAX_RECONNECT_ATTEMPTS = 5; const RECONNECT_DELAY = 5000; const PING_INTERVAL = 30000; const HISTORY_INTERVAL = 60000; function connect() { ws = new WebSocket(`wss://api06.omniquestgo.com.br/wss?from=${webchatId}&token=${token}`); ws.onopen = () => { LOGGER_ENABLED && console.log('[WebChat] WebSocket conectado!'); reconnectAttempts = 0; pingInterval = setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'ping' })); } }, PING_INTERVAL); historyInterval = setInterval(async () => { if (ws.readyState === WebSocket.OPEN) { await loadMessageHistory(); } }, HISTORY_INTERVAL); }; ws.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.type === 'webhook' && data.payload && data.payload.message) { const msg = data.payload.message; appendMessage( msg.body, 'channel-received', formatTime(msg.createdAt), msg.ack, msg.id, msg.mediaType, msg.mediaUrl ); if (msg.mediaType) { loadMessageHistory(); } } if (data.type === 'ack_update' && data.payload) { if (data.payload.mediaType) { const msgDiv = document.getElementById('msg-' + data.payload.id); if (msgDiv) { msgDiv.remove(); appendMessage( data.payload.body, 'channel-sent', formatTime(data.payload.createdAt), data.payload.ack, data.payload.id, data.payload.mediaType, data.payload.mediaUrl ); } } else { updateMessageAck(data.payload.messageId, data.payload.ack); } } if (data.type === 'pong') { LOGGER_ENABLED && console.log('[WebChat] Pong recebido'); } } catch (error) { LOGGER_ENABLED && console.error('[WebChat] Erro ao processar mensagem WebSocket:', error); } }; ws.onerror = (error) => { LOGGER_ENABLED && console.error('[WebChat] Erro na conexão WebSocket:', error); }; ws.onclose = () => { LOGGER_ENABLED && console.log('[WebChat] Conexão WebSocket fechada'); clearInterval(pingInterval); clearInterval(historyInterval); if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) { reconnectAttempts++; LOGGER_ENABLED && console.log(`[WebChat] Tentando reconectar (tentativa ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})...`); setTimeout(connect, RECONNECT_DELAY); } else { LOGGER_ENABLED && console.error('[WebChat] Número máximo de tentativas de reconexão atingido'); } }; } connect(); } // Função para limpar a sessão async function clearSession() { if (confirm('Tem certeza que deseja limpar a sessão e começar uma nova conversa?')) { messagesDiv.innerHTML = ''; sessionStorage.removeItem('channelWebchatId'); if (ws) { ws.close(); } webchatId = null; token = null; chatLoaded = false; await showSessionId(); await loadMessageHistory(); connectWebSocket(); } } chatClear.addEventListener('click', clearSession); })();