diff --git a/src/app/globals.css b/src/app/globals.css index 76a6741..836fec6 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -154,6 +154,11 @@ } @layer components { + /* Tippy.js (menções do editor) */ + .tippy-box { + @apply rounded-lg border border-slate-200 bg-white shadow-lg; + } + .tippy-content { @apply p-0; } /* Tipografia básica para conteúdos rich text (Tiptap) */ .rich-text { @apply text-foreground; diff --git a/src/app/tickets/new/page.tsx b/src/app/tickets/new/page.tsx index 3777c0e..8a39268 100644 --- a/src/app/tickets/new/page.tsx +++ b/src/app/tickets/new/page.tsx @@ -28,7 +28,7 @@ import { CategorySelectFields } from "@/components/tickets/category-select" export default function NewTicketPage() { const router = useRouter() - const { convexUserId, isStaff } = useAuth() + const { convexUserId, isStaff, role } = useAuth() const queuesEnabled = Boolean(isStaff && convexUserId) const queueArgs = queuesEnabled ? { tenantId: DEFAULT_TENANT_ID, viewerId: convexUserId as Id<"users"> } @@ -79,6 +79,11 @@ export default function NewTicketPage() { if (hasChamados) setQueueName("Chamados") }, [queueOptions, queueName]) + const allowTicketMentions = useMemo(() => { + const normalized = (role ?? "").toLowerCase() + return normalized === "admin" || normalized === "agent" || normalized === "collaborator" + }, [role]) + async function submit(event: React.FormEvent) { event.preventDefault() if (!convexUserId || loading) return @@ -201,6 +206,7 @@ export default function NewTicketPage() { } }} placeholder="Detalhe o problema, passos para reproduzir, links, etc." + ticketMention={{ enabled: allowTicketMentions }} /> {descriptionError ?

{descriptionError}

: null} diff --git a/src/components/portal/portal-ticket-form.tsx b/src/components/portal/portal-ticket-form.tsx index d2254a6..a51cb8d 100644 --- a/src/components/portal/portal-ticket-form.tsx +++ b/src/components/portal/portal-ticket-form.tsx @@ -198,6 +198,7 @@ export function PortalTicketForm() { placeholder="Compartilhe passos para reproduzir, mensagens de erro ou informações adicionais." className="rounded-2xl border border-slate-200 shadow-sm focus-within:border-neutral-900 focus-within:ring-neutral-900/20" disabled={machineInactive || isSubmitting} + ticketMention={{ enabled: allowTicketMentions }} /> @@ -252,3 +253,4 @@ export function PortalTicketForm() { ) } + const allowTicketMentions = true diff --git a/src/components/tickets/new-ticket-dialog.tsx b/src/components/tickets/new-ticket-dialog.tsx index 436506a..c6f76bd 100644 --- a/src/components/tickets/new-ticket-dialog.tsx +++ b/src/components/tickets/new-ticket-dialog.tsx @@ -57,7 +57,7 @@ export function NewTicketDialog({ triggerClassName }: { triggerClassName?: strin }, mode: "onTouched", }) - const { convexUserId, isStaff } = useAuth() + const { convexUserId, isStaff, role } = useAuth() const queuesEnabled = Boolean(isStaff && convexUserId) const queueArgs = queuesEnabled ? { tenantId: DEFAULT_TENANT_ID, viewerId: convexUserId as Id<"users"> } @@ -297,6 +297,7 @@ export function NewTicketDialog({ triggerClassName }: { triggerClassName?: strin }) } placeholder="Detalhe o problema, passos para reproduzir, links, etc." + ticketMention={{ enabled: allowTicketMentions }} /> ) } + const allowTicketMentions = useMemo(() => { + const normalized = (role ?? "").toLowerCase() + return normalized === "admin" || normalized === "agent" || normalized === "collaborator" + }, [role]) diff --git a/src/components/ui/rich-text-editor.tsx b/src/components/ui/rich-text-editor.tsx index c68ddf4..96ad54a 100644 --- a/src/components/ui/rich-text-editor.tsx +++ b/src/components/ui/rich-text-editor.tsx @@ -16,6 +16,9 @@ import Placeholder from "@tiptap/extension-placeholder" import Mention from "@tiptap/extension-mention" import { ReactRenderer } from "@tiptap/react" import tippy, { type Instance, type Props as TippyProps } from "tippy.js" +// Nota: o CSS do Tippy não é obrigatório, mas melhora muito a renderização +// do popover de sugestões. O componente aplica um z-index alto e estratégia +// "fixed" para evitar problemas de sobreposição/scrolling mesmo sem CSS global. import { cn } from "@/lib/utils" import sanitize from "sanitize-html" import { Button } from "@/components/ui/button" @@ -357,6 +360,8 @@ const TicketMentionExtension = Mention.extend({ interactive: true, trigger: "manual", placement: "bottom-start", + zIndex: 99999, + popperOptions: { strategy: "fixed" }, }) }, onUpdate(props) {