Add chat widget improvements and chat history component

Widget improvements:
- Pulsating badge with unread message count on floating button
- Clickable ticket reference link in chat header
- ExternalLink icon on hover

Desktop (Raven) improvements:
- Track previous unread count for new message detection
- Send native Windows notifications for new messages
- Focus chat window when new messages arrive

Chat history:
- New query getTicketChatHistory for fetching chat sessions and messages
- New component TicketChatHistory displaying chat sessions
- Sessions can be expanded/collapsed to view messages
- Pagination support for long conversations
- Added to both dashboard and portal ticket views

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
esdrasrenan 2025-12-07 03:20:22 -03:00
parent b194d77d57
commit d766de4fda
6 changed files with 453 additions and 9 deletions

View file

@ -267,6 +267,7 @@ impl ChatPollerHandle {
pub struct ChatRuntime {
inner: Arc<Mutex<Option<ChatPollerHandle>>>,
last_sessions: Arc<Mutex<Vec<ChatSession>>>,
last_unread_count: Arc<Mutex<u32>>,
}
impl ChatRuntime {
@ -274,6 +275,7 @@ impl ChatRuntime {
Self {
inner: Arc::new(Mutex::new(None)),
last_sessions: Arc::new(Mutex::new(Vec::new())),
last_unread_count: Arc::new(Mutex::new(0)),
}
}
@ -301,6 +303,7 @@ impl ChatRuntime {
let base_clone = sanitized_base.clone();
let token_clone = token.clone();
let last_sessions = self.last_sessions.clone();
let last_unread_count = self.last_unread_count.clone();
let join_handle = tauri::async_runtime::spawn(async move {
crate::log_info!("Chat polling iniciado");
@ -379,10 +382,15 @@ impl ChatRuntime {
}
// Verificar mensagens nao lidas e emitir evento
let prev_unread = *last_unread_count.lock();
let new_messages = result.total_unread > prev_unread;
*last_unread_count.lock() = result.total_unread;
if result.total_unread > 0 {
crate::log_info!(
"Chat: {} mensagens nao lidas",
result.total_unread
"Chat: {} mensagens nao lidas (prev={})",
result.total_unread,
prev_unread
);
let _ = app.emit(
"raven://chat/unread-update",
@ -391,6 +399,37 @@ impl ChatRuntime {
"sessions": result.sessions
}),
);
// Notificar novas mensagens (apenas se aumentou)
if new_messages && prev_unread > 0 {
let new_count = result.total_unread - prev_unread;
let notification_title = "Nova mensagem de suporte";
let notification_body = if new_count == 1 {
"Voce recebeu 1 nova mensagem no chat".to_string()
} else {
format!("Voce recebeu {} novas mensagens no chat", new_count)
};
if let Err(e) = app
.notification()
.builder()
.title(notification_title)
.body(&notification_body)
.show()
{
crate::log_warn!(
"Falha ao enviar notificacao de nova mensagem: {e}"
);
}
// Focar janela de chat se existir
if let Some(session) = result.sessions.first() {
let label = format!("chat-{}", session.ticket_id);
if let Some(window) = app.get_webview_window(&label) {
let _ = window.show();
let _ = window.set_focus();
}
}
}
}
} else {
// Sem sessoes ativas