Ajusta auto-minimização do chat web e unifica realtime no desktop
This commit is contained in:
parent
c65e37e232
commit
3d45fe3b04
10 changed files with 279 additions and 635 deletions
77
src/app/api/machines/chat/read/route.ts
Normal file
77
src/app/api/machines/chat/read/route.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import { z } from "zod"
|
||||
|
||||
import { api } from "@/convex/_generated/api"
|
||||
import type { Id } from "@/convex/_generated/dataModel"
|
||||
import { createCorsPreflight, jsonWithCors } from "@/server/cors"
|
||||
import { createConvexClient, ConvexConfigurationError } from "@/server/convex-client"
|
||||
import { checkRateLimit, RATE_LIMITS, rateLimitHeaders } from "@/server/rate-limit"
|
||||
|
||||
const readSchema = z.object({
|
||||
machineToken: z.string().min(1),
|
||||
ticketId: z.string().min(1),
|
||||
messageIds: z.array(z.string().min(1)).min(1).max(50),
|
||||
})
|
||||
|
||||
const CORS_METHODS = "POST, OPTIONS"
|
||||
|
||||
export async function OPTIONS(request: Request) {
|
||||
return createCorsPreflight(request.headers.get("origin"), CORS_METHODS)
|
||||
}
|
||||
|
||||
// POST /api/machines/chat/read
|
||||
// Marca mensagens do chat como lidas pela maquina (zera unreadByMachine na sessao ativa)
|
||||
export async function POST(request: Request) {
|
||||
const origin = request.headers.get("origin")
|
||||
|
||||
let client
|
||||
try {
|
||||
client = createConvexClient()
|
||||
} catch (error) {
|
||||
if (error instanceof ConvexConfigurationError) {
|
||||
return jsonWithCors({ error: error.message }, 500, origin, CORS_METHODS)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
|
||||
let payload
|
||||
try {
|
||||
const raw = await request.json()
|
||||
payload = readSchema.parse(raw)
|
||||
} catch (error) {
|
||||
return jsonWithCors(
|
||||
{ error: "Payload invalido", details: error instanceof Error ? error.message : String(error) },
|
||||
400,
|
||||
origin,
|
||||
CORS_METHODS
|
||||
)
|
||||
}
|
||||
|
||||
const rateLimit = checkRateLimit(
|
||||
`chat-read:${payload.machineToken}`,
|
||||
RATE_LIMITS.CHAT_MESSAGES.maxRequests,
|
||||
RATE_LIMITS.CHAT_MESSAGES.windowMs
|
||||
)
|
||||
if (!rateLimit.allowed) {
|
||||
return jsonWithCors(
|
||||
{ error: "Rate limit exceeded", retryAfterMs: rateLimit.retryAfterMs },
|
||||
429,
|
||||
origin,
|
||||
CORS_METHODS,
|
||||
rateLimitHeaders(rateLimit)
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await client.mutation(api.liveChat.markMachineMessagesRead, {
|
||||
machineToken: payload.machineToken,
|
||||
ticketId: payload.ticketId as Id<"tickets">,
|
||||
messageIds: payload.messageIds as unknown as Id<"ticketChatMessages">[],
|
||||
})
|
||||
return jsonWithCors(result, 200, origin, CORS_METHODS, rateLimitHeaders(rateLimit))
|
||||
} catch (error) {
|
||||
console.error("[machines.chat.read] Falha ao marcar mensagens como lidas", error)
|
||||
const details = error instanceof Error ? error.message : String(error)
|
||||
return jsonWithCors({ error: "Falha ao marcar mensagens como lidas", details }, 500, origin, CORS_METHODS)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,17 +382,24 @@ export function ChatWidget() {
|
|||
|
||||
// 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) {
|
||||
setIsOpen(true)
|
||||
setIsMinimized(false)
|
||||
// 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
|
||||
|
||||
if (!isOpen) {
|
||||
setIsOpen(true)
|
||||
setIsMinimized(!hasUnreadForAgent)
|
||||
} else if (isMinimized && hasUnreadForAgent) {
|
||||
setIsMinimized(false)
|
||||
}
|
||||
if (newestSession) {
|
||||
setActiveTicketId(newestSession.ticketId)
|
||||
}
|
||||
}
|
||||
|
||||
prevSessionCountRef.current = currentCount
|
||||
}, [activeSessions])
|
||||
}, [activeSessions, isOpen, isMinimized])
|
||||
|
||||
// Scroll para última mensagem
|
||||
useEffect(() => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue