feat: melhorias no sistema de chat ao vivo

- Chat do agente abre expandido automaticamente ao iniciar nova sessao
- Toasts fecham apos tempo fixo independente do foco da janela
- Janela de chat do desktop com transparencia (sem fundo branco)
- Chat reabre quando usuario abre o Raven (duplo clique no tray)
- Chat nao reabre sozinho com novas mensagens (apenas notificacao)
- Mensagem de toast simplificada: "Chat ao vivo iniciado"
- Reduz intervalo de polling SSE de 2s para 1s (mais responsivo)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Seu Nome 2025-12-08 11:06:01 -03:00
parent 3700ac9dad
commit 24dee5d5eb
9 changed files with 74 additions and 31 deletions

View file

@ -252,6 +252,7 @@ export function ChatWidget() {
const inputRef = useRef<HTMLTextAreaElement | null>(null)
const fileInputRef = useRef<HTMLInputElement | null>(null)
const dropAreaRef = useRef<HTMLDivElement | null>(null)
const prevSessionCountRef = useRef<number>(0)
// Buscar sessões de chat ativas do agente
const activeSessions = useQuery(
@ -285,6 +286,26 @@ export function ChatWidget() {
}
}, [activeTicketId, activeSessions])
// Auto-abrir widget quando uma nova sessão é iniciada
useEffect(() => {
if (!activeSessions) return
const currentCount = activeSessions.length
const prevCount = prevSessionCountRef.current
// Se aumentou o número de sessões, é uma nova sessão - abrir o widget expandido
if (currentCount > prevCount && prevCount >= 0) {
setIsOpen(true)
setIsMinimized(false)
// Selecionar a sessão mais recente (última da lista ou primeira se única)
const newestSession = activeSessions[activeSessions.length - 1] ?? activeSessions[0]
if (newestSession) {
setActiveTicketId(newestSession.ticketId)
}
}
prevSessionCountRef.current = currentCount
}, [activeSessions])
// Scroll para última mensagem
useEffect(() => {
if (messagesEndRef.current && isOpen && !isMinimized) {

View file

@ -133,9 +133,9 @@ export function TicketChatPanel({ ticketId }: TicketChatPanelProps) {
actorId: viewerId as Id<"users">,
})
if (result.isNew) {
toast.success("Chat ao vivo iniciado! O cliente será notificado.", { id: "live-chat" })
toast.success("Chat ao vivo iniciado", { id: "live-chat" })
} else {
toast.info("Já existe uma sessão de chat ativa.", { id: "live-chat" })
toast.info("Já existe uma sessão de chat ativa", { id: "live-chat" })
}
} catch (error: unknown) {
const message = error instanceof Error ? error.message : "Não foi possível iniciar o chat"

View file

@ -1,11 +1,11 @@
"use client"
import { useTheme } from "next-themes"
import { Toaster as Sonner, ToasterProps } from "sonner"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
"use client"
import { useTheme } from "next-themes"
import { Toaster as Sonner, ToasterProps } from "sonner"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
const baseClass =
"inline-flex w-auto min-w-0 items-center justify-center gap-2 self-center rounded-xl border border-black bg-black px-3 py-2 text-sm font-medium text-white shadow-lg"
const baseStyle = {
@ -23,6 +23,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
pauseWhenPageIsHidden={false}
toastOptions={{
className: baseClass,
style: baseStyle,
@ -44,6 +45,6 @@ const Toaster = ({ ...props }: ToasterProps) => {
{...props}
/>
)
}
export { Toaster }
}
export { Toaster }