From f45ee91804fc78448e5a319a8d135390dece31de Mon Sep 17 00:00:00 2001 From: esdrasrenan Date: Sun, 7 Dec 2025 03:09:51 -0300 Subject: [PATCH] Fix chat widget UI and allow attachment-only messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Allow sending messages with only attachments (no text required) - Change "Chat Ativo" header to just "Chat" - Replace Headphones icon with MessageCircle for own messages - Replace PhoneOff icon with XCircle for end chat button 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- convex/tickets.ts | 24 ++++++++++++++---------- src/components/chat/chat-widget.tsx | 9 ++++----- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/convex/tickets.ts b/convex/tickets.ts index fe50efd..834a4d9 100644 --- a/convex/tickets.ts +++ b/convex/tickets.ts @@ -3178,14 +3178,17 @@ export const postChatMessage = mutation({ } const trimmedBody = body.replace(/\r\n/g, "\n").trim() - if (trimmedBody.length === 0) { - throw new ConvexError("Digite uma mensagem para enviar no chat") + const files = attachments ?? [] + + // Validar que há pelo menos texto ou anexo + if (trimmedBody.length === 0 && files.length === 0) { + throw new ConvexError("Digite uma mensagem ou anexe um arquivo") } if (trimmedBody.length > 4000) { throw new ConvexError("Mensagem muito longa (máx. 4000 caracteres)") } - const files = attachments ?? [] + // Validar anexos if (files.length > 5) { throw new ConvexError("Envie até 5 arquivos por mensagem") } @@ -3196,13 +3199,14 @@ export const postChatMessage = mutation({ } } - const normalizedBody = await normalizeTicketMentions(ctx, trimmedBody, { user: participant.user, role: participant.role ?? "" }, ticketDoc.tenantId) - const plainLength = plainTextLength(normalizedBody) - if (plainLength === 0) { - throw new ConvexError("A mensagem está vazia após a formatação") - } - if (plainLength > 4000) { - throw new ConvexError("Mensagem muito longa (máx. 4000 caracteres)") + // Normalizar corpo apenas se houver texto + let normalizedBody = "" + if (trimmedBody.length > 0) { + normalizedBody = await normalizeTicketMentions(ctx, trimmedBody, { user: participant.user, role: participant.role ?? "" }, ticketDoc.tenantId) + const plainLength = plainTextLength(normalizedBody) + if (plainLength > 4000) { + throw new ConvexError("Mensagem muito longa (máx. 4000 caracteres)") + } } const authorSnapshot: CommentAuthorSnapshot = { diff --git a/src/components/chat/chat-widget.tsx b/src/components/chat/chat-widget.tsx index f973276..14912a6 100644 --- a/src/components/chat/chat-widget.tsx +++ b/src/components/chat/chat-widget.tsx @@ -22,10 +22,9 @@ import { X, Minimize2, User, - Headphones, ChevronDown, WifiOff, - PhoneOff, + XCircle, Paperclip, FileText, Image as ImageIcon, @@ -428,7 +427,7 @@ export function ChatWidget() {
-

Chat Ativo

+

Chat

{/* Indicador online/offline */} {liveChat?.hasMachine && ( machineOnline ? ( @@ -464,7 +463,7 @@ export function ChatWidget() { {isEndingChat ? ( ) : ( - + )} Encerrar @@ -548,7 +547,7 @@ export function ChatWidget() { isOwn ? "bg-black text-white" : "bg-slate-200 text-slate-600" )} > - {isOwn ? : } + {isOwn ? : }