const listView = document.getElementById('list-view'); const observationView = document.getElementById('obs-view'); const encaminharView = document.getElementById('encaminhar-view'); // Novos elementos do layout redesenhado const queueTableBody = document.getElementById('queue-table-body'); const queueEmpty = document.getElementById('queue-empty'); const queueCount = document.getElementById('queue-count'); const currentCard = document.getElementById('current-card'); const noCurrentCard = document.getElementById('no-current'); const cardTicket = document.getElementById('card-ticket'); const cardStatusBadge = document.getElementById('card-status-badge'); const cardClientName = document.getElementById('card-client-name'); const cardService = document.getElementById('card-service'); const cardType = document.getElementById('card-type'); const nextButton = document.getElementById('next-button'); const recallButton = document.getElementById('recall-button'); const logoutButton = document.getElementById('logout-button'); const observationText = document.getElementById('observation-text'); const saveButton = document.getElementById('save-button'); const selectedItemNameSpan = document.getElementById('selected-item-name'); const idAtend = document.getElementById('idAtend'); const counterStart = document.getElementById('counter-start'); let currentData = []; let selectedItemId = null; let selectedItemName = ''; // =========================== // FLAG que trava o ID do atendimento chamado. // Quando o call-next retorna e define o atendimento atual, // este flag impede que atualizações da fila sobrescrevam o selectedItemId. // =========================== let calledAtendimentoData = null; // Guarda os dados completos do atendimento chamado window.electronAPI.onLoadData((data) => { // Se já estiver em atendimento, ignora atualizações da lista para evitar flickering no botão if (localStorage.getItem('atendimentoAtual')) { return; } if (!data) { return; } populateQueueTable(data); }); async function initializeSocket() { if (typeof window.electronAPI === 'undefined' || !window.electronAPI.getPusherConfig) { console.error('electronAPI not available or getPusherConfig method missing.'); return; } const config = await window.electronAPI.getPusherConfig(); let host = config.host; const tenantId = localStorage.getItem('tenantId'); const token = localStorage.getItem('authToken'); //! checa se ja tem o colabId e o tenantId if (tenantId && token) { // Conexão Socket.io adaptada do Pusher const socket = io(host, { auth: { token }, extraHeaders: { 'x-tenant-id': tenantId } }); socket.on('connect', () => { console.log('Socket.io conectado ao host: ', host); }); // Evento que substitui o bind do Pusher socket.on('queueUpdate', (data) => { console.log('Notificação de fila recebida:', data); // Avisa o processo principal que houve mudança. // O main vai buscar a lista completa e atualizar todas as janelas. window.electronAPI.updateQueue(); }); socket.on('error', (err) => { console.error('Socket.io connection error: ', err); }); } else { console.warn('User not authenticated or tenantId not available. WebSocket not connected.'); } } initializeSocket(); //chama o proximo da fila ao abrir a janela de atendimentos window.electronAPI.selectAtendID((data) => { nextButton.disabled = true; if (!data) { showNoCurrentCard('Ninguém aguardando atendimento'); return; } // Trava os dados do atendimento chamado para que atualizações da fila // NÃO sobrescrevam quem foi chamado. calledAtendimentoData = data; selectedItemId = data._id ?? null; selectedItemName = data.clientName ?? ''; // Atualiza a tabela da fila (sem afetar o card atual) // populateQueueTable já NÃO mexe no selectedItemId quando calledAtendimentoData está travado showListView(); // Mostra o card do atendimento chamado showCurrentCard(data); }); window.electronAPI.showObservation(() => { window.electronAPI.iniciaAtendimento(selectedItemId); showObservationView(); // Muda para a tela de observação }); // Função para popular a tabela da fila function populateQueueTable(proximos) { const atendimentoEmAndamentoId = localStorage.getItem('atendimentoAtual'); const atendimentoEmAndamentoNome = localStorage.getItem('atendimentoAtualNome'); if (atendimentoEmAndamentoId) { // Em atendimento: mostra card de atendimento no painel direito queueTableBody.innerHTML = ''; queueCount.textContent = '0'; queueEmpty.style.display = 'flex'; document.querySelector('.queue-table').style.display = 'none'; // Mostra card como "Atendendo" currentCard.style.display = 'flex'; noCurrentCard.style.display = 'none'; cardTicket.textContent = ''; cardStatusBadge.textContent = 'Atendendo'; cardStatusBadge.className = 'card-badge badge-atendendo'; cardClientName.textContent = (atendimentoEmAndamentoNome || '').toUpperCase(); cardService.textContent = ''; cardType.textContent = ''; nextButton.disabled = true; recallButton.disabled = true; return; } // Se não vier dados por parâmetro, tenta pegar do localStorage (fallback) if (!Array.isArray(proximos)) { let datastorage = localStorage.getItem('proximos'); proximos = JSON.parse(datastorage || '[]'); } // Limpa e popula a tabela queueTableBody.innerHTML = ''; if (!proximos || proximos.length === 0) { queueEmpty.style.display = 'flex'; document.querySelector('.queue-table').style.display = 'none'; queueCount.textContent = '0'; } else { queueEmpty.style.display = 'none'; document.querySelector('.queue-table').style.display = 'table'; queueCount.textContent = proximos.length; proximos.forEach((item, index) => { const tr = document.createElement('tr'); const isPreferencial = item.ticketNumber && item.ticketNumber.startsWith('P'); tr.innerHTML = ` ${item.ticketNumber || '---'} ${(item.clientName || '---').toUpperCase()} ${item.serviceName || 'Atendimento'} ${isPreferencial ? 'PREFERENCIAL' : 'NORMAL'} `; queueTableBody.appendChild(tr); }); } // CORREÇÃO DO BUG: Só atualiza selectedItemId se NÃO houver um atendimento já chamado (travado) if (!calledAtendimentoData) { // Nenhum atendimento foi chamado ainda, pode selecionar o primeiro const firstItem = proximos && proximos[0]; if (firstItem) { selectedItemId = firstItem._id; selectedItemName = firstItem.clientName; } else { selectedItemId = null; selectedItemName = ''; } // Sem atendimento chamado: não mostra card if (!currentCard.style.display || currentCard.style.display === 'none') { noCurrentCard.style.display = 'flex'; } } // Se calledAtendimentoData está definido, NÃO toca no selectedItemId — mantém o que foi chamado. } // Mostra o card do atendimento atual (chamado) function showCurrentCard(data) { currentCard.style.display = 'flex'; noCurrentCard.style.display = 'none'; cardTicket.textContent = data.ticketNumber || '---'; const statusText = data.status === 'Atendendo' ? 'Atendendo' : 'Chamado'; cardStatusBadge.textContent = statusText; cardStatusBadge.className = `card-badge ${data.status === 'Atendendo' ? 'badge-atendendo' : 'badge-chamado'}`; cardClientName.textContent = (data.clientName || '---').toUpperCase(); cardService.textContent = (data.serviceName || 'ATENDIMENTO').toUpperCase(); const isPreferencial = data.ticketNumber && data.ticketNumber.startsWith('P'); cardType.textContent = isPreferencial ? 'PREFERENCIAL' : 'NORMAL'; cardType.className = `card-type ${isPreferencial ? 'type-preferencial' : ''}`; // Habilita os botões setTimeout(() => { nextButton.disabled = false; recallButton.disabled = false; }, 500); } function showNoCurrentCard(message) { currentCard.style.display = 'none'; noCurrentCard.style.display = 'flex'; noCurrentCard.querySelector('p').textContent = message || 'Nenhum atendimento chamado'; } // Verifica o estado ao carregar a janela document.addEventListener('DOMContentLoaded', () => { const atendimentoEmAndamentoId = localStorage.getItem('atendimentoAtual'); if (atendimentoEmAndamentoId) { // Se um atendimento está em andamento, a tela de observação deve ser mostrada selectedItemId = atendimentoEmAndamentoId; selectedItemName = localStorage.getItem('atendimentoAtualNome'); selectedItemNameSpan.innerHTML = ` ${(selectedItemName || '').toUpperCase()} `; showObservationView(); } }); //mostra a tela de listagem e permite iniciar o atendimento function showListView() { listView.style.display = 'block'; encaminharView.style.display = 'none'; observationView.style.display = 'none'; observationText.value = ''; // Limpa a textarea } showListView(); //inicia o atendimento function showObservationView() { if (!selectedItemId) return; // Não muda se nada estiver selecionado listView.style.display = 'none'; observationView.style.display = 'block'; } // // Evento do botão "Iniciar atendimento" (INICIAR) nextButton.addEventListener('click', () => { // Usa calledAtendimentoData para garantir que estamos iniciando O ATENDIMENTO CORRETO const idToStart = calledAtendimentoData ? calledAtendimentoData._id : selectedItemId; const nameToStart = calledAtendimentoData ? calledAtendimentoData.clientName : selectedItemName; if (idToStart !== null) { // Salva o estado de atendimento no localStorage localStorage.setItem('atendimentoAtual', idToStart); localStorage.setItem('atendimentoAtualNome', nameToStart); // Atualiza o span da tela de observação selectedItemId = idToStart; selectedItemName = nameToStart; selectedItemNameSpan.innerHTML = ` ${(nameToStart || '').toUpperCase()} `; // Notifica o main process e muda a view // IMPORTANTE: iniciaAtendimento deve apenas mudar o status na API, não chamar o próximo. window.electronAPI.atendimentoIniciado(idToStart); window.electronAPI.iniciaAtendimento(idToStart); // Limpa o travamento — atendimento foi iniciado calledAtendimentoData = null; showObservationView(); // Muda para a tela de observação } else { console.warn("Nenhum item selecionado para 'Iniciar'"); } }); // Evento do botão RECHAMAR recallButton.addEventListener('click', () => { if (calledAtendimentoData) { // Re-chama o mesmo atendimento (pode tocar som, exibir no painel, etc.) window.electronAPI.rechamarAtendimento(calledAtendimentoData._id); // Feedback visual recallButton.textContent = 'RECHAMANDO...'; recallButton.disabled = true; setTimeout(() => { recallButton.textContent = 'RECHAMAR'; recallButton.disabled = false; }, 2000); } }); logoutButton.addEventListener('click', () => { window.electronAPI.logoutApp(); }); // // // Evento do botão "Salvar" saveButton.addEventListener('click', () => { const observation = observationText.value; if (selectedItemId !== null) { // Limpa o estado de atendimento localStorage.removeItem('atendimentoAtual'); localStorage.removeItem('atendimentoAtualNome'); window.electronAPI.atendimentoFinalizado(); // Limpa o travamento calledAtendimentoData = null; window.electronAPI.saveObservation({ itemId: selectedItemId, observation: observation }); window.location.reload(); } });