"use client"
import { useEffect, useMemo, useRef, useState } from "react"
import Link from "next/link"
import { formatDistanceToNow } from "date-fns"
import { ptBR } from "date-fns/locale"
import { useQuery } from "convex/react"
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { mapTicketsFromServerList } from "@/lib/mappers/ticket"
import type { Ticket } from "@/lib/schemas/ticket"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Skeleton } from "@/components/ui/skeleton"
import { TicketPriorityPill } from "@/components/tickets/priority-pill"
import { TicketStatusBadge } from "@/components/tickets/status-badge"
import { useAuth } from "@/lib/auth-client"
import { cn } from "@/lib/utils"
function TicketRow({ ticket, entering }: { ticket: Ticket; entering: boolean }) {
const queueLabel = ticket.queue ?? "Sem fila"
const requesterName = ticket.requester.name ?? ticket.requester.email ?? "Solicitante"
const categoryBadges = [ticket.category?.name, ticket.subcategory?.name].filter((value): value is string => Boolean(value))
const badgeClass =
"rounded-lg border border-slate-300 px-3.5 py-1.5 text-sm font-medium text-slate-600 transition-colors"
return (
#{ticket.reference}
{queueLabel}
{ticket.subject}
{ticket.summary ?? "Sem descrição informada."}
{requesterName}
•
{formatDistanceToNow(ticket.updatedAt, { addSuffix: true, locale: ptBR })}
{categoryBadges.length > 0 ? (
categoryBadges.map((label) => (
{label}
))
) : (
Sem categoria
)}
)
}
export function RecentTicketsPanel() {
const { convexUserId } = useAuth()
const ticketsArgs = convexUserId
? { tenantId: DEFAULT_TENANT_ID, viewerId: convexUserId as Id<"users">, limit: 12 }
: undefined
const ticketsResult = useQuery(convexUserId ? api.tickets.list : "skip", ticketsArgs)
const [enteringId, setEnteringId] = useState(null)
const previousIdsRef = useRef([])
const tickets = useMemo(() => {
if (!Array.isArray(ticketsResult)) return []
const all = mapTicketsFromServerList(ticketsResult as unknown[]).filter((t) => t.status !== "RESOLVED")
// Unassigned first (no assignee), oldest first among unassigned; then the rest by updatedAt desc
const unassigned = all
.filter((t) => !t.assignee)
.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())
const assigned = all
.filter((t) => !!t.assignee)
.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())
return [...unassigned, ...assigned].slice(0, 6)
}, [ticketsResult])
useEffect(() => {
if (!Array.isArray(ticketsResult)) {
previousIdsRef.current = []
return
}
const ids = tickets.map((ticket) => ticket.id)
const previous = previousIdsRef.current
if (!ids.length) {
previousIdsRef.current = ids
return
}
if (!previous.length) {
previousIdsRef.current = ids
return
}
const topId = ids[0]
if (!previous.includes(topId)) {
setEnteringId(topId)
}
previousIdsRef.current = ids
}, [tickets, ticketsResult])
useEffect(() => {
if (!enteringId) return
const timer = window.setTimeout(() => setEnteringId(null), 600)
return () => window.clearTimeout(timer)
}, [enteringId])
if (convexUserId && !Array.isArray(ticketsResult)) {
return (
Últimos chamados
{Array.from({ length: 4 }).map((_, index) => (
))}
)
}
return (
Últimos chamados
Ver todos
{tickets.length === 0 ? (
Nenhum ticket recente encontrado.
) : (
tickets.map((ticket) => (
))
)}
)
}