style: refresh ticket ui components

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
esdrasrenan 2025-10-04 20:13:06 -03:00
parent 5c16ab75a6
commit 744d5933d4
16 changed files with 718 additions and 650 deletions

View file

@ -11,72 +11,68 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Badge } from "@/components/ui/badge"
import { toast } from "sonner"
import { ArrowDown, ArrowRight, ArrowUp, ChevronsUp } from "lucide-react"
import { cn } from "@/lib/utils"
const labels: Record<TicketPriority, string> = {
LOW: "Baixa",
MEDIUM: "Média",
HIGH: "Alta",
URGENT: "Urgente",
const priorityStyles: Record<TicketPriority, { label: string; badgeClass: string }> = {
LOW: { label: "Baixa", badgeClass: "border border-slate-200 bg-slate-100 text-slate-700" },
MEDIUM: { label: "Média", badgeClass: "border border-slate-200 bg-[#dff1fb] text-[#0a4760]" },
HIGH: { label: "Alta", badgeClass: "border border-slate-200 bg-[#fde8d1] text-[#7d3b05]" },
URGENT: { label: "Urgente", badgeClass: "border border-slate-200 bg-[#fbd9dd] text-[#8b0f1c]" },
}
function badgeClass(p: TicketPriority) {
switch (p) {
case "URGENT":
return "bg-red-100 text-red-700"
case "HIGH":
return "bg-amber-100 text-amber-700"
case "MEDIUM":
return "bg-blue-100 text-blue-700"
default:
return "bg-slate-100 text-slate-700"
}
}
const triggerClass = "h-8 w-[160px] rounded-full border border-slate-300 bg-white px-3 text-left text-sm font-medium text-neutral-800 shadow-sm focus:ring-0 data-[state=open]:border-[#00d6eb]"
const itemClass = "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"
const iconClass = "size-4 text-neutral-700"
const baseBadgeClass = "inline-flex items-center gap-2 rounded-full px-3 py-0.5 text-xs font-semibold"
function PriorityIcon({ p }: { p: TicketPriority }) {
const cls = "size-3.5 text-cyan-600"
if (p === "LOW") return <ArrowDown className={cls} />
if (p === "MEDIUM") return <ArrowRight className={cls} />
if (p === "HIGH") return <ArrowUp className={cls} />
return <ChevronsUp className={cls} />
function PriorityIcon({ value }: { value: TicketPriority }) {
if (value === "LOW") return <ArrowDown className={iconClass} />
if (value === "MEDIUM") return <ArrowRight className={iconClass} />
if (value === "HIGH") return <ArrowUp className={iconClass} />
return <ChevronsUp className={iconClass} />
}
export function PrioritySelect({ ticketId, value }: { ticketId: string; value: TicketPriority }) {
const updatePriority = useMutation(api.tickets.updatePriority)
const [priority, setPriority] = useState<TicketPriority>(value)
const { userId } = useAuth()
return (
<Select
value={priority}
onValueChange={async (val) => {
const prev = priority
const next = val as TicketPriority
onValueChange={async (selected) => {
const previous = priority
const next = selected as TicketPriority
setPriority(next)
toast.loading("Atualizando prioridade...", { id: "prio" })
toast.loading("Atualizando prioridade...", { id: "priority" })
try {
if (!userId) throw new Error("No user")
if (!userId) throw new Error("missing user")
await updatePriority({ ticketId: ticketId as unknown as Id<"tickets">, priority: next, actorId: userId as Id<"users"> })
toast.success("Prioridade atualizada!", { id: "prio" })
toast.success("Prioridade atualizada!", { id: "priority" })
} catch {
setPriority(prev)
toast.error("Não foi possível atualizar a prioridade.", { id: "prio" })
setPriority(previous)
toast.error("Não foi possível atualizar a prioridade.", { id: "priority" })
}
}}
>
<SelectTrigger className="h-7 w-[140px] border-transparent bg-muted/50 px-2">
<SelectTrigger className={triggerClass}>
<SelectValue>
<Badge className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 ${badgeClass(priority)}`}>
<PriorityIcon p={priority} /> {labels[priority]}
<Badge className={cn(baseBadgeClass, priorityStyles[priority]?.badgeClass)}>
<PriorityIcon value={priority} />
{priorityStyles[priority]?.label ?? priority}
</Badge>
</SelectValue>
</SelectTrigger>
<SelectContent>
{(["LOW","MEDIUM","HIGH","URGENT"] as const).map((p) => (
<SelectItem key={p} value={p}>
<span className="inline-flex items-center gap-2"><PriorityIcon p={p} />{labels[p]}</span>
<SelectContent className="rounded-lg border border-slate-200 bg-white text-neutral-800 shadow-sm">
{(["LOW", "MEDIUM", "HIGH", "URGENT"] as const).map((option) => (
<SelectItem key={option} value={option} className={itemClass}>
<span className="inline-flex items-center gap-2">
<PriorityIcon value={option} />
{priorityStyles[option].label}
</span>
</SelectItem>
))}
</SelectContent>
</Select>
)
}