From 082f2d67f17cbcd7bb7ea89260de6ffd36a247c1 Mon Sep 17 00:00:00 2001 From: rever-tecnologia Date: Thu, 11 Dec 2025 15:48:33 -0300 Subject: [PATCH] fix: corrige sincronizacao de estado do chat entre abas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O BroadcastChannel nao estava funcionando corretamente porque cada aba restaurava do localStorage independentemente na montagem. Mudanca: - Substituido BroadcastChannel pelo evento 'storage' do localStorage - O evento storage dispara automaticamente em TODAS as outras abas quando o localStorage e alterado (mais confiavel) - Removido broadcastChannelRef e CHAT_WIDGET_CHANNEL nao mais usados Comportamento: - Abrir/fechar/minimizar chat em uma aba sincroniza com todas as outras - Estado persiste entre reloads via localStorage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/components/chat/chat-widget.tsx | 44 +++++++++++++---------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/components/chat/chat-widget.tsx b/src/components/chat/chat-widget.tsx index f7922b4..a3b024d 100644 --- a/src/components/chat/chat-widget.tsx +++ b/src/components/chat/chat-widget.tsx @@ -38,7 +38,6 @@ import { const MAX_MESSAGE_LENGTH = 4000 const MAX_ATTACHMENT_SIZE = 5 * 1024 * 1024 // 5MB const MAX_ATTACHMENTS = 5 -const CHAT_WIDGET_CHANNEL = "chat-widget-sync" const STORAGE_KEY = "chat-widget-state" type ChatWidgetState = { @@ -281,7 +280,6 @@ export function ChatWidget() { return null }) const [draft, setDraft] = useState("") - const broadcastChannelRef = useRef(null) const [isSending, setIsSending] = useState(false) const [isEndingChat, setIsEndingChat] = useState(false) const [attachments, setAttachments] = useState([]) @@ -320,31 +318,32 @@ export function ChatWidget() { const machineOnline = liveChat?.machineOnline ?? false const machineHostname = liveChat?.machineHostname - // Sincronizar estado entre abas usando BroadcastChannel + // Sincronizar estado entre abas usando evento storage do localStorage + // O evento storage dispara automaticamente em TODAS as outras abas quando localStorage muda useEffect(() => { if (typeof window === "undefined") return - // Criar canal de broadcast - const channel = new BroadcastChannel(CHAT_WIDGET_CHANNEL) - broadcastChannelRef.current = channel + const handleStorageChange = (event: StorageEvent) => { + // Ignorar mudancas em outras chaves + if (event.key !== STORAGE_KEY) return + // Ignorar se nao tem valor novo + if (!event.newValue) return - // Ouvir mensagens de outras abas - channel.onmessage = (event: MessageEvent) => { - const state = event.data - setIsOpen(state.isOpen) - setIsMinimized(state.isMinimized) - if (state.activeTicketId) { - setActiveTicketId(state.activeTicketId) - } + try { + const state = JSON.parse(event.newValue) as ChatWidgetState + setIsOpen(state.isOpen) + setIsMinimized(state.isMinimized) + if (state.activeTicketId) { + setActiveTicketId(state.activeTicketId) + } + } catch {} } - return () => { - channel.close() - broadcastChannelRef.current = null - } + window.addEventListener("storage", handleStorageChange) + return () => window.removeEventListener("storage", handleStorageChange) }, []) - // Salvar estado no localStorage e broadcast para outras abas quando muda + // Salvar estado no localStorage quando muda (dispara evento storage em outras abas) useEffect(() => { if (typeof window === "undefined") return @@ -354,15 +353,10 @@ export function ChatWidget() { activeTicketId, } - // Salvar no localStorage para persistir entre reloads + // Salvar no localStorage (isso dispara evento storage em outras abas automaticamente) try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)) } catch {} - - // Broadcast para outras abas - if (broadcastChannelRef.current) { - broadcastChannelRef.current.postMessage(state) - } }, [isOpen, isMinimized, activeTicketId]) // Auto-selecionar primeira sessão se nenhuma selecionada