feat(ui,tickets): aplicar visual Rever (badges revertidas), header com play/pause, edição inline com cancelar, empty states e toasts centralizados; novas mutations Convex (updateSubject/updateSummary/toggleWork)

This commit is contained in:
esdrasrenan 2025-10-04 17:13:13 -03:00
parent 881bb7bfdd
commit 6c57c691f3
14 changed files with 512 additions and 307 deletions

View file

@ -0,0 +1,74 @@
"use client"
import { useState } from "react"
import { useMutation } from "convex/react"
// @ts-ignore
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import type { TicketStatus } from "@/lib/schemas/ticket"
import { useAuth } from "@/lib/auth-client"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Badge } from "@/components/ui/badge"
import { toast } from "sonner"
const labels: Record<TicketStatus, string> = {
NEW: "Novo",
OPEN: "Aberto",
PENDING: "Pendente",
ON_HOLD: "Em espera",
RESOLVED: "Resolvido",
CLOSED: "Fechado",
}
function badgeClass(s: TicketStatus) {
switch (s) {
case "OPEN":
return "bg-blue-100 text-blue-700"
case "PENDING":
return "bg-amber-100 text-amber-700"
case "ON_HOLD":
return "bg-purple-100 text-purple-700"
case "RESOLVED":
return "bg-emerald-100 text-emerald-700"
case "CLOSED":
return "bg-slate-100 text-slate-700"
default:
return "bg-slate-100 text-slate-700"
}
}
export function StatusSelect({ ticketId, value }: { ticketId: string; value: TicketStatus }) {
const updateStatus = useMutation(api.tickets.updateStatus)
const [status, setStatus] = useState<TicketStatus>(value)
const { userId } = useAuth()
return (
<Select
value={status}
onValueChange={async (val) => {
const prev = status
const next = val as TicketStatus
setStatus(next)
toast.loading("Atualizando status...", { id: "status" })
try {
if (!userId) throw new Error("No user")
await updateStatus({ ticketId: ticketId as unknown as Id<"tickets">, status: next, actorId: userId as Id<"users"> })
toast.success(`Status alterado para ${labels[next] ?? next}.`, { id: "status" })
} catch {
setStatus(prev)
toast.error("Não foi possível atualizar o status.", { id: "status" })
}
}}
>
<SelectTrigger className="h-7 w-[160px] border-transparent bg-muted/50 px-2">
<SelectValue>
<Badge className={`rounded-full px-2 py-0.5 ${badgeClass(status)}`}>{labels[status]}</Badge>
</SelectValue>
</SelectTrigger>
<SelectContent>
{(["NEW","OPEN","PENDING","ON_HOLD","RESOLVED","CLOSED"] as const).map((s) => (
<SelectItem key={s} value={s}>{labels[s as TicketStatus]}</SelectItem>
))}
</SelectContent>
</Select>
)
}