Fix chat session management and add floating widget
- Fix session sync: events now send complete ChatSession data instead of partial ChatSessionSummary, ensuring proper ticket/agent info display - Add session-ended event detection to remove closed sessions from client - Add ChatFloatingWidget component for in-app chat experience - Restrict endSession to ADMIN/MANAGER/AGENT roles only - Improve polling logic to detect new and ended sessions properly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e4f8f465de
commit
88a3b37f2f
5 changed files with 680 additions and 92 deletions
|
|
@ -322,102 +322,131 @@ impl ChatRuntime {
|
|||
Ok(result) => {
|
||||
last_checked_at = Some(chrono::Utc::now().timestamp_millis());
|
||||
|
||||
if result.has_active_sessions {
|
||||
// Verificar novas sessoes
|
||||
let prev_sessions: Vec<String> = {
|
||||
last_sessions.lock().iter().map(|s| s.session_id.clone()).collect()
|
||||
};
|
||||
// Buscar sessoes completas para ter dados corretos
|
||||
let current_sessions = if result.has_active_sessions {
|
||||
fetch_sessions(&base_clone, &token_clone).await.unwrap_or_default()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// Buscar detalhes das sessoes
|
||||
if let Ok(sessions) = fetch_sessions(&base_clone, &token_clone).await {
|
||||
for session in &sessions {
|
||||
if !prev_sessions.contains(&session.session_id) {
|
||||
// Nova sessao! Emitir evento
|
||||
crate::log_info!(
|
||||
"Nova sessao de chat: ticket={}",
|
||||
session.ticket_id
|
||||
);
|
||||
let _ = app.emit(
|
||||
"raven://chat/session-started",
|
||||
SessionStartedEvent {
|
||||
session: session.clone(),
|
||||
},
|
||||
);
|
||||
// Verificar sessoes anteriores
|
||||
let prev_sessions: Vec<ChatSession> = last_sessions.lock().clone();
|
||||
let prev_session_ids: Vec<String> = prev_sessions.iter().map(|s| s.session_id.clone()).collect();
|
||||
let current_session_ids: Vec<String> = current_sessions.iter().map(|s| s.session_id.clone()).collect();
|
||||
|
||||
// Enviar notificacao nativa do Windows
|
||||
// A janela de chat NAO abre automaticamente -
|
||||
// o usuario deve clicar na notificacao ou no tray
|
||||
let notification_title = format!(
|
||||
"Chat iniciado - Chamado #{}",
|
||||
session.ticket_ref
|
||||
);
|
||||
let notification_body = format!(
|
||||
"{} iniciou um chat de suporte.\nClique no icone do Raven para abrir.",
|
||||
session.agent_name
|
||||
);
|
||||
if let Err(e) = app
|
||||
.notification()
|
||||
.builder()
|
||||
.title(¬ification_title)
|
||||
.body(¬ification_body)
|
||||
.show()
|
||||
{
|
||||
crate::log_warn!(
|
||||
"Falha ao enviar notificacao: {e}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar cache
|
||||
*last_sessions.lock() = sessions;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// Detectar novas sessoes
|
||||
for session in ¤t_sessions {
|
||||
if !prev_session_ids.contains(&session.session_id) {
|
||||
// Nova sessao! Emitir evento
|
||||
crate::log_info!(
|
||||
"Chat: {} mensagens nao lidas (prev={})",
|
||||
result.total_unread,
|
||||
prev_unread
|
||||
"Nova sessao de chat: ticket={}, session={}",
|
||||
session.ticket_id,
|
||||
session.session_id
|
||||
);
|
||||
let _ = app.emit(
|
||||
"raven://chat/unread-update",
|
||||
serde_json::json!({
|
||||
"totalUnread": result.total_unread,
|
||||
"sessions": result.sessions
|
||||
}),
|
||||
"raven://chat/session-started",
|
||||
SessionStartedEvent {
|
||||
session: session.clone(),
|
||||
},
|
||||
);
|
||||
|
||||
// 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(¬ification_body)
|
||||
.show()
|
||||
{
|
||||
crate::log_warn!(
|
||||
"Falha ao enviar notificacao de nova mensagem: {e}"
|
||||
);
|
||||
}
|
||||
// NAO foca a janela automaticamente - usuario abre manualmente
|
||||
// Enviar notificacao nativa do Windows
|
||||
let notification_title = format!(
|
||||
"Chat iniciado - Chamado #{}",
|
||||
session.ticket_ref
|
||||
);
|
||||
let notification_body = format!(
|
||||
"{} iniciou um chat de suporte.\nClique no icone do Raven para abrir.",
|
||||
session.agent_name
|
||||
);
|
||||
if let Err(e) = app
|
||||
.notification()
|
||||
.builder()
|
||||
.title(¬ification_title)
|
||||
.body(¬ification_body)
|
||||
.show()
|
||||
{
|
||||
crate::log_warn!(
|
||||
"Falha ao enviar notificacao de nova sessao: {e}"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sem sessoes ativas
|
||||
*last_sessions.lock() = Vec::new();
|
||||
}
|
||||
|
||||
// Detectar sessoes encerradas
|
||||
for prev_session in &prev_sessions {
|
||||
if !current_session_ids.contains(&prev_session.session_id) {
|
||||
// Sessao foi encerrada! Emitir evento
|
||||
crate::log_info!(
|
||||
"Sessao de chat encerrada: ticket={}, session={}",
|
||||
prev_session.ticket_id,
|
||||
prev_session.session_id
|
||||
);
|
||||
let _ = app.emit(
|
||||
"raven://chat/session-ended",
|
||||
serde_json::json!({
|
||||
"sessionId": prev_session.session_id,
|
||||
"ticketId": prev_session.ticket_id
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar cache de sessoes
|
||||
*last_sessions.lock() = current_sessions.clone();
|
||||
|
||||
// Verificar mensagens nao lidas
|
||||
let prev_unread = *last_unread_count.lock();
|
||||
let new_messages = result.total_unread > prev_unread;
|
||||
*last_unread_count.lock() = result.total_unread;
|
||||
|
||||
// Sempre emitir unread-update com sessoes completas
|
||||
let _ = app.emit(
|
||||
"raven://chat/unread-update",
|
||||
serde_json::json!({
|
||||
"totalUnread": result.total_unread,
|
||||
"sessions": current_sessions
|
||||
}),
|
||||
);
|
||||
|
||||
// Notificar novas mensagens (quando aumentou)
|
||||
if new_messages && result.total_unread > 0 {
|
||||
let new_count = result.total_unread - prev_unread;
|
||||
|
||||
crate::log_info!(
|
||||
"Chat: {} novas mensagens (total={})",
|
||||
new_count,
|
||||
result.total_unread
|
||||
);
|
||||
|
||||
// Emitir evento para o frontend atualizar UI
|
||||
let _ = app.emit(
|
||||
"raven://chat/new-message",
|
||||
serde_json::json!({
|
||||
"totalUnread": result.total_unread,
|
||||
"newCount": new_count,
|
||||
"sessions": current_sessions
|
||||
}),
|
||||
);
|
||||
|
||||
// Enviar notificacao nativa do Windows
|
||||
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(¬ification_body)
|
||||
.show()
|
||||
{
|
||||
crate::log_warn!(
|
||||
"Falha ao enviar notificacao de nova mensagem: {e}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue