botui/ui/suite/attendant/index.html
Rodrigo Rodriguez (Pragmatismo) 69654f37d6 refactor(ui): extract inline CSS/JS to external files
Phase 2 of CSS/JS extraction - replace inline styles and scripts with
external file references for better maintainability and caching.

Files updated:
- home.html -> css/home.css, js/home.js
- tasks/tasks.html -> tasks/tasks.css, tasks/tasks.js
- admin/index.html -> admin/admin.css, admin/admin.js
- analytics/analytics.html -> analytics/analytics.css, analytics/analytics.js
- mail/mail.html -> mail/mail.css, mail/mail.js
- monitoring/monitoring.html -> monitoring/monitoring.css, monitoring/monitoring.js
- attendant/index.html -> attendant/attendant.css, attendant/attendant.js

All JS wrapped in IIFE pattern to prevent global namespace pollution.
Functions called from HTML onclick handlers exposed via window object.
HTMX reload handlers included for proper reinitialization.

Per PROMPT.md: no CDN links, HTMX-first approach, local assets only.
2026-01-10 20:12:48 -03:00

575 lines
26 KiB
HTML

<!-- Attendant Console - General Bots -->
<link rel="stylesheet" href="attendant.css" />
<!-- CRM Disabled State -->
<!-- CRM Disabled State - Hidden by default, CRM is now enabled by default -->
<div class="crm-disabled" id="crmDisabled" style="display: none">
<div class="crm-disabled-icon">🚫</div>
<h2 data-i18n="attendant-crm-disabled">CRM Features Not Enabled</h2>
<p>
The Attendant Console requires CRM features to be enabled for
this bot. This allows human agents to receive and respond to
conversations transferred from the bot.
</p>
</div>
<!-- Main Layout - Shown by default, CRM is enabled by default -->
<div class="attendant-layout" id="mainLayout" style="display: grid">
<!-- Left Sidebar - Queue -->
<aside class="queue-sidebar">
<div class="queue-header">
<div class="queue-title">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"
/>
<circle cx="9" cy="7" r="4" />
<path d="M23 21v-2a4 4 0 0 0-3-3.87" />
<path d="M16 3.13a4 4 0 0 1 0 7.75" />
</svg>
<span data-i18n="attendant-title">Attendant Console</span>
</div>
<div
class="attendant-status"
id="attendantStatus"
onclick="toggleStatusDropdown()"
>
<div
class="status-indicator online"
id="statusIndicator"
></div>
<div class="status-info">
<div class="status-name" id="attendantName">
Loading...
</div>
<div class="status-text" id="statusText" data-i18n="attendant-status-online">
Online - Ready for conversations
</div>
</div>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M6 9l6 6 6-6" />
</svg>
<div class="status-dropdown" id="statusDropdown">
<div
class="status-option"
onclick="setStatus('online')"
>
<div class="status-indicator online"></div>
<span>Online</span>
</div>
<div
class="status-option"
onclick="setStatus('busy')"
>
<div class="status-indicator busy"></div>
<span>Busy</span>
</div>
<div
class="status-option"
onclick="setStatus('away')"
>
<div class="status-indicator away"></div>
<span>Away</span>
</div>
<div
class="status-option"
onclick="setStatus('offline')"
>
<div class="status-indicator offline"></div>
<span>Offline</span>
</div>
</div>
</div>
</div>
<div class="queue-stats">
<div class="stat-item">
<div class="stat-value" id="waitingCount">0</div>
<div class="stat-label">Waiting</div>
</div>
<div class="stat-item">
<div class="stat-value" id="activeCount">0</div>
<div class="stat-label">Active</div>
</div>
<div class="stat-item">
<div class="stat-value" id="resolvedCount">0</div>
<div class="stat-label">Resolved</div>
</div>
</div>
<div class="queue-filters">
<button
class="filter-btn active"
data-filter="all"
onclick="filterQueue('all')"
>
All <span class="badge" id="allBadge">0</span>
</button>
<button
class="filter-btn"
data-filter="waiting"
onclick="filterQueue('waiting')"
>
Waiting <span class="badge" id="waitingBadge">0</span>
</button>
<button
class="filter-btn"
data-filter="mine"
onclick="filterQueue('mine')"
>
Mine <span class="badge" id="mineBadge">0</span>
</button>
<button
class="filter-btn"
data-filter="high"
onclick="filterQueue('high')"
>
🔥 Priority
</button>
</div>
<div class="conversation-list" id="conversationList">
<div class="empty-queue" id="emptyQueue">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
>
<path d="M20 6L9 17l-5-5" />
</svg>
<p>No conversations in queue</p>
<small>New conversations will appear here</small>
</div>
</div>
</aside>
<!-- Chat Area -->
<main class="chat-area" id="chatArea">
<div class="no-conversation" id="noConversation">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
/>
</svg>
<h3 data-i18n="attendant-select-conversation">Select a conversation</h3>
<p>
Choose a conversation from the queue to start responding
</p>
</div>
<div
id="activeChat"
style="display: none; flex-direction: column; height: 100%"
>
<div class="chat-header">
<div class="customer-info">
<div class="customer-avatar" id="customerAvatar">
?
</div>
<div class="customer-details">
<h3 id="customerName">Customer Name</h3>
<div class="customer-status-line">
<span
class="channel-tag"
id="customerChannel"
>web</span
>
<span id="customerStatusText"
>Active now</span
>
</div>
</div>
</div>
<div class="chat-actions">
<button
class="action-btn"
onclick="showTransferModal()"
title="Transfer"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M17 1l4 4-4 4" />
<path d="M3 11V9a4 4 0 0 1 4-4h14" />
<path d="M7 23l-4-4 4-4" />
<path d="M21 13v2a4 4 0 0 1-4 4H3" />
</svg>
Transfer
</button>
<button
class="action-btn primary"
onclick="resolveConversation()"
title="Resolve"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M20 6L9 17l-5-5" />
</svg>
Resolve
</button>
</div>
</div>
<div class="chat-messages" id="chatMessages">
<!-- Messages loaded dynamically -->
</div>
<div class="chat-input-area">
<div class="quick-responses" id="quickResponses">
<button
class="quick-response-btn"
onclick="useQuickResponse('Hello! How can I help you today?')"
>
👋 Greeting
</button>
<button
class="quick-response-btn"
onclick="useQuickResponse('Thank you for your patience.')"
>
🙏 Thanks
</button>
<button
class="quick-response-btn"
onclick="useQuickResponse('Let me look into that for you.')"
>
🔍 Looking into it
</button>
<button
class="quick-response-btn"
onclick="useQuickResponse('Is there anything else I can help you with?')"
>
❓ Anything else
</button>
</div>
<div class="input-wrapper">
<div class="input-actions">
<button
class="input-action-btn"
onclick="attachFile()"
title="Attach file"
>
<button class="input-action-btn" onclick="attachFile()" title="Attach file">
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"
/>
</svg>
</button>
<button
class="input-action-btn"
onclick="polishMessage()"
title="✨ Polish message with AI"
style="color: var(--primary);"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d="M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z"/>
<path d="M19 13l1 3 3 1-3 1-1 3-1-3-3-1 3-1 1-3z"/>
</svg>
</button>
<button
class="input-action-btn"
onclick="insertEmoji()"
title="Insert emoji"
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="10" />
<path d="M8 14s1.5 2 4 2 4-2 4-2" />
<line x1="9" y1="9" x2="9.01" y2="9" />
<line x1="15" y1="9" x2="15.01" y2="9" />
</svg>
</button>
</div>
<textarea
class="chat-input"
id="chatInput"
placeholder="Type your message..."
rows="1"
></textarea>
<button
class="send-btn"
id="sendBtn"
onclick="sendMessage()"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="22" y1="2" x2="11" y2="13" />
<polygon
points="22 2 15 22 11 13 2 9 22 2"
/>
</svg>
</button>
</div>
</div>
</div>
</main>
<!-- Right Sidebar - Insights -->
<aside class="insights-sidebar">
<div class="sidebar-section">
<div class="section-title">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8z"
/>
<path d="M12 6v6l4 2" />
</svg>
AI Insights
</div>
<div class="ai-insight" id="sentimentInsight">
<div class="insight-header">
<span class="insight-label"
>Customer Sentiment</span
>
</div>
<div class="insight-value">
<span
class="sentiment-indicator sentiment-neutral"
id="sentimentValue"
>😐 Neutral</span
>
</div>
</div>
<div class="ai-insight" id="intentInsight">
<div class="insight-header">
<span class="insight-label">Detected Intent</span>
</div>
<div class="insight-value" id="intentValue">
Awaiting messages...
</div>
</div>
<div class="ai-insight" id="summaryInsight">
<div class="insight-header">
<span class="insight-label"
>Conversation Summary</span
>
</div>
<div class="insight-value" id="summaryValue">
No conversation selected
</div>
</div>
</div>
<div class="sidebar-section">
<div class="section-title">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
/>
</svg>
Suggested Replies
</div>
<div id="suggestedReplies">
<div
class="suggested-reply"
onclick="useSuggestion(this)"
>
<div class="suggested-reply-text">
Select a conversation to see AI-suggested
replies
</div>
<div class="suggestion-meta">
<span class="suggestion-source"
>AI Assistant</span
>
</div>
</div>
</div>
</div>
<div
class="sidebar-section"
id="customerDetails"
style="display: none"
>
<div class="section-title">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"
/>
<circle cx="12" cy="7" r="4" />
</svg>
Customer Details
</div>
<div class="customer-detail-item">
<div class="detail-label">Email</div>
<div class="detail-value" id="detailEmail">-</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Phone</div>
<div class="detail-value" id="detailPhone">-</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Location</div>
<div class="detail-value" id="detailLocation">-</div>
</div>
<div class="customer-detail-item">
<div class="detail-label">Tags</div>
<div class="tags-container" id="detailTags">
<span class="tag">new-customer</span>
</div>
</div>
</div>
<div class="sidebar-section">
<div class="section-title">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="12" cy="12" r="10" />
<polyline points="12 6 12 12 16 14" />
</svg>
Previous Conversations
</div>
<div id="conversationHistory">
<div
class="history-item"
onclick="loadHistoricalConversation('123')"
>
<div class="history-header">
<span class="history-date"
>No history available</span
>
</div>
<div class="history-summary">
Select a customer to view their history
</div>
</div>
</div>
</div>
</aside>
</div>
<!-- Transfer Modal -->
<div class="modal-overlay" id="transferModal">
<div class="modal">
<div class="modal-header">
<h3 data-i18n="attendant-transfer">Transfer Conversation</h3>
<button class="modal-close" onclick="closeTransferModal()">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label class="form-label">Transfer to</label>
<div class="attendant-list" id="attendantList">
<!-- Loaded dynamically -->
</div>
</div>
<div class="form-group">
<label class="form-label">Reason (optional)</label>
<input
type="text"
class="form-input"
id="transferReason"
placeholder="e.g., Technical issue, needs specialist"
/>
</div>
</div>
<div class="modal-footer">
<button class="action-btn" onclick="closeTransferModal()">
Cancel
</button>
<button
class="action-btn primary"
onclick="confirmTransfer()"
>
Transfer
</button>
</div>
</div>
</div>
<!-- Toast Container -->
<script src="attendant.js"></script>