"use client"; import { RiFilter3Line, RiLineChartLine, RiPieChartLine, RiTable2, } from "@remixicon/react"; import { useRouter, useSearchParams } from "next/navigation"; import { useCallback, useMemo, useState, useTransition } from "react"; import { EmptyState } from "@/components/shared/empty-state"; import { CategoryReportSkeleton } from "@/components/shared/skeletons/category-report-skeleton"; import { Card } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import type { CategoryChartData } from "@/lib/relatorios/fetch-category-chart-data"; import type { CategoryReportData } from "@/lib/relatorios/types"; import { CategoryReportCards } from "./category-report-cards"; import { CategoryReportChart } from "./category-report-chart"; import { CategoryReportExport } from "./category-report-export"; import { CategoryReportFilters } from "./category-report-filters"; import { CategoryReportTable } from "./category-report-table"; import type { CategoryOption, FilterState } from "./types"; interface CategoryReportPageProps { initialData: CategoryReportData; categories: CategoryOption[]; initialFilters: FilterState; chartData: CategoryChartData; } export function CategoryReportPage({ initialData, categories, initialFilters, chartData, }: CategoryReportPageProps) { const router = useRouter(); const searchParams = useSearchParams(); const [isPending, startTransition] = useTransition(); const [filters, setFilters] = useState(initialFilters); const [data, setData] = useState(initialData); // Get active tab from URL or default to "table" const activeTab = searchParams.get("aba") || "table"; // Debounce timer const [debounceTimer, setDebounceTimer] = useState( null, ); const handleFiltersChange = useCallback( (newFilters: FilterState) => { setFilters(newFilters); // Clear existing timer if (debounceTimer) { clearTimeout(debounceTimer); } // Set new debounced timer (300ms) const timer = setTimeout(() => { startTransition(() => { // Build new URL with query params const params = new URLSearchParams(searchParams.toString()); params.set("inicio", newFilters.startPeriod); params.set("fim", newFilters.endPeriod); if (newFilters.selectedCategories.length > 0) { params.set("categorias", newFilters.selectedCategories.join(",")); } else { params.delete("categorias"); } // Preserve current tab const currentTab = searchParams.get("aba"); if (currentTab) { params.set("aba", currentTab); } // Navigate with new params (this will trigger server component re-render) router.push(`?${params.toString()}`, { scroll: false }); }); }, 300); setDebounceTimer(timer); }, [debounceTimer, router, searchParams], ); // Handle tab change const handleTabChange = useCallback( (value: string) => { const params = new URLSearchParams(searchParams.toString()); params.set("aba", value); router.push(`?${params.toString()}`, { scroll: false }); }, [router, searchParams], ); // Update data when initialData changes (from server) useMemo(() => { setData(initialData); }, [initialData]); // Check if no categories are available const hasNoCategories = categories.length === 0; // Check if no data in period const hasNoData = data.categories.length === 0 && !hasNoCategories; return (
{/* Filters */} } /> {/* Loading State */} {isPending && } {/* Empty States */} {!isPending && hasNoCategories && ( } /> )} {!isPending && !hasNoCategories && hasNoData && filters.selectedCategories.length === 0 && ( } /> )} {!isPending && !hasNoCategories && hasNoData && filters.selectedCategories.length > 0 && ( } /> )} {/* Tabs: Table and Chart */} {!isPending && !hasNoCategories && !hasNoData && ( Tabela Gráfico {/* Desktop Table */}
{/* Mobile Cards */}
)}
); }