alterações de melhorias
This commit is contained in:
+44
-4
@@ -1101,7 +1101,7 @@ async function carregarConversas() {
|
||||
});
|
||||
}
|
||||
renderConversas(data.data, busca);
|
||||
} catch(e) {}
|
||||
} catch(e) { if (Chatc2Toast) Chatc2Toast.error('Erro ao carregar conversas'); }
|
||||
}
|
||||
|
||||
var AVATAR_COLORS = ['#667eea','#764ba2','#f093fb','#4facfe','#43e97b','#fa709a','#fee140','#30cfd0','#a18cd1','#fda085'];
|
||||
@@ -1151,6 +1151,23 @@ function renderConversas(convs, busca) {
|
||||
return '<span class="conv-badge" style="background:' + esc(l.cor || '#667eea') + '">' + esc(l.nome || '') + '</span>';
|
||||
}).join('');
|
||||
const ultimaMsg = (c.ultimaMsg || '').substring(0, 60);
|
||||
// Preview com ícone por tipo de mensagem
|
||||
var previewHtml;
|
||||
if (!c.ultimaMsg) {
|
||||
previewHtml = '<em>Sem mensagens</em>';
|
||||
} else if (c.ultimaTipo === 'audio' || c.ultimaTipo === 'ptt') {
|
||||
previewHtml = '🎤 Mensagem de voz';
|
||||
} else if (c.ultimaTipo === 'image') {
|
||||
previewHtml = '🖼️ Imagem';
|
||||
} else if (c.ultimaTipo === 'video') {
|
||||
previewHtml = '🎥 Vídeo';
|
||||
} else if (c.ultimaTipo === 'document') {
|
||||
previewHtml = '📎 Documento';
|
||||
} else if (c.ultimaTipo === 'triagem') {
|
||||
previewHtml = '🤖 Menu de triagem';
|
||||
} else {
|
||||
previewHtml = esc(ultimaMsg);
|
||||
}
|
||||
const tempo = formatTime(c.dtUltimaMsg);
|
||||
return '<div class="conv-item ' + isActive + '" onclick="abrirConversa(' + c.id + ')" data-id="' + c.id + '">' +
|
||||
'<div class="conv-avatar" style="background:' + cor + '">' + iniciais + '</div>' +
|
||||
@@ -1159,7 +1176,7 @@ function renderConversas(convs, busca) {
|
||||
'<div class="conv-nome">' + esc(nome) + '</div>' +
|
||||
'<div style="font-size:10px;color:rgba(255,255,255,0.35);flex-shrink:0">' + tempo + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="conv-ultima">' + (ultimaMsg ? esc(ultimaMsg) : '<em>Sem mensagens</em>') + '</div>' +
|
||||
'<div class="conv-ultima">' + previewHtml + '</div>' +
|
||||
'<div class="conv-status">' + statusDot + ' ' + (c.status === 'E' ? 'Em espera' : c.status === 'A' ? 'Aberto' : 'Finalizado') + '</div>' +
|
||||
(labelsHtml ? '<div class="conv-badges">' + labelsHtml + '</div>' : '') +
|
||||
'</div>' +
|
||||
@@ -1491,8 +1508,20 @@ async function carregarMensagens() {
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
});
|
||||
var data = await res.json();
|
||||
if (data.success) renderMensagens(data.data);
|
||||
} catch(e) {}
|
||||
if (data.success) {
|
||||
// Notificação desktop: detecta novas mensagens de cliente
|
||||
var novasDoCliente = data.data.filter(function(m) {
|
||||
return m.remetente === 'C' && m.id > ultimaMsgIdGlobal && m.privada !== 'S';
|
||||
});
|
||||
if (novasDoCliente.length > 0 && Chatc2Notify) {
|
||||
var ultima = novasDoCliente[novasDoCliente.length - 1];
|
||||
Chatc2Notify.show('Nova mensagem', (ultima.mensagem || 'Mídia recebida').substring(0, 100));
|
||||
}
|
||||
// Atualiza ID máximo global
|
||||
data.data.forEach(function(m) { if (m.id > ultimaMsgIdGlobal) ultimaMsgIdGlobal = m.id; });
|
||||
renderMensagens(data.data);
|
||||
}
|
||||
} catch(e) { if (Chatc2Toast) Chatc2Toast.error('Erro ao carregar mensagens'); }
|
||||
carregandoMsgs = false;
|
||||
}
|
||||
|
||||
@@ -2110,11 +2139,20 @@ window.logout = function() {
|
||||
};
|
||||
|
||||
// Auto-refresh a cada 5 segundos
|
||||
let ultimaMsgIdGlobal = 0;
|
||||
setInterval(function() {
|
||||
carregarConversas();
|
||||
if (conversaAtiva) carregarMensagens();
|
||||
}, 5000);
|
||||
|
||||
// Notificação desktop: pede permissão na primeira interação
|
||||
document.addEventListener('click', function pedirPermissao() {
|
||||
document.removeEventListener('click', pedirPermissao);
|
||||
if (Chatc2Notify && Chatc2Notify.isSupported()) {
|
||||
Chatc2Notify.requestPermission();
|
||||
}
|
||||
}, { once: true });
|
||||
|
||||
// Presença: marca o atendente como "online" para o dashboard
|
||||
function pingPresenca() {
|
||||
fetch('/api/' + alias + '/dashboard/ping', {
|
||||
@@ -2133,6 +2171,8 @@ document.getElementById('msgInput').addEventListener('input', function() {
|
||||
})();
|
||||
</script>
|
||||
<script src="/js/dark-mode.js"></script>
|
||||
<script src="/js/notifications.js"></script>
|
||||
<script src="/js/toast.js"></script>
|
||||
<!-- impeccable-live-start -->
|
||||
<script src="http://localhost:8400/live.js"></script>
|
||||
<!-- impeccable-live-end -->
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
// Dark Mode Controller — Unified for all Chatc2 pages
|
||||
(function() {
|
||||
// Detecta preferência do sistema
|
||||
var osPrefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
var manualOverride = localStorage.getItem('chatc2_dark_mode_manual');
|
||||
|
||||
// Decide tema inicial: manual > preferência OS > claro
|
||||
function getInitialTheme() {
|
||||
if (manualOverride !== null) return manualOverride === 'true';
|
||||
return osPrefersDark.matches;
|
||||
}
|
||||
|
||||
// Apply on load immediately (FOUC prevention)
|
||||
if (localStorage.getItem('chatc2_dark_mode') === 'true') {
|
||||
if (getInitialTheme()) {
|
||||
document.documentElement.classList.add('dark-mode-pending');
|
||||
}
|
||||
|
||||
function applyTheme(enable) {
|
||||
function applyTheme(enable, isManual) {
|
||||
document.documentElement.classList.remove('dark-mode-pending');
|
||||
document.body && document.body.classList.toggle('dark-mode', enable);
|
||||
if (document.body) {
|
||||
document.body.classList.toggle('dark-mode', enable);
|
||||
}
|
||||
localStorage.setItem('chatc2_dark_mode', enable ? 'true' : 'false');
|
||||
if (isManual) {
|
||||
localStorage.setItem('chatc2_dark_mode_manual', enable ? 'true' : 'false');
|
||||
}
|
||||
document.querySelectorAll('.dark-mode-toggle').forEach(function(btn) {
|
||||
btn.innerHTML = enable ? '☀️ Claro' : '🌙 Escuro';
|
||||
});
|
||||
@@ -16,21 +31,28 @@
|
||||
|
||||
window.darkModeToggle = function() {
|
||||
var isDark = localStorage.getItem('chatc2_dark_mode') === 'true';
|
||||
applyTheme(!isDark);
|
||||
applyTheme(!isDark, true); // toggle manual
|
||||
};
|
||||
|
||||
window.darkModeApply = function(enable) { applyTheme(enable); };
|
||||
window.darkModeApply = function(enable) { applyTheme(enable, false); };
|
||||
|
||||
window.darkModeIsDark = function() {
|
||||
return localStorage.getItem('chatc2_dark_mode') === 'true';
|
||||
};
|
||||
|
||||
// Apply stored preference after DOM ready
|
||||
// Reage a mudanças no tema do sistema (só quando não há override manual)
|
||||
osPrefersDark.addEventListener('change', function(e) {
|
||||
if (localStorage.getItem('chatc2_dark_mode_manual') === null) {
|
||||
applyTheme(e.matches, false);
|
||||
}
|
||||
});
|
||||
|
||||
// Apply after DOM ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
applyTheme(localStorage.getItem('chatc2_dark_mode') === 'true');
|
||||
applyTheme(getInitialTheme(), false);
|
||||
});
|
||||
} else {
|
||||
applyTheme(localStorage.getItem('chatc2_dark_mode') === 'true');
|
||||
applyTheme(getInitialTheme(), false);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Notificações Desktop — Chatc2
|
||||
*
|
||||
* Incluir em páginas que precisam de notificações (chat, dashboard):
|
||||
* <script src="/js/notifications.js"></script>
|
||||
*
|
||||
* Uso:
|
||||
* Chatc2Notify.requestPermission(); // pede permissão ao usuário
|
||||
* Chatc2Notify.show('Nova mensagem', 'Cliente enviou uma mensagem');
|
||||
*
|
||||
* Respeita: permissão do navegador, foco da janela (não notifica se já está focada).
|
||||
*/
|
||||
(function() {
|
||||
var permitido = false;
|
||||
var inicializado = false;
|
||||
|
||||
function init() {
|
||||
if (inicializado) return;
|
||||
inicializado = true;
|
||||
|
||||
// Verifica suporte
|
||||
if (!('Notification' in window)) return;
|
||||
|
||||
// Verifica permissão atual
|
||||
if (Notification.permission === 'granted') {
|
||||
permitido = true;
|
||||
} else if (Notification.permission === 'denied') {
|
||||
permitido = false;
|
||||
}
|
||||
}
|
||||
|
||||
window.Chatc2Notify = {
|
||||
/** Pede permissão ao usuário (deve ser chamado após interação do usuário). */
|
||||
requestPermission: function() {
|
||||
init();
|
||||
if (!('Notification' in window)) return;
|
||||
if (Notification.permission === 'granted') {
|
||||
permitido = true;
|
||||
return;
|
||||
}
|
||||
if (Notification.permission === 'denied') return;
|
||||
|
||||
Notification.requestPermission().then(function(permission) {
|
||||
permitido = permission === 'granted';
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Exibe uma notificação.
|
||||
* Só dispara se: permissão concedida E janela não está focada.
|
||||
*/
|
||||
show: function(title, body, icon) {
|
||||
init();
|
||||
if (!permitido) return;
|
||||
if (document.hasFocus && document.hasFocus()) return; // já está olhando
|
||||
|
||||
try {
|
||||
var n = new Notification(title, {
|
||||
body: body || '',
|
||||
icon: icon || '/favicon.ico',
|
||||
tag: 'chatc2',
|
||||
});
|
||||
// Clica na notificação → foca a janela
|
||||
n.onclick = function() {
|
||||
window.focus();
|
||||
n.close();
|
||||
};
|
||||
// Auto-fecha após 5s
|
||||
setTimeout(function() { n.close(); }, 5000);
|
||||
} catch(e) {
|
||||
// Ignora erros (ex: Service Worker não registrado)
|
||||
}
|
||||
},
|
||||
|
||||
/** Retorna true se notificações estão disponíveis. */
|
||||
isSupported: function() {
|
||||
init();
|
||||
return 'Notification' in window;
|
||||
},
|
||||
|
||||
/** Retorna true se permissão está concedida. */
|
||||
isPermitted: function() {
|
||||
init();
|
||||
return permitido;
|
||||
},
|
||||
};
|
||||
|
||||
// Inicializa ao carregar
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Toast notifications — Chatc2
|
||||
*
|
||||
* Incluir em páginas que precisam de feedback visual:
|
||||
* <script src="/js/toast.js"></script>
|
||||
*
|
||||
* Uso:
|
||||
* Chatc2Toast.success('Mensagem enviada!');
|
||||
* Chatc2Toast.error('Erro ao carregar conversas');
|
||||
* Chatc2Toast.warn('Conexão lenta...');
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var container = null;
|
||||
|
||||
function ensureContainer() {
|
||||
if (container) return container;
|
||||
container = document.createElement('div');
|
||||
container.id = 'chatc2-toast-container';
|
||||
container.style.cssText = 'position:fixed;top:20px;right:20px;z-index:99999;display:flex;flex-direction:column;gap:8px;pointer-events:none;';
|
||||
document.body.appendChild(container);
|
||||
return container;
|
||||
}
|
||||
|
||||
function show(message, type) {
|
||||
var c = ensureContainer();
|
||||
|
||||
var toast = document.createElement('div');
|
||||
var colors = {
|
||||
success: { bg: '#d1fae5', color: '#065f46', border: '#6ee7b7' },
|
||||
error: { bg: '#fef2f2', color: '#991b1b', border: '#fca5a5' },
|
||||
warn: { bg: '#fef3c7', color: '#92400e', border: '#fcd34d' },
|
||||
info: { bg: '#ede9fe', color: '#5b21b6', border: '#c4b5fd' },
|
||||
};
|
||||
var col = colors[type] || colors.info;
|
||||
|
||||
toast.style.cssText = 'pointer-events:auto;padding:10px 16px;border-radius:8px;font-size:13px;font-weight:500;' +
|
||||
'max-width:380px;box-shadow:0 4px 16px rgba(0,0,0,0.12);animation:chatc2ToastIn 0.25s ease;' +
|
||||
'background:' + col.bg + ';color:' + col.color + ';border-left:4px solid ' + col.border + ';';
|
||||
toast.textContent = message;
|
||||
|
||||
c.appendChild(toast);
|
||||
|
||||
// Auto-remove
|
||||
var duration = type === 'error' ? 6000 : 3500;
|
||||
setTimeout(function() {
|
||||
toast.style.opacity = '0';
|
||||
toast.style.transform = 'translateX(20px)';
|
||||
toast.style.transition = 'all 0.2s ease';
|
||||
setTimeout(function() {
|
||||
if (toast.parentNode) toast.parentNode.removeChild(toast);
|
||||
}, 200);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
// Inject keyframe
|
||||
if (!document.getElementById('chatc2-toast-style')) {
|
||||
var style = document.createElement('style');
|
||||
style.id = 'chatc2-toast-style';
|
||||
style.textContent = '@keyframes chatc2ToastIn{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:translateX(0)}}';
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
window.Chatc2Toast = {
|
||||
success: function(msg) { show(msg, 'success'); },
|
||||
error: function(msg) { show(msg, 'error'); },
|
||||
warn: function(msg) { show(msg, 'warn'); },
|
||||
info: function(msg) { show(msg, 'info'); },
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user