- Adiciona tabela liveChatSessions no schema Convex - Cria convex/liveChat.ts com mutations e queries para chat - Adiciona API routes para maquinas (sessions, messages, poll) - Cria modulo chat.rs no Tauri com ChatRuntime e polling - Adiciona comandos de chat no lib.rs (start/stop polling, open/close window) - Cria componentes React do chat widget (ChatWidget, types) - Adiciona botao "Iniciar Chat" no dashboard (ticket-chat-panel) - Implementa menu de chat no system tray - Polling de 2 segundos para maior responsividade - Janela de chat flutuante, frameless, always-on-top 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
126 lines
3.6 KiB
TypeScript
126 lines
3.6 KiB
TypeScript
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"
|
|
|
|
const getMessagesSchema = z.object({
|
|
machineToken: z.string().min(1),
|
|
ticketId: z.string().min(1),
|
|
since: z.number().optional(),
|
|
limit: z.number().optional(),
|
|
})
|
|
|
|
const postMessageSchema = z.object({
|
|
machineToken: z.string().min(1),
|
|
ticketId: z.string().min(1),
|
|
body: z.string().min(1).max(4000),
|
|
attachments: z
|
|
.array(
|
|
z.object({
|
|
storageId: z.string(),
|
|
name: z.string(),
|
|
size: z.number().optional(),
|
|
type: z.string().optional(),
|
|
})
|
|
)
|
|
.optional(),
|
|
})
|
|
|
|
const CORS_METHODS = "POST, OPTIONS"
|
|
|
|
export async function OPTIONS(request: Request) {
|
|
return createCorsPreflight(request.headers.get("origin"), CORS_METHODS)
|
|
}
|
|
|
|
// POST /api/machines/chat/messages
|
|
// action=list: Lista mensagens de um chat
|
|
// action=send: Envia nova mensagem
|
|
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 raw
|
|
try {
|
|
raw = await request.json()
|
|
} catch {
|
|
return jsonWithCors({ error: "JSON invalido" }, 400, origin, CORS_METHODS)
|
|
}
|
|
|
|
const action = raw.action ?? "list"
|
|
|
|
if (action === "list") {
|
|
let payload
|
|
try {
|
|
payload = getMessagesSchema.parse(raw)
|
|
} catch (error) {
|
|
return jsonWithCors(
|
|
{ error: "Payload invalido", details: error instanceof Error ? error.message : String(error) },
|
|
400,
|
|
origin,
|
|
CORS_METHODS
|
|
)
|
|
}
|
|
|
|
try {
|
|
const result = await client.query(api.liveChat.listMachineMessages, {
|
|
machineToken: payload.machineToken,
|
|
ticketId: payload.ticketId as Id<"tickets">,
|
|
since: payload.since,
|
|
limit: payload.limit,
|
|
})
|
|
return jsonWithCors(result, 200, origin, CORS_METHODS)
|
|
} catch (error) {
|
|
console.error("[machines.chat.messages] Falha ao listar mensagens", error)
|
|
const details = error instanceof Error ? error.message : String(error)
|
|
return jsonWithCors({ error: "Falha ao listar mensagens", details }, 500, origin, CORS_METHODS)
|
|
}
|
|
}
|
|
|
|
if (action === "send") {
|
|
let payload
|
|
try {
|
|
payload = postMessageSchema.parse(raw)
|
|
} catch (error) {
|
|
return jsonWithCors(
|
|
{ error: "Payload invalido", details: error instanceof Error ? error.message : String(error) },
|
|
400,
|
|
origin,
|
|
CORS_METHODS
|
|
)
|
|
}
|
|
|
|
try {
|
|
const result = await client.mutation(api.liveChat.postMachineMessage, {
|
|
machineToken: payload.machineToken,
|
|
ticketId: payload.ticketId as Id<"tickets">,
|
|
body: payload.body,
|
|
attachments: payload.attachments as
|
|
| Array<{
|
|
storageId: Id<"_storage">
|
|
name: string
|
|
size?: number
|
|
type?: string
|
|
}>
|
|
| undefined,
|
|
})
|
|
return jsonWithCors(result, 200, origin, CORS_METHODS)
|
|
} catch (error) {
|
|
console.error("[machines.chat.messages] Falha ao enviar mensagem", error)
|
|
const details = error instanceof Error ? error.message : String(error)
|
|
return jsonWithCors({ error: "Falha ao enviar mensagem", details }, 500, origin, CORS_METHODS)
|
|
}
|
|
}
|
|
|
|
return jsonWithCors({ error: "Acao invalida" }, 400, origin, CORS_METHODS)
|
|
}
|