"use client" import { useMemo } from "react" import { useQuery } from "convex/react" import { IconAlertTriangle, IconGraph, IconClockHour4 } from "@tabler/icons-react" import { api } from "@/convex/_generated/api" import type { Id } from "@/convex/_generated/dataModel" import { useAuth } from "@/lib/auth-client" import { DEFAULT_TENANT_ID } from "@/lib/constants" import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Skeleton } from "@/components/ui/skeleton" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { useState } from "react" function formatMinutes(value: number | null) { if (value === null) return "—" if (value < 60) return `${value.toFixed(0)} min` const hours = Math.floor(value / 60) const minutes = Math.round(value % 60) if (minutes === 0) return `${hours}h` return `${hours}h ${minutes}min` } export function SlaReport() { const [companyId, setCompanyId] = useState("all") const { session, convexUserId } = useAuth() const tenantId = session?.user.tenantId ?? DEFAULT_TENANT_ID const data = useQuery( api.reports.slaOverview, convexUserId ? ({ tenantId, viewerId: convexUserId as Id<"users">, companyId: companyId === "all" ? undefined : (companyId as Id<"companies">) }) : "skip" ) const companies = useQuery(api.companies.list, convexUserId ? { tenantId, viewerId: convexUserId as Id<"users"> } : "skip") as Array<{ id: Id<"companies">; name: string }> | undefined const queueTotal = useMemo( () => data?.queueBreakdown.reduce((acc: number, queue: { open: number }) => acc + queue.open, 0) ?? 0, [data] ) if (!data) { return (
{Array.from({ length: 4 }).map((_, index) => ( ))}
) } return (
Tickets abertos Chamados ativos acompanhados pelo SLA. {data.totals.open} Vencidos Tickets que ultrapassaram o prazo previsto. {data.totals.overdue} Tempo resposta médio Com base nos tickets respondidos. {formatMinutes(data.response.averageFirstResponseMinutes ?? null)}

{data.response.responsesRegistered} registros

Tempo resolução médio Chamados finalizados no período analisado. {formatMinutes(data.resolution.averageResolutionMinutes ?? null)}

{data.resolution.resolvedCount} resolvidos

Fila x Volume aberto Distribuição dos {queueTotal} tickets abertos por fila de atendimento.
{data.queueBreakdown.length === 0 ? (

Nenhuma fila com tickets ativos no momento.

) : (
    {data.queueBreakdown.map((queue: { id: string; name: string; open: number }) => (
  • {queue.name} {((queue.open / Math.max(queueTotal, 1)) * 100).toFixed(0)}% do volume aberto
    {queue.open} tickets
  • ))}
)}
) }