diff --git a/apps/desktop/src/chat/convexMachineClient.ts b/apps/desktop/src/chat/convexMachineClient.ts index b4e0c34..94a6879 100644 --- a/apps/desktop/src/chat/convexMachineClient.ts +++ b/apps/desktop/src/chat/convexMachineClient.ts @@ -98,69 +98,15 @@ export async function subscribeMachineUpdates( onError?: (error: Error) => void ): Promise<() => void> { const { client, token } = await ensureClient() - let stopped = false - let pollTimer: ReturnType | null = null - - const stopPoll = () => { - if (pollTimer) { - clearInterval(pollTimer) - pollTimer = null - } - } - - const startPoll = async () => { - stopPoll() - try { - const { apiBaseUrl } = await getMachineStoreConfig() - const poll = async () => { - try { - const res = await fetch(`${apiBaseUrl}/api/machines/chat/poll`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ machineToken: token }), - }) - if (!res.ok) throw new Error(`poll failed: ${res.status}`) - const data = (await res.json()) as MachineUpdatePayload - if (!stopped) callback(data) - } catch (err) { - if (!stopped) onError?.(err as Error) - } - } - await poll() - pollTimer = setInterval(poll, 4000) - } catch (err) { - onError?.(err as Error) - } - } const sub = client.onUpdate( FN_CHECK_UPDATES as unknown as FunctionReference<"query">, { machineToken: token }, - (value) => { - stopPoll() - callback(value) - }, - (err) => { - onError?.(err) - startPoll().catch(() => { - // erro já reportado via onError - }) - } + (value) => callback(value), + (err) => onError?.(err) ) - // fallback caso a inscrição falhe imediatamente - setTimeout(() => { - if (stopped) return - // Se não houver mensagens recebidas pelo WS em 3s, inicia polling - // (o callback do WS encerra o polling caso volte a funcionar) - startPoll().catch(() => { - // erro já reportado via onError - }) - }, 3000) - return () => { - stopped = true - stopPoll() sub.unsubscribe() } } @@ -171,53 +117,6 @@ export async function subscribeMachineMessages( onError?: (error: Error) => void ): Promise<() => void> { const { client, token } = await ensureClient() - let stopped = false - let pollTimer: ReturnType | null = null - let lastSince = 0 - - const stopPoll = () => { - if (pollTimer) { - clearInterval(pollTimer) - pollTimer = null - } - } - - const startPoll = async () => { - stopPoll() - try { - const { apiBaseUrl } = await getMachineStoreConfig() - const poll = async () => { - try { - const res = await fetch(`${apiBaseUrl}/api/machines/chat/messages`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - action: "list", - machineToken: token, - ticketId, - since: lastSince || undefined, - }), - }) - if (!res.ok) throw new Error(`messages poll failed: ${res.status}`) - const data = (await res.json()) as MessagesPayload - if (!stopped) { - callback(data) - const newest = (data.messages as ChatMessage[]).reduce( - (max: number, msg: ChatMessage) => Math.max(max, msg.createdAt), - lastSince - ) - lastSince = newest - } - } catch (err) { - if (!stopped) onError?.(err as Error) - } - } - await poll() - pollTimer = setInterval(poll, 4000) - } catch (err) { - onError?.(err as Error) - } - } const sub = client.onUpdate( FN_LIST_MESSAGES as unknown as FunctionReference<"query">, @@ -225,33 +124,11 @@ export async function subscribeMachineMessages( machineToken: token, ticketId, }, - (value) => { - stopPoll() - callback(value) - const newest = (value.messages as ChatMessage[]).reduce( - (max: number, msg: ChatMessage) => Math.max(max, msg.createdAt), - lastSince - ) - lastSince = newest - }, - (err) => { - onError?.(err) - startPoll().catch(() => { - // erro já reportado via onError - }) - } + (value) => callback(value), + (err) => onError?.(err) ) - setTimeout(() => { - if (stopped) return - startPoll().catch(() => { - // erro já reportado via onError - }) - }, 3000) - return () => { - stopped = true - stopPoll() sub.unsubscribe() } } diff --git a/src/components/tickets/ticket-chat-panel.tsx b/src/components/tickets/ticket-chat-panel.tsx index 7753113..b1d2ea2 100644 --- a/src/components/tickets/ticket-chat-panel.tsx +++ b/src/components/tickets/ticket-chat-panel.tsx @@ -179,6 +179,28 @@ export function TicketChatPanel({ ticketId }: TicketChatPanelProps) { toast.error(`Mensagem muito longa (max. ${MAX_MESSAGE_LENGTH} caracteres).`) return } + + // Garantir que a sessão de chat ao vivo exista antes de enviar + if (liveChat?.hasMachine && !hasActiveSession) { + try { + await startLiveChat({ + ticketId: ticketId as Id<"tickets">, + actorId: viewerId as Id<"users">, + }) + } catch (error: unknown) { + const message = (() => { + if (error instanceof Error) { + const errorMsg = error.message.toLowerCase() + if (errorMsg.includes("offline")) return "Máquina offline. Aguarde a máquina ficar online para iniciar o chat." + if (errorMsg.includes("não encontrad") || errorMsg.includes("not found")) return "Máquina não encontrada" + } + return "Não foi possível iniciar o chat ao vivo." + })() + toast.error(message, { id: "live-chat" }) + return + } + } + setIsSending(true) try { await postChatMessage({