fix: automações (gatilhos, histórico) e chat desktop
This commit is contained in:
parent
8ab510bfe9
commit
e4d0c95791
7 changed files with 670 additions and 53 deletions
|
|
@ -4,7 +4,15 @@ import { openUrl as openExternal } from "@tauri-apps/plugin-opener"
|
|||
import { invoke } from "@tauri-apps/api/core"
|
||||
import { listen } from "@tauri-apps/api/event"
|
||||
import { Send, X, Loader2, MessageCircle, Paperclip, FileText, Image as ImageIcon, File, User, ChevronUp, Minimize2, Eye, Download, Check } from "lucide-react"
|
||||
import type { ChatAttachment, ChatMessage, ChatMessagesResponse, NewMessageEvent, SessionEndedEvent, UnreadUpdateEvent } from "./types"
|
||||
import type {
|
||||
ChatAttachment,
|
||||
ChatMessage,
|
||||
ChatMessagesResponse,
|
||||
NewMessageEvent,
|
||||
SessionEndedEvent,
|
||||
SessionStartedEvent,
|
||||
UnreadUpdateEvent,
|
||||
} from "./types"
|
||||
import { getMachineStoreConfig } from "./machineStore"
|
||||
|
||||
const MAX_MESSAGES_IN_MEMORY = 200 // Limite de mensagens para evitar memory leak
|
||||
|
|
@ -243,6 +251,7 @@ export function ChatWidget({ ticketId, ticketRef }: ChatWidgetProps) {
|
|||
const messagesContainerRef = useRef<HTMLDivElement>(null)
|
||||
const messageElementsRef = useRef<Map<string, HTMLDivElement>>(new Map())
|
||||
const prevHasSessionRef = useRef<boolean>(false)
|
||||
const retryDelayMsRef = useRef<number>(1_000)
|
||||
|
||||
const [isAtBottom, setIsAtBottom] = useState(true)
|
||||
const isAtBottomRef = useRef(true)
|
||||
|
|
@ -361,6 +370,7 @@ export function ChatWidget({ ticketId, ticketRef }: ChatWidgetProps) {
|
|||
}
|
||||
|
||||
setError(null)
|
||||
retryDelayMsRef.current = 1_000
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
setError(message || "Erro ao carregar mensagens.")
|
||||
|
|
@ -369,6 +379,22 @@ export function ChatWidget({ ticketId, ticketRef }: ChatWidgetProps) {
|
|||
}
|
||||
}, [ensureConfig, ticketId, ticketRef])
|
||||
|
||||
// Auto-retry leve quando houver erro (evita ficar "morto" após falha transiente).
|
||||
useEffect(() => {
|
||||
if (!error) return
|
||||
|
||||
const delayMs = retryDelayMsRef.current
|
||||
const timeout = window.setTimeout(() => {
|
||||
loadMessages()
|
||||
}, delayMs)
|
||||
|
||||
retryDelayMsRef.current = Math.min(retryDelayMsRef.current * 2, 30_000)
|
||||
|
||||
return () => {
|
||||
window.clearTimeout(timeout)
|
||||
}
|
||||
}, [error, loadMessages])
|
||||
|
||||
const markUnreadMessagesRead = useCallback(async () => {
|
||||
if (unreadCount <= 0) return
|
||||
const ids = getUnreadAgentMessageIds(messages, unreadCount)
|
||||
|
|
@ -420,6 +446,24 @@ export function ChatWidget({ ticketId, ticketRef }: ChatWidgetProps) {
|
|||
}
|
||||
}, [ticketId, loadMessages])
|
||||
|
||||
// Recarregar quando uma nova sessão iniciar (usuário pode estar com o chat aberto em "Offline")
|
||||
useEffect(() => {
|
||||
let unlisten: (() => void) | null = null
|
||||
listen<SessionStartedEvent>("raven://chat/session-started", (event) => {
|
||||
if (event.payload?.session?.ticketId === ticketId) {
|
||||
loadMessages()
|
||||
}
|
||||
})
|
||||
.then((u) => {
|
||||
unlisten = u
|
||||
})
|
||||
.catch((err) => console.error("Falha ao registrar listener session-started:", err))
|
||||
|
||||
return () => {
|
||||
unlisten?.()
|
||||
}
|
||||
}, [ticketId, loadMessages])
|
||||
|
||||
// Atualizar contador em tempo real (inclui decremento quando a máquina marca como lida)
|
||||
useEffect(() => {
|
||||
let unlisten: (() => void) | null = null
|
||||
|
|
@ -697,10 +741,15 @@ export function ChatWidget({ ticketId, ticketRef }: ChatWidgetProps) {
|
|||
// Mostrar chip compacto de erro (compativel com janela minimizada)
|
||||
return (
|
||||
<div className="pointer-events-none flex h-full w-full items-end justify-end bg-transparent p-2">
|
||||
<div className="pointer-events-auto flex items-center gap-2 rounded-full bg-red-100 px-4 py-2 text-red-600 shadow-lg">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => loadMessages()}
|
||||
className="pointer-events-auto flex items-center gap-2 rounded-full bg-red-100 px-4 py-2 text-red-600 shadow-lg transition hover:bg-red-200/60"
|
||||
title="Tentar novamente"
|
||||
>
|
||||
<X className="size-4" />
|
||||
<span className="text-sm font-medium">Erro no chat</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue