"use client" import { type ReactNode } from "react" import Link from "next/link" import { useQuery } from "convex/react" import { IconClockHour4, IconTrendingDown, IconTrendingUp } from "@tabler/icons-react" import { Area, AreaChart, CartesianGrid, XAxis } from "recharts" import { formatDistanceToNow } from "date-fns" import { ptBR } from "date-fns/locale" 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 { cn, formatDateDM, formatDateDMY, formatMinutesHuman } from "@/lib/utils" import { Badge } from "@/components/ui/badge" import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from "@/components/ui/card" import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart" import { Skeleton } from "@/components/ui/skeleton" type DashboardOverview = { newTickets?: { last24h: number; previous24h: number; trendPercentage: number | null } inProgress?: { current: number; previousSnapshot: number; trendPercentage: number | null } firstResponse?: { averageMinutes: number | null; deltaMinutes: number | null; responsesCount: number } awaitingAction?: { total: number; atRisk: number } resolution?: { resolvedLast7d: number; previousResolved: number; rate: number | null; deltaPercentage: number | null } } type QueueTrendResponse = { rangeDays: number queues: Array<{ id: string name: string openedTotal: number resolvedTotal: number series: Array<{ date: string; opened: number; resolved: number }> }> } const queueSparkConfig = { opened: { label: "Novos", color: "var(--chart-1)" }, resolved: { label: "Resolvidos", color: "var(--chart-2)" }, } const metricBadgeClass = "gap-1 rounded-full border-border/60 px-2.5 py-0.5 text-[11px] sm:px-3 sm:py-1 sm:text-xs" export function DashboardHero() { const { session, convexUserId, isStaff } = useAuth() const tenantId = session?.user.tenantId ?? DEFAULT_TENANT_ID const dashboardEnabled = Boolean(isStaff && convexUserId) const overview = useQuery( api.reports.dashboardOverview, dashboardEnabled ? { tenantId, viewerId: convexUserId as Id<"users"> } : "skip" ) as DashboardOverview | undefined const newTicketsTrend = overview?.newTickets ? { delta: overview.newTickets.trendPercentage, label: overview.newTickets.trendPercentage === null ? "Sem comparativo" : `${overview.newTickets.trendPercentage >= 0 ? "+" : ""}${overview.newTickets.trendPercentage.toFixed(1)}% vs. 24h anteriores`, } : null const inProgressTrend = overview?.inProgress ? { delta: overview.inProgress.trendPercentage, label: overview.inProgress.trendPercentage === null ? "Sem histórico" : `${overview.inProgress.trendPercentage >= 0 ? "+" : ""}${overview.inProgress.trendPercentage.toFixed(1)}% vs. última medição`, } : null const responseDelta = overview?.firstResponse ? (() => { const delta = overview.firstResponse.deltaMinutes if (delta === null) return { delta, label: "Sem comparação" } return { delta, label: `${delta > 0 ? "+" : ""}${delta.toFixed(1)} min` } })() : null const resolutionInfo = overview?.resolution ? { delta: overview.resolution.deltaPercentage ?? null, label: overview.resolution.deltaPercentage === null ? "Sem histórico" : `${overview.resolution.deltaPercentage >= 0 ? "+" : ""}${overview.resolution.deltaPercentage.toFixed(1)}%`, rateLabel: overview.resolution.rate !== null ? `${overview.resolution.rate.toFixed(1)}% dos tickets resolvidos` : "Taxa indisponível", } : { delta: null, label: "Sem histórico", rateLabel: "Taxa indisponível" } const newTicketsFooter = (() => { if (!newTicketsTrend) return "Aguardando dados" if (newTicketsTrend.delta === null) return "Sem comparativo recente" return newTicketsTrend.delta >= 0 ? "Acima das 24h anteriores" : "Abaixo das 24h anteriores" })() const inProgressFooter = (() => { if (!inProgressTrend) return "Monitoramento aguardando histórico" if (inProgressTrend.delta === null) return "Sem histórico recente" return inProgressTrend.delta >= 0 ? "Acima da última medição" : "Abaixo da última medição" })() const responseFooter = (() => { if (!responseDelta) return "Sem dados suficientes para comparação" if (responseDelta.delta === null) return "Sem comparação recente" return responseDelta.delta <= 0 ? "Melhor que a última medição" : "Pior que a última medição" })() const resolutionFooter = resolutionInfo?.rateLabel ?? "Taxa indisponível no momento." return (
{queue.name}
Última movimentação {lastUpdated ?? "—"}
Entraram
{queue.openedTotal}
Resolvidos
{queue.resolvedTotal}
{isLoading ?
de {isLoading ? "—" : data?.total ?? 0} tickets ativos