fix(chat): melhora realtime e anexos no desktop

This commit is contained in:
esdrasrenan 2025-12-12 21:36:32 -03:00
parent 3d45fe3b04
commit 8cf13c43de
5 changed files with 603 additions and 141 deletions

View file

@ -58,7 +58,9 @@ type ChatSession = {
ticketRef: number
ticketSubject: string
sessionId: string
agentId: string
unreadCount: number
lastActivityAt: number
}
type UploadedFile = {
@ -242,8 +244,8 @@ export function ChatWidget() {
// pois o chat nativo do Tauri ja esta disponivel
const isTauriContext = typeof window !== "undefined" && "__TAURI__" in window
const { convexUserId } = useAuth()
const viewerId = convexUserId ?? null
const { convexUserId, isStaff } = useAuth()
const viewerId = isStaff ? (convexUserId ?? null) : null
// Inicializar estado a partir do localStorage (para persistir entre reloads)
const [isOpen, setIsOpen] = useState(() => {
@ -290,8 +292,8 @@ 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>(-1) // -1 indica "ainda nao inicializado"
const hasRestoredStateRef = useRef<boolean>(false) // Flag para evitar sobrescrever estado do localStorage
const hasInitializedSessionsRef = useRef(false)
const prevSessionIdsRef = useRef<Set<string>>(new Set())
// Buscar sessões de chat ativas do agente
const activeSessions = useQuery(
@ -366,40 +368,32 @@ export function ChatWidget() {
}
}, [activeTicketId, activeSessions])
// Auto-abrir widget quando uma nova sessão é iniciada (apenas para sessoes NOVAS, nao na montagem inicial)
// Auto-abrir o widget quando ESTE agente iniciar uma nova sessão de chat.
// Nao roda na montagem inicial para nao sobrescrever o estado do localStorage.
useEffect(() => {
if (!activeSessions) return
const currentCount = activeSessions.length
const prevCount = prevSessionCountRef.current
// Primeira execucao: apenas inicializar o ref, nao abrir automaticamente
// Isso preserva o estado do localStorage (se usuario tinha minimizado, mantem minimizado)
if (prevCount === -1) {
prevSessionCountRef.current = currentCount
hasRestoredStateRef.current = true
const currentIds = new Set(activeSessions.map((s) => s.sessionId))
if (!hasInitializedSessionsRef.current) {
prevSessionIdsRef.current = currentIds
hasInitializedSessionsRef.current = true
return
}
// Se aumentou o número de sessões APOS a montagem inicial, é uma nova sessão - abrir o widget expandido
if (currentCount > prevCount && hasRestoredStateRef.current) {
// O estado do widget e definido com base nas nao lidas.
// Selecionar a sessão mais recente (última da lista ou primeira se única)
const newestSession = activeSessions[activeSessions.length - 1] ?? activeSessions[0]
const hasUnreadForAgent = (newestSession?.unreadCount ?? 0) > 0
const newSessions = activeSessions.filter((s) => !prevSessionIdsRef.current.has(s.sessionId))
prevSessionIdsRef.current = currentIds
if (!isOpen) {
setIsOpen(true)
setIsMinimized(!hasUnreadForAgent)
} else if (isMinimized && hasUnreadForAgent) {
setIsMinimized(false)
}
if (newestSession) {
setActiveTicketId(newestSession.ticketId)
}
}
if (newSessions.length === 0) return
if (!viewerId) return
prevSessionCountRef.current = currentCount
}, [activeSessions, isOpen, isMinimized])
const mine = newSessions.find((s) => s.agentId === viewerId) ?? null
if (!mine) return
setIsOpen(true)
setIsMinimized(false)
setActiveTicketId(mine.ticketId)
}, [activeSessions, viewerId])
// Scroll para última mensagem
useEffect(() => {