Otimizações de performance e correções no chat ao vivo
- Corrigir acentuações (sessão, sessões, duração) - Auto-minimizar chat nativo quando sessão termina - Corrigir race condition em markMachineMessagesRead (Promise.all) - Adicionar paginação no cron autoEndInactiveSessions (.take(50)) - Otimizar listMachineMessages com limite de 100 mensagens - Corrigir memory leak no ChatWidget (limite de 200 mensagens) - Exibir estado offline quando não há sessão ativa 🤖 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
115c5128a6
commit
0e0bd9a49c
3 changed files with 88 additions and 44 deletions
|
|
@ -8,6 +8,7 @@ import { Send, X, Loader2, MessageCircle, Paperclip, FileText, Image as ImageIco
|
|||
import type { ChatMessage, ChatMessagesResponse, SendMessageResponse } from "./types"
|
||||
|
||||
const STORE_FILENAME = "machine-agent.json"
|
||||
const MAX_MESSAGES_IN_MEMORY = 200 // Limite de mensagens para evitar memory leak
|
||||
|
||||
// Tipos de arquivo permitidos
|
||||
const ALLOWED_EXTENSIONS = [
|
||||
|
|
@ -52,6 +53,7 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
const messagesEndRef = useRef<HTMLDivElement>(null)
|
||||
const lastFetchRef = useRef<number>(0)
|
||||
const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
const hadSessionRef = useRef<boolean>(false)
|
||||
|
||||
// Scroll para o final quando novas mensagens chegam
|
||||
const scrollToBottom = useCallback(() => {
|
||||
|
|
@ -62,6 +64,14 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
scrollToBottom()
|
||||
}, [messages, scrollToBottom])
|
||||
|
||||
// Auto-minimizar quando a sessão termina (hasSession muda de true para false)
|
||||
useEffect(() => {
|
||||
if (hadSessionRef.current && !hasSession) {
|
||||
setIsMinimized(true)
|
||||
}
|
||||
hadSessionRef.current = hasSession
|
||||
}, [hasSession])
|
||||
|
||||
// Carregar configuracao do store
|
||||
const loadConfig = useCallback(async () => {
|
||||
try {
|
||||
|
|
@ -72,7 +82,7 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
const config = await store.get<{ apiBaseUrl: string }>("config")
|
||||
|
||||
if (!token || !config?.apiBaseUrl) {
|
||||
setError("Maquina nao registrada")
|
||||
setError("Máquina não registrada")
|
||||
setIsLoading(false)
|
||||
return null
|
||||
}
|
||||
|
|
@ -99,15 +109,17 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
|
||||
if (response.messages.length > 0) {
|
||||
if (since) {
|
||||
// Adicionar apenas novas mensagens
|
||||
// Adicionar apenas novas mensagens (com limite para evitar memory leak)
|
||||
setMessages(prev => {
|
||||
const existingIds = new Set(prev.map(m => m.id))
|
||||
const newMsgs = response.messages.filter(m => !existingIds.has(m.id))
|
||||
return [...prev, ...newMsgs]
|
||||
const combined = [...prev, ...newMsgs]
|
||||
// Manter apenas as últimas MAX_MESSAGES_IN_MEMORY mensagens
|
||||
return combined.slice(-MAX_MESSAGES_IN_MEMORY)
|
||||
})
|
||||
} else {
|
||||
// Primeira carga
|
||||
setMessages(response.messages)
|
||||
// Primeira carga (já limitada)
|
||||
setMessages(response.messages.slice(-MAX_MESSAGES_IN_MEMORY))
|
||||
}
|
||||
lastFetchRef.current = Math.max(...response.messages.map(m => m.createdAt))
|
||||
}
|
||||
|
|
@ -178,7 +190,9 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
if (prev.some(m => m.id === event.payload.message.id)) {
|
||||
return prev
|
||||
}
|
||||
return [...prev, event.payload.message]
|
||||
const combined = [...prev, event.payload.message]
|
||||
// Manter apenas as últimas MAX_MESSAGES_IN_MEMORY mensagens
|
||||
return combined.slice(-MAX_MESSAGES_IN_MEMORY)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -324,15 +338,23 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
)
|
||||
}
|
||||
|
||||
// Quando não há sessão, mostrar versão minimizada com indicador de offline
|
||||
if (!hasSession) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col items-center justify-center bg-white p-4">
|
||||
<p className="text-sm text-slate-500">Nenhuma sessao de chat ativa</p>
|
||||
<div className="flex h-screen flex-col items-center justify-end bg-transparent p-4">
|
||||
<div className="flex items-center gap-2 rounded-full bg-slate-200 px-4 py-2 text-slate-600 shadow-lg">
|
||||
<MessageCircle className="size-4" />
|
||||
<span className="text-sm font-medium">
|
||||
{ticketInfo ? `Chat #${ticketInfo.ref}` : "Chat"}
|
||||
</span>
|
||||
<span className="size-2 rounded-full bg-slate-400" />
|
||||
<span className="text-xs text-slate-500">Offline</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Versao minimizada (chip compacto igual web)
|
||||
// Versão minimizada (chip compacto igual web)
|
||||
if (isMinimized) {
|
||||
return (
|
||||
<div className="flex h-screen flex-col items-center justify-end bg-transparent p-4">
|
||||
|
|
@ -403,7 +425,7 @@ export function ChatWidget({ ticketId }: ChatWidgetProps) {
|
|||
Nenhuma mensagem ainda
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-slate-400">
|
||||
O agente iniciara a conversa em breve
|
||||
O agente iniciará a conversa em breve
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue