From 5a0c66861324747db297ce2c9f218f74a63b9eb2 Mon Sep 17 00:00:00 2001 From: fcarraUniSa Date: Tue, 17 Feb 2026 11:09:48 +0100 Subject: [PATCH] Update AgentDashboard.tsx --- components/AgentDashboard.tsx | 615 ++++++++++++++++++++++++++++++---- 1 file changed, 552 insertions(+), 63 deletions(-) diff --git a/components/AgentDashboard.tsx b/components/AgentDashboard.tsx index 47d4309..2273399 100644 --- a/components/AgentDashboard.tsx +++ b/components/AgentDashboard.tsx @@ -57,7 +57,7 @@ interface AgentDashboardProps { settings: AppSettings; updateTicketStatus: (id: string, status: TicketStatus) => void; updateTicketAgent: (id: string, agentId: string) => void; - onReplyTicket: (ticketId: string, message: string) => void; // Added Prop + onReplyTicket: (ticketId: string, message: string) => void; addArticle: (article: KBArticle) => void; updateArticle: (article: KBArticle) => void; addAgent: (agent: Agent) => void; @@ -218,7 +218,7 @@ export const AgentDashboard: React.FC = ({ const [selectedTicketId, setSelectedTicketId] = useState(null); const [selectedQueue, setSelectedQueue] = useState(null); // Name of the queue const [isViewingArchive, setIsViewingArchive] = useState(false); - const [replyText, setReplyText] = useState(''); // State for reply input + const [replyText, setReplyText] = useState(''); // ROLE BASED PERMISSIONS const canManageGlobalSettings = currentUser.role === 'superadmin'; @@ -293,14 +293,6 @@ export const AgentDashboard: React.FC = ({ return agents.filter(a => a.queues.includes(ticketQueue)); }; - const handleReplySubmit = () => { - if (selectedTicketId && replyText.trim()) { - onReplyTicket(selectedTicketId, replyText); - setReplyText(''); - showToast('Risposta inviata', 'success'); - } - }; - // Helper function to fetch URL content via proxy const fetchUrlContent = async (url: string): Promise => { @@ -341,6 +333,14 @@ export const AgentDashboard: React.FC = ({ }; // Handlers + const handleReplySubmit = () => { + if (selectedTicketId && replyText.trim()) { + onReplyTicket(selectedTicketId, replyText); + setReplyText(''); + showToast('Risposta inviata', 'success'); + } + }; + const handleAiAnalysis = async () => { if (!settings.features.aiKnowledgeAgentEnabled) { showToast("L'Agente Knowledge AI è disabilitato dall'amministratore.", 'error'); @@ -366,9 +366,9 @@ export const AgentDashboard: React.FC = ({ settings.aiConfig.model ); if (suggestions) { - setAiSuggestions(suggestions); + setAiSuggestions(suggestions); } else { - showToast("Nessuna lacuna identificata dall'AI.", 'info'); + showToast("Nessuna lacuna identificata dall'AI.", 'info'); } setIsAiAnalyzing(false); }; @@ -383,7 +383,6 @@ export const AgentDashboard: React.FC = ({ source: 'ai', lastUpdated: new Date().toISOString().split('T')[0] }); - // Remove from list setAiSuggestions(prev => prev.filter((_, i) => i !== index)); showToast("Articolo aggiunto alla KB", 'success'); }; @@ -721,11 +720,11 @@ export const AgentDashboard: React.FC = ({ {/* Main Content */}
- {/* SETTINGS VIEW */} + {/* SETTINGS VIEW - PERMISSION GATED */} {view === 'settings' && canAccessSettings && (
- {/* SIDEBAR FOR SETTINGS */} + {/* Sidebar Settings Tabs */}

Impostazioni

@@ -766,11 +765,9 @@ export const AgentDashboard: React.FC = ({
- {/* SETTINGS CONTENT (System, General, AI, Users, Agents, Queues, Email) */} - {/* Keeping the existing structure for tabs but ensuring they render correctly */} + {/* SYSTEM SETTINGS TAB */} {settingsTab === 'system' && canManageGlobalSettings && (
- {/* ... System Settings Inputs ... */}

Limiti e Quote di Sistema

@@ -779,16 +776,82 @@ export const AgentDashboard: React.FC = ({ value={tempSettings.features.maxKbArticles} onChange={e => setTempSettings({...tempSettings, features: {...tempSettings.features, maxKbArticles: parseInt(e.target.value)}})} />
- {/* ... other inputs ... */} +
+ + setTempSettings({...tempSettings, features: {...tempSettings.features, maxAgents: parseInt(e.target.value)}})} /> +
+
+ + setTempSettings({...tempSettings, features: {...tempSettings.features, maxSupervisors: parseInt(e.target.value)}})} /> +
+
+ + setTempSettings({...tempSettings, features: {...tempSettings.features, maxAiGeneratedArticles: parseInt(e.target.value)}})} /> +
+
+
+ setTempSettings({...tempSettings, features: {...tempSettings.features, kbEnabled: e.target.checked}})} /> + +
+
+ setTempSettings({...tempSettings, features: {...tempSettings.features, aiKnowledgeAgentEnabled: e.target.checked}})} /> +
)} - - {/* Re-implementing just the AI tab content for context, assuming others are similar */} - {settingsTab === 'ai' && canManageTeam && ( + + {/* GENERAL (BRANDING) TAB */} + {settingsTab === 'general' && canManageGlobalSettings && ( +
+

Personalizzazione Branding

+
+ + setTempSettings({...tempSettings, branding: {...tempSettings.branding, appName: e.target.value}})} /> +
+
+ +
+ setTempSettings({...tempSettings, branding: {...tempSettings.branding, primaryColor: e.target.value}})} /> + setTempSettings({...tempSettings, branding: {...tempSettings.branding, primaryColor: e.target.value}})} /> +
+
+
+ + setTempSettings({...tempSettings, branding: {...tempSettings.branding, logoUrl: e.target.value}})} /> +
+
+ )} + + {/* AI CONFIG TAB */} + {settingsTab === 'ai' && canManageTeam && (

Integrazione AI

- {/* ... AI Inputs ... */} +
+ +
+

Configurazione Provider AI

+

Scegli il motore di intelligenza artificiale per l'assistente chat e l'analisi della KB.

+
+
+
@@ -806,23 +869,249 @@ export const AgentDashboard: React.FC = ({
- {/* ... key and model inputs ... */} + +
+
+ + setTempSettings({...tempSettings, aiConfig: {...tempSettings.aiConfig, model: e.target.value}})} + /> +
+
+ + setTempSettings({...tempSettings, aiConfig: {...tempSettings.aiConfig, baseUrl: e.target.value}})} + /> +
+
+ + {/* API KEY FIELD */}
setTempSettings({...tempSettings, aiConfig: {...tempSettings.aiConfig, apiKey: e.target.value}})} /> +

La chiave non verrà mostrata in chiaro dopo il salvataggio.

)} + + {/* USERS TAB */} + {settingsTab === 'users' && canManageTeam && ( +
+
+

Gestione Utenti Frontend

+ +
+ +
+

{editingUser ? 'Modifica Utente' : 'Aggiungi Nuovo Utente'}

+
+ setNewUserForm({...newUserForm, name: e.target.value})} /> + setNewUserForm({...newUserForm, email: e.target.value})} /> + setNewUserForm({...newUserForm, company: e.target.value})} /> + +
+
+ {editingUser && } + +
+
+ +
+ + + + {clientUsers.map(user => ( + + + + + + + + ))} + +
NomeEmailAziendaStatoAzioni
{user.name}{user.email}{user.company || '-'}{user.status} + + + +
+
+
+ )} + + {/* AGENTS TAB */} + {settingsTab === 'agents' && canManageTeam && ( +
+
+

Team di Supporto

+ {isAgentQuotaFull ? Quota Agenti Raggiunta : ( + + )} +
+ +
+

{editingAgent ? 'Modifica Profilo Agente' : 'Nuovo Membro del Team'}

+
+
+ handleAvatarSaved(img, cfg, !!editingAgent)} + /> +
+
+
+ setNewAgentForm({...newAgentForm, name: e.target.value})} /> + setNewAgentForm({...newAgentForm, email: e.target.value})} /> +
+
+ + setNewAgentForm({...newAgentForm, password: e.target.value})} /> +
+ +
+ +
+ {queues.map(q => ( + + ))} +
+
+ +
+ {editingAgent && } + +
+
+
+
+ +
+ {agents.map(agent => ( +
+
+ {agent.name} +
+
+
+

{agent.name}

+ {agent.role} +
+

{agent.email}

+
+ {agent.queues.map(q => {q})} +
+
+ + {agent.role !== 'superadmin' && } +
+
+
+ ))} +
+
+ )} - {/* ... other tabs ... */} + {/* QUEUES TAB */} + {settingsTab === 'queues' && canManageTeam && ( +
+

Code di Smistamento

+
+
+ + setNewQueueForm({...newQueueForm, name: e.target.value})} /> +
+
+ + setNewQueueForm({...newQueueForm, description: e.target.value})} /> +
+ +
+ +
+ {queues.map(q => ( +
+
+

+ + {q.name} +

+

{q.description}

+
+ +
+ ))} +
+
+ )} - {/* Save Button */} + {settingsTab === 'email' && canManageGlobalSettings && ( +
+

Configurazione SMTP

+
+
+ + setTempSettings({...tempSettings, smtp: {...tempSettings.smtp, host: e.target.value}})} /> +
+
+ + setTempSettings({...tempSettings, smtp: {...tempSettings.smtp, port: parseInt(e.target.value)}})} /> +
+
+ + setTempSettings({...tempSettings, smtp: {...tempSettings.smtp, user: e.target.value}})} /> +
+
+ + setTempSettings({...tempSettings, smtp: {...tempSettings.smtp, pass: e.target.value}})} /> +
+
+
+ +
+
+ )} + {settingsTab !== 'users' && settingsTab !== 'agents' && settingsTab !== 'queues' && (
- ))} + ); + })} - {/* Archive button */} -
+ +
+
Storico
@@ -877,19 +1177,82 @@ export const AgentDashboard: React.FC = ({ {/* COLUMN 2: TICKET LIST */}
- {/* ... Ticket list rendering ... */} +
+

+ {isViewingArchive ? 'Archivio Ticket' : selectedQueue ? selectedQueue : 'Seleziona Coda'} +

+ {filteredTickets.length} ticket +
- {filteredTickets.map(ticket => ( + {filteredTickets.length === 0 ? ( +
+
+ {isViewingArchive ? : } +
+

Nessun ticket {isViewingArchive ? 'in archivio' : 'in questa coda'}.

+
+ ) : ( + filteredTickets.map(ticket => (
setSelectedTicketId(ticket.id)} className={`p-4 border-b border-gray-100 cursor-pointer hover:bg-blue-50 transition relative group ${selectedTicketId === ticket.id ? 'bg-blue-50 border-l-4 border-brand-500' : ''}`} > - {/* Ticket Item Content */} +
+ {/* Agent Quick Assign - Only for Active Tickets */} + {!isViewingArchive && ( +
e.stopPropagation()}> + + +
+ )} + + {/* Status Quick Change */} +
e.stopPropagation()}> + +
+ +
+
+
+ +
+ {ticket.id} + {ticket.priority} +

{ticket.subject}

{ticket.customerName} • {ticket.status}

+
+ {ticket.attachments && ticket.attachments.length > 0 && ( +
+ + {ticket.attachments.length} +
+ )} + {ticket.createdAt.split('T')[0]} +
- ))} + )) + )}
@@ -900,19 +1263,52 @@ export const AgentDashboard: React.FC = ({

{selectedTicket.subject}

- {/* ... Header details ... */} +
+ {selectedTicket.customerName} + + {selectedTicket.createdAt.split('T')[0]} + + {selectedTicket.queue} +
+
+
+ +
- {/* ... Status controls ... */}

{selectedTicket.description}

- {/* Attachments */} + {/* Attachments Section */} {selectedTicket.attachments && selectedTicket.attachments.length > 0 && (
- {/* ... Attachment list ... */} +

+ Allegati +

+
+ {selectedTicket.attachments.map(att => ( +
+ + {att.name} +
+ ))} +
)} @@ -930,7 +1326,6 @@ export const AgentDashboard: React.FC = ({ )}
- {/* CHAT INPUT AREA - FIXED */}