botserver/ui/suite/attendant/index.html

959 lines
30 KiB
HTML
Raw Normal View History

2025-11-21 23:23:53 -03:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Attendant - General Bots</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;</title>
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: var(--bg-primary, #0f172a);
color: var(--text-primary, #f1f5f9);
height: 100vh;
overflow: hidden;
}
.attendant-layout {
display: grid;
grid-template-columns: 320px 1fr 380px;
height: 100vh;
}
/* Left Sidebar - Queue */
.queue-sidebar {
background: var(--bg-secondary, #1e293b);
border-right: 1px solid var(--border-color, #334155);
display: flex;
flex-direction: column;
}
.queue-header {
padding: 20px;
border-bottom: 1px solid var(--border-color, #334155);
}
.queue-title {
font-size: 20px;
font-weight: 600;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 8px;
}
.attendant-status {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background: #10b981;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.status-text {
font-size: 14px;
color: var(--text-secondary, #94a3b8);
}
.queue-filters {
padding: 16px 20px;
display: flex;
gap: 8px;
border-bottom: 1px solid var(--border-color, #334155);
}
.filter-btn {
padding: 8px 16px;
border: none;
border-radius: 6px;
background: var(--bg-tertiary, #334155);
color: var(--text-secondary, #94a3b8);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.filter-btn:hover {
background: var(--bg-quaternary, #475569);
}
.filter-btn.active {
background: var(--accent-color, #3b82f6);
color: white;
}
.filter-btn .badge {
display: inline-block;
margin-left: 6px;
padding: 2px 6px;
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
font-size: 11px;
}
.conversation-list {
flex: 1;
overflow-y: auto;
}
.conversation-item {
padding: 16px 20px;
border-bottom: 1px solid var(--border-color, #334155);
cursor: pointer;
transition: background 0.2s;
position: relative;
}
.conversation-item:hover {
background: var(--bg-tertiary, #334155);
}
.conversation-item.active {
background: var(--bg-tertiary, #334155);
border-left: 3px solid var(--accent-color, #3b82f6);
}
.conversation-item.unread::before {
content: '';
position: absolute;
left: 8px;
top: 50%;
transform: translateY(-50%);
width: 8px;
height: 8px;
background: var(--accent-color, #3b82f6);
border-radius: 50%;
}
.conversation-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.customer-name {
font-weight: 500;
font-size: 14px;
}
.conversation-time {
font-size: 12px;
color: var(--text-secondary, #94a3b8);
}
.conversation-preview {
font-size: 13px;
color: var(--text-secondary, #94a3b8);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-bottom: 8px;
}
.conversation-meta {
display: flex;
gap: 8px;
}
.channel-tag {
padding: 3px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
}
.channel-whatsapp {
background: rgba(37, 211, 102, 0.2);
color: #25d366;
}
.channel-teams {
background: rgba(93, 120, 255, 0.2);
color: #5d78ff;
}
.channel-instagram {
background: rgba(225, 48, 108, 0.2);
color: #e1306c;
}
.channel-web {
background: rgba(59, 130, 246, 0.2);
color: #3b82f6;
}
.priority-high {
padding: 3px 8px;
border-radius: 4px;
font-size: 11px;
background: rgba(239, 68, 68, 0.2);
color: #ef4444;
}
/* Center - Chat Area */
.chat-area {
display: flex;
flex-direction: column;
background: var(--bg-primary, #0f172a);
}
.chat-header {
padding: 20px 24px;
background: var(--bg-secondary, #1e293b);
border-bottom: 1px solid var(--border-color, #334155);
display: flex;
justify-content: space-between;
align-items: center;
}
.customer-info {
display: flex;
align-items: center;
gap: 12px;
}
.customer-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--accent-color, #3b82f6);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 16px;
}
.customer-details h3 {
font-size: 16px;
margin-bottom: 2px;
}
.customer-status {
font-size: 13px;
color: var(--text-secondary, #94a3b8);
}
.chat-actions {
display: flex;
gap: 8px;
}
.action-btn {
padding: 8px 12px;
border: none;
border-radius: 6px;
background: var(--bg-tertiary, #334155);
color: var(--text-primary, #f1f5f9);
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
.action-btn:hover {
background: var(--bg-quaternary, #475569);
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
}
.message {
margin-bottom: 20px;
display: flex;
gap: 12px;
}
.message.customer {
flex-direction: row;
}
.message.attendant {
flex-direction: row-reverse;
}
.message.bot {
flex-direction: row;
}
.message-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--bg-tertiary, #334155);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
flex-shrink: 0;
}
.message.bot .message-avatar {
background: var(--accent-color, #3b82f6);
}
.message-content {
max-width: 70%;
}
.message-bubble {
padding: 12px 16px;
border-radius: 12px;
margin-bottom: 4px;
}
.message.customer .message-bubble {
background: var(--bg-secondary, #1e293b);
}
.message.attendant .message-bubble {
background: var(--accent-color, #3b82f6);
}
.message.bot .message-bubble {
background: var(--bg-tertiary, #334155);
border: 1px solid var(--accent-color, #3b82f6);
}
.message-meta {
display: flex;
align-items: center;
gap: 8px;
font-size: 11px;
color: var(--text-secondary, #94a3b8);
}
.message.attendant .message-meta {
justify-content: flex-end;
}
.bot-badge {
padding: 2px 6px;
background: rgba(59, 130, 246, 0.2);
color: var(--accent-color, #3b82f6);
border-radius: 4px;
font-size: 10px;
font-weight: 600;
}
.chat-input-area {
padding: 20px;
background: var(--bg-secondary, #1e293b);
border-top: 1px solid var(--border-color, #334155);
}
.quick-responses {
display: flex;
gap: 8px;
margin-bottom: 12px;
overflow-x: auto;
}
.quick-response-btn {
padding: 6px 12px;
border: 1px solid var(--border-color, #334155);
border-radius: 6px;
background: transparent;
color: var(--text-secondary, #94a3b8);
font-size: 12px;
cursor: pointer;
white-space: nowrap;
transition: all 0.2s;
}
.quick-response-btn:hover {
border-color: var(--accent-color, #3b82f6);
color: var(--accent-color, #3b82f6);
}
.input-wrapper {
display: flex;
gap: 12px;
align-items: flex-end;
}
.chat-input {
flex: 1;
padding: 12px;
border: 1px solid var(--border-color, #334155);
border-radius: 8px;
background: var(--bg-primary, #0f172a);
color: var(--text-primary, #f1f5f9);
font-size: 14px;
font-family: inherit;
resize: none;
min-height: 44px;
max-height: 120px;
}
.chat-input:focus {
outline: none;
border-color: var(--accent-color, #3b82f6);
}
.send-btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
background: var(--accent-color, #3b82f6);
color: white;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.send-btn:hover {
background: var(--accent-hover, #2563eb);
transform: translateY(-1px);
}
/* Right Sidebar - Bot Insights & Customer Info */
.insights-sidebar {
background: var(--bg-secondary, #1e293b);
border-left: 1px solid var(--border-color, #334155);
overflow-y: auto;
}
.sidebar-section {
padding: 20px;
border-bottom: 1px solid var(--border-color, #334155);
}
.section-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 8px;
}
.bot-insight {
padding: 12px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
margin-bottom: 12px;
border-left: 3px solid var(--accent-color, #3b82f6);
}
.insight-label {
font-size: 11px;
color: var(--text-secondary, #94a3b8);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 6px;
}
.insight-value {
font-size: 14px;
font-weight: 500;
}
.suggested-reply {
padding: 12px;
background: var(--bg-primary, #0f172a);
border-radius: 8px;
margin-bottom: 8px;
cursor: pointer;
transition: all 0.2s;
border: 1px solid transparent;
}
.suggested-reply:hover {
border-color: var(--accent-color, #3b82f6);
background: var(--bg-tertiary, #334155);
}
.suggested-reply-text {
font-size: 13px;
margin-bottom: 4px;
}
.suggestion-confidence {
font-size: 11px;
color: var(--text-secondary, #94a3b8);
}
.customer-detail-item {
margin-bottom: 16px;
}
.detail-label {
font-size: 12px;
color: var(--text-secondary, #94a3b8);
margin-bottom: 4px;
}
.detail-value {
font-size: 14px;
font-weight: 500;
}
.conversation-history-item {
padding: 12px;
background: var(--bg-tertiary, #334155);
border-radius: 8px;
margin-bottom: 8px;
cursor: pointer;
transition: all 0.2s;
}
.conversation-history-item:hover {
background: var(--bg-quaternary, #475569);
}
.history-date {
font-size: 11px;
color: var(--text-secondary, #94a3b8);
margin-bottom: 4px;
}
.history-summary {
font-size: 13px;
}
.sentiment-indicator {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-radius: 8px;
font-size: 13px;
}
.sentiment-positive {
background: rgba(16, 185, 129, 0.2);
color: #10b981;
}
.sentiment-neutral {
background: rgba(245, 158, 11, 0.2);
color: #f59e0b;
}
.sentiment-negative {
background: rgba(239, 68, 68, 0.2);
color: #ef4444;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: var(--text-secondary, #94a3b8);
}
.empty-icon {
font-size: 64px;
margin-bottom: 16px;
opacity: 0.5;
}
</style>
</head>
<body>
<div class="attendant-layout">
<!-- Left Sidebar - Queue -->
<div class="queue-sidebar">
<div class="queue-header">
<div class="queue-title">
<span>💬</span>
<span>Conversation Queue</span>
</div></span>
<div class="attendant-status">
<div</span> class="status-indicator"></div>
<div class="status-text">Online & Ready</div>
</div>
</div>
<div class="queue-filters">
<button class="filter-btn active">
All <span class="badge">12</span>
</button>
<button class="filter-btn">
Waiting <span class="badge">5</span>
</button>
<button class="filter-btn">
Active <span class="badge">7</span>
</button>
</div>
<div class="conversation-list" id="conversationList">
<div class="conversation-item active unread" data-id="1">
<div class="conversation-header">
<div class="customer-name">Maria Silva</div>
<div class="conversation-time">2 min</div>
</div>
<div class="conversation-preview">
🤖 Bot: Entendi! Vou transferir você para um atendente...
</div>
<div class="conversation-meta">
<span class="channel-tag channel-whatsapp">WhatsApp</span>
<span class="priority-high">High</span>
</div>
</div>
<div class="conversation-item" data-id="2">
<div class="conversation-header">
<div class="customer-name">John Doe</div>
<div class="conversation-time">5 min</div>
</div>
<div class="conversation-preview">
Customer: Can you help me with my order?
</div>
<div class="conversation-meta">
<span class="channel-tag channel-teams">Teams</span>
</div>
</div>
<div class="conversation-item unread" data-id="3">
<div class="conversation-header">
<div class="customer-name">Ana Costa</div>
<div class="conversation-time">12 min</div>
</div>
<div class="conversation-preview">
🤖 Bot: Qual é o seu pedido?
</div>
<div class="conversation-meta">
<span class="channel-tag channel-instagram">Instagram</span>
</div>
</div>
<div class="conversation-item" data-id="4">
<div class="conversation-header">
<div class="customer-name">Carlos Santos</div>
<div class="conversation-time">20 min</div>
</div>
<div class="conversation-preview">
Attendant: Obrigado pelo contato!
</div>
<div class="conversation-meta">
<span class="channel-tag channel-web">Web Chat</span>
</div>
</div>
</div>
</div>
<!-- Center - Chat Area -->
<div class="chat-area">
<div class="chat-header">
<div class="customer-info">
<div class="customer-avatar">MS</div>
<div class="customer-details">
<h3>Maria Silva</h3>
<div class="customer-status">Typing...</div>
</div>
</div>
<div class="chat-actions">
<button class="action-btn" title="Transfer">🔄 Transfer</button>
<button class="action-btn" title="Close">✓ Resolve</button>
<button class="action-btn" title="More"></button>
</div>
</div>
<div class="chat-messages" id="chatMessages">
<div class="message customer">
<div class="message-avatar">MS</div>
<div class="message-content">
<div class="message-bubble">
Olá! Preciso de ajuda com meu pedido #12345
</div>
<div class="message-meta">
<span>10:23 AM</span>
<span>via WhatsApp</span>
</div>
</div>
</div>
<div class="message bot">
<div class="message-avatar">🤖</div>
<div class="message-content">
<div class="message-bubble">
Olá Maria! Vejo que você tem uma dúvida sobre o pedido #12345. Posso ajudar com:
<br>1. Status do pedido
<br>2. Prazo de entrega
<br>3. Cancelamento/Troca
<br><br>O que você precisa?
</div>
<div class="message-meta">
<span class="bot-badge">BOT</span>
<span>10:23 AM</span>
</div>
</div>
</div>
<div class="message customer">
<div class="message-avatar">MS</div>
<div class="message-content">
<div class="message-bubble">
Quero saber o prazo de entrega, já faz 10 dias!
</div>
<div class="message-meta">
<span>10:24 AM</span>
</div>
</div>
</div>
<div class="message bot">
<div class="message-avatar">🤖</div>
<div class="message-content">
<div class="message-bubble">
Entendi sua preocupação. Vou consultar o status do seu pedido e transferir você para um atendente que pode ajudar melhor com isso. Aguarde um momento...
</div>
<div class="message-meta">
<span class="bot-badge">BOT</span>
<span>10:24 AM</span>
<span>🔄 Transferred to queue</span>
</div>
</div>
</div>
</div>
<div class="chat-input-area">
<div class="quick-responses">
<button class="quick-response-btn">👋 Olá! Como posso ajudar?</button>
<button class="quick-response-btn">✓ Vou verificar isso para você</button>
<button class="quick-response-btn">📦 Verificando o pedido...</button>
<button class="quick-response-btn">😊 Obrigado pelo contato!</button>
</div>
<div class="input-wrapper">
<textarea class="chat-input" placeholder="Type your message..." rows="1"></textarea>
<button class="send-btn">Send</button>
</div>
</div>
</div>
<!-- Right Sidebar - Bot Insights -->
<div class="insights-sidebar">
<div class="sidebar-section">
<div class="section-title">🤖 Bot Insights</div>
<div class="bot-insight">
<div class="insight-label">Intent Detected</div>
<div class="insight-value">Order Status Inquiry</div>
</div>
<div class="bot-insight">
<div class="insight-label">Sentiment</div>
<div class="sentiment-indicator sentiment-negative">
<span>😟</span>
<span>Frustrated (75%)</span></span>
</div>
</div>
<div class="bot-insight">
<div class="insight-label">Context</div>
<div class="insight-value">Order #12345 - Shipped 8 days ago, expected today</div>
</div>
</div>
<div class="sidebar-section">
<div class="section-title">💡 Suggested Replies</div>
<div class="suggested-reply">
<div class="suggested-reply-text">
"Olá Maria! Vi que seu pedido está em trânsito e deve chegar hoje. Posso te enviar o código de rastreamento?"
</div>
<div class="suggestion-confidence">AI Confidence: 92%</div>
</div>
<div class="suggested-reply">
<div class="suggested-reply-text">
"Entendo sua preocupação. Vou acelerar a entrega e garantir que chegue ainda hoje."
</div>
<div class="suggestion-confidence">AI Confidence: 85%</div>
</div>
</div>
<div class="sidebar-section">
<div class="section-title">👤 Customer Info</div>
<div class="customer-detail-item">
<div class="detail-label">Email</div>
<div class="detail-value">maria.silva@email.com</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Phone</div>
<div class="detail-value">+55 11 98765-4321</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Total Orders</div>
<div class="detail-value">8 orders • R$ 2,450.00</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Customer Since</div>
<div class="detail-value">January 2023</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Tags</div>
<div style="display: flex; gap: 4px; flex-wrap: wrap;">
<span class="channel-tag channel-whatsapp">VIP</span>
<span class="channel-tag channel-web">Frequent Buyer</span>
</div>
</div>
</div>
<div class="sidebar-section">
<div class="section-title">📜 Recent History</div>
<div class="conversation-history-item">
<div class="history-date">Dec 15, 2024</div>
<div class="history-summary">Order inquiry - Resolved</div>
</div>
<div class="conversation-history-item">
<div class="history-date">Nov 28, 2024</div>
<div class="history-summary">Product question - Bot handled</div>
</div>
<div class="conversation-history-item">
<div class="history-date">Nov 10, 2024</div>
<div class="history-summary">Complaint - Refund issued</div>
</div>
</div>
</div>
</div>
<script>
const API_BASE = window.location.origin;
// Auto-resize textarea
const chatInput = document.querySelector('.chat-input');
chatInput.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = this.scrollHeight + 'px';
});
// Quick responses
document.querySelectorAll('.quick-response-btn').forEach(btn => {
btn.addEventListener('click', () => {
chatInput.value = btn.textContent;
chatInput.focus();
});
});
// Suggested replies
document.querySelectorAll('.suggested-reply').forEach(reply => {
reply.addEventListener('click', () => {
chatInput.value = reply.querySelector('.suggested-reply-text').textContent.trim();
chatInput.focus();
});
});
// Send message
document.querySelector('.send-btn').addEventListener('click', sendMessage);
chatInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
function sendMessage() {
const message = chatInput.value.trim();
if (!message) return;
// Add message to chat
const messagesContainer = document.getElementById('chatMessages');
const messageEl = document.createElement('div');
messageEl.className = 'message attendant';
messageEl.innerHTML = `
<div class="message-avatar">You</div>
<div class="message-content">
<div class="message-bubble">${message}</div>
<div class="message-meta">
<span>${new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>
</div>
</div>
`;
messagesContainer.appendChild(messageEl);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
// Clear input
chatInput.value = '';
chatInput.style.height = 'auto';
// TODO: Send to API
// sendMessageAPI(message);
}
// Conversation selection
document.querySelectorAll('.conversation-item').forEach(item => {
item.addEventListener('click', () => {
document.querySelectorAll('.conversation-item').forEach(i => i.classList.remove('active'));
item.classList.add('active');
item.classList.remove('unread');
// TODO: Load conversation
// loadConversation(item.dataset.id);
});
});
// Load conversations from API
async function loadQueue() {
try {
// TODO: Implement API call
// const response = await fetch(`${API_BASE}/api/attendant/queue`);
// const conversations = await response.json();
// renderConversations(conversations);
} catch (error) {
console.error('Failed to load queue:', error);
}
}
// WebSocket for real-time updates
function connectWebSocket() {
const ws = new WebSocket(`ws://${window.location.host}/ws/attendant`);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch(data.type) {
case 'new_message':
handleNewMessage(data);
break;
case 'queue_update':
updateQueue(data);
break;
case 'bot_insight':
updateInsights(data);
break;
}
};
}
// Initialize
// loadQueue();
// connectWebSocket();
</script>
</body>
</html>