Fix JSX block in detail (RTE + Dropzone), hide priority in detail for customers, use isCustomer and hide queue

This commit is contained in:
Esdras Renan 2025-10-14 22:42:37 -03:00
parent 3f49e349f7
commit 2a4bc486cf

View file

@ -17,7 +17,7 @@ import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Dropzone } from "@/components/ui/dropzone" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Dropzone } from "@/components/ui/dropzone"
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty" import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty"
import { Skeleton } from "@/components/ui/skeleton" import { Skeleton } from "@/components/ui/skeleton"
import { RichTextEditor } from "@/components/ui/textarea" // removed wrong import; RichTextEditor comes from rich-text-editor
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { sanitizeEditorHtml, RichTextEditor } from "@/components/ui/rich-text-editor" import { sanitizeEditorHtml, RichTextEditor } from "@/components/ui/rich-text-editor"
@ -67,7 +67,7 @@ interface PortalTicketDetailProps {
} }
export function PortalTicketDetail({ ticketId }: PortalTicketDetailProps) { export function PortalTicketDetail({ ticketId }: PortalTicketDetailProps) {
const { convexUserId, session } = useAuth() const { convexUserId, session, isCustomer } = useAuth()
const addComment = useMutation(api.tickets.addComment) const addComment = useMutation(api.tickets.addComment)
const [comment, setComment] = useState(""); const [attachments, setAttachments] = useState<Array<{ storageId: string; name: string; size?: number; type?: string }>>([]) const [comment, setComment] = useState(""); const [attachments, setAttachments] = useState<Array<{ storageId: string; name: string; size?: number; type?: string }>>([])
@ -159,14 +159,16 @@ export function PortalTicketDetail({ ticketId }: PortalTicketDetailProps) {
<Badge className="rounded-full bg-neutral-900 px-3 py-1 text-xs font-semibold uppercase text-white"> <Badge className="rounded-full bg-neutral-900 px-3 py-1 text-xs font-semibold uppercase text-white">
{statusLabel[ticket.status]} {statusLabel[ticket.status]}
</Badge> </Badge>
<Badge className={`rounded-full px-3 py-1 text-xs font-semibold uppercase ${priorityTone[ticket.priority]}`}> {!isCustomer ? (
{priorityLabel[ticket.priority]} <Badge className={`rounded-full px-3 py-1 text-xs font-semibold uppercase ${priorityTone[ticket.priority]}`}>
</Badge> {priorityLabel[ticket.priority]}
</Badge>
) : null}
</div> </div>
</div> </div>
</CardHeader> </CardHeader>
<CardContent className="grid gap-4 border-t border-slate-100 px-5 py-5 text-sm text-neutral-700 sm:grid-cols-2"> <CardContent className="grid gap-4 border-t border-slate-100 px-5 py-5 text-sm text-neutral-700 sm:grid-cols-2">
<DetailItem label="Fila" value={ticket.queue ?? "Sem fila"} /> {isCustomer ? null : <DetailItem label="Fila" value={ticket.queue ?? "Sem fila"} />}
<DetailItem label="Categoria" value={ticket.category?.name ?? "Não classificada"} /> <DetailItem label="Categoria" value={ticket.category?.name ?? "Não classificada"} />
<DetailItem label="Solicitante" value={ticket.requester.name} subtitle={ticket.requester.email} /> <DetailItem label="Solicitante" value={ticket.requester.name} subtitle={ticket.requester.email} />
{ticket.assignee ? ( {ticket.assignee ? (
@ -186,7 +188,28 @@ export function PortalTicketDetail({ ticketId }: PortalTicketDetailProps) {
</CardHeader> </CardHeader>
<CardContent className="space-y-6 px-5 pb-6"> <CardContent className="space-y-6 px-5 pb-6">
<form onSubmit={handleSubmit} className="space-y-3"> <form onSubmit={handleSubmit} className="space-y-3">
<label htmlFor="comment" className="text-sm font-medium text-neutral-800">\n Enviar uma mensagem para a equipe\n </label>\n <RichTextEditor\n value={comment}\n onChange={(html) => setComment(html)}\n placeholder="Descreva o que aconteceu, envie atualizações ou compartilhe novas informações."\n className="rounded-2xl border border-slate-200 shadow-sm focus-within:border-neutral-900 focus-within:ring-neutral-900/20"\n />\n <div>\n <Dropzone\n onUploaded={(files) => setAttachments((prev) => [...prev, ...files])}\n className="rounded-xl border border-dashed border-slate-300 bg-slate-50 px-3 py-4 text-sm text-neutral-600 shadow-inner"\n />\n <p className="mt-1 text-xs text-neutral-500">Máximo 10MB Até 5 arquivos</p>\n </div>\n <div className="flex justify-end">\n <Button type="submit" className="rounded-full bg-neutral-900 px-6 text-sm font-semibold text-white hover:bg-neutral-900/90">\n Enviar comentário\n </Button>\n </div>\n </form> <label htmlFor="comment" className="text-sm font-medium text-neutral-800">
Enviar uma mensagem para a equipe
</label>
<RichTextEditor
value={comment}
onChange={(html) => setComment(html)}
placeholder="Descreva o que aconteceu, envie atualizações ou compartilhe novas informações."
className="rounded-2xl border border-slate-200 shadow-sm focus-within:border-neutral-900 focus-within:ring-neutral-900/20"
/>
<div>
<Dropzone
onUploaded={(files) => setAttachments((prev) => [...prev, ...files])}
className="rounded-xl border border-dashed border-slate-300 bg-slate-50 px-3 py-4 text-sm text-neutral-600 shadow-inner"
/>
<p className="mt-1 text-xs text-neutral-500">Máximo 10MB Até 5 arquivos</p>
</div>
<div className="flex justify-end">
<Button type="submit" className="rounded-full bg-neutral-900 px-6 text-sm font-semibold text-white hover:bg-neutral-900/90">
Enviar comentário
</Button>
</div>
</form>
<div className="space-y-5"> <div className="space-y-5">
{ticket.comments.length === 0 ? ( {ticket.comments.length === 0 ? (