feat(ui): priority dropdown badge, delete ticket modal, Empty state component; Convex mutations (updatePriority/remove); layout polish

- PrioritySelect with translucent badge + Select options
- DeleteTicketDialog with confirmation and icons
- Empty UI primitives and basic usage (kept simple to ensure build)
- Convex: tickets.updatePriority & tickets.remove
- Header: integrate priority select, delete action, avatar-rich assignee select
This commit is contained in:
esdrasrenan 2025-10-04 14:56:16 -03:00
parent ea60c3b841
commit 97ca2b3b54
5 changed files with 222 additions and 3 deletions

View file

@ -0,0 +1,61 @@
"use client"
import { useRouter } from "next/navigation"
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 { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogTrigger } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { AlertTriangle, Trash2 } from "lucide-react"
import { toast } from "sonner"
export function DeleteTicketDialog({ ticketId }: { ticketId: Id<"tickets"> }) {
const router = useRouter()
const remove = useMutation(api.tickets.remove)
const [open, setOpen] = useState(false)
const [loading, setLoading] = useState(false)
async function confirm() {
setLoading(true)
toast.loading("Excluindo ticket...", { id: "del" })
try {
await remove({ ticketId, actorId: undefined as unknown as Id<"users"> })
toast.success("Ticket excluído.", { id: "del" })
setOpen(false)
router.push("/tickets")
} catch {
toast.error("Não foi possível excluir o ticket.", { id: "del" })
} finally {
setLoading(false)
}
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="ghost" size="sm" className="gap-2 text-destructive hover:bg-destructive/10">
<Trash2 className="size-4" /> Excluir
</Button>
</DialogTrigger>
<DialogContent className="max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-destructive">
<AlertTriangle className="size-5" /> Excluir ticket
</DialogTitle>
<DialogDescription>
Esta ação é permanente e removerá o ticket, comentários e eventos associados. Deseja continuar?
</DialogDescription>
</DialogHeader>
<div className="flex justify-end gap-2 pt-2">
<Button variant="outline" onClick={() => setOpen(false)}>Cancelar</Button>
<Button variant="destructive" onClick={confirm} disabled={loading} className="gap-2">
{loading ? "Excluindo..." : (<><Trash2 className="size-4" /> Excluir</>)}
</Button>
</div>
</DialogContent>
</Dialog>
)
}