"use client" import { z } from "zod" import { useState } from "react" import type { Id } from "@/convex/_generated/dataModel" import type { TicketPriority, TicketQueueSummary } from "@/lib/schemas/ticket" import { useMutation, useQuery } from "convex/react" // @ts-ignore import { api } from "@/convex/_generated/api" import { DEFAULT_TENANT_ID } from "@/lib/constants" import { useAuth } from "@/lib/auth-client" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { FieldSet, FieldGroup, Field, FieldLabel, FieldError } from "@/components/ui/field" import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { toast } from "sonner" import { Spinner } from "@/components/ui/spinner" import { Dropzone } from "@/components/ui/dropzone" import { RichTextEditor } from "@/components/ui/rich-text-editor" import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { PriorityIcon, priorityBadgeClass, priorityItemClass, priorityStyles, priorityTriggerClass, } from "@/components/tickets/priority-select" const schema = z.object({ subject: z.string().min(3, "Informe um assunto"), summary: z.string().optional(), description: z.string().optional(), priority: z.enum(["LOW", "MEDIUM", "HIGH", "URGENT"]).default("MEDIUM"), channel: z.enum(["EMAIL", "WHATSAPP", "CHAT", "PHONE", "API", "MANUAL"]).default("MANUAL"), queueName: z.string().nullable().optional(), }) export function NewTicketDialog() { const [open, setOpen] = useState(false) const [loading, setLoading] = useState(false) const form = useForm>({ resolver: zodResolver(schema), defaultValues: { subject: "", summary: "", description: "", priority: "MEDIUM", channel: "MANUAL", queueName: null }, mode: "onTouched", }) const { userId } = useAuth() const queues = (useQuery(api.queues.summary, { tenantId: DEFAULT_TENANT_ID }) as TicketQueueSummary[] | undefined) ?? [] const create = useMutation(api.tickets.create) const addComment = useMutation(api.tickets.addComment) const [attachments, setAttachments] = useState>([]) const priorityValue = form.watch("priority") as TicketPriority const channelValue = form.watch("channel") const queueValue = form.watch("queueName") ?? "NONE" const selectTriggerClass = "flex h-8 w-full items-center justify-between rounded-full border border-slate-300 bg-white px-3 text-sm font-medium text-neutral-800 shadow-sm focus:ring-0 data-[state=open]:border-[#00d6eb]" const selectItemClass = "flex items-center gap-2 rounded-md px-2 py-2 text-sm text-neutral-800 transition data-[state=checked]:bg-[#00e8ff]/15 data-[state=checked]:text-neutral-900 focus:bg-[#00e8ff]/10" async function submit(values: z.infer) { if (!userId) return const subjectTrimmed = (values.subject ?? "").trim() if (subjectTrimmed.length < 3) { form.setError("subject", { type: "min", message: "Informe um assunto" }) return } setLoading(true) toast.loading("Criando ticket…", { id: "new-ticket" }) try { const sel = queues.find((q) => q.name === values.queueName) const id = await create({ tenantId: DEFAULT_TENANT_ID, subject: subjectTrimmed, summary: values.summary, priority: values.priority, channel: values.channel, queueId: sel?.id as Id<"queues"> | undefined, requesterId: userId as Id<"users">, }) const hasDescription = (values.description ?? "").replace(/<[^>]*>/g, "").trim().length > 0 const bodyHtml = hasDescription ? (values.description as string) : (values.summary || "") if (attachments.length > 0 || bodyHtml.trim().length > 0) { const typedAttachments = attachments.map((a) => ({ storageId: a.storageId as unknown as Id<"_storage">, name: a.name, size: a.size, type: a.type, })) await addComment({ ticketId: id as Id<"tickets">, authorId: userId as Id<"users">, visibility: "PUBLIC", body: bodyHtml, attachments: typedAttachments }) } toast.success("Ticket criado!", { id: "new-ticket" }) setOpen(false) form.reset() setAttachments([]) // Navegar para o ticket recém-criado window.location.href = `/tickets/${id}` } catch (err) { toast.error("Não foi possível criar o ticket.", { id: "new-ticket" }) } finally { setLoading(false) } } return ( Novo ticket Preencha as informações básicas para abrir um chamado.
Assunto Resumo