feat: implementar relatórios de categorias e substituir seleção de período por picker visual

BREAKING CHANGE: Remove feature de seleção de período das preferências do usuário

  Alterações principais:

  - Adiciona sistema completo de relatórios por categoria
    - Cria página /relatorios/categorias com filtros e visualizações
    - Implementa tabela e gráfico de evolução mensal
    - Adiciona funcionalidade de exportação de dados
    - Cria skeleton otimizado para melhor UX de loading

  - Remove feature de seleção de período das preferências
    - Deleta lib/user-preferences/period.ts
    - Remove colunas periodMonthsBefore e periodMonthsAfter do schema
    - Remove todas as referências em 16+ arquivos
    - Atualiza database schema via Drizzle

  - Substitui Select de período por MonthPicker visual
    - Implementa componente PeriodPicker reutilizável
    - Integra shadcn MonthPicker customizado (português, Remix icons)
    - Substitui createMonthOptions em todos os formulários
    - Mantém formato "YYYY-MM" no banco de dados

  - Melhora design da tabela de relatórios
    - Mescla colunas Categoria e Tipo em uma única coluna
    - Substitui badge de tipo por dot colorido discreto
    - Reduz largura da tabela em ~120px
    - Atualiza skeleton para refletir nova estrutura

  - Melhorias gerais de UI
    - Reduz espaçamento entre títulos da sidebar (p-2 → px-2 py-1)
    - Adiciona MonthNavigation para navegação entre períodos
    - Otimiza loading states com skeletons detalhados
This commit is contained in:
Felipe Coutinho
2026-01-04 03:03:09 +00:00
parent d192f47bc7
commit 4237062bde
54 changed files with 2987 additions and 472 deletions

View File

@@ -23,11 +23,10 @@ import {
} from "@/components/ui/select";
import { Separator } from "@/components/ui/separator";
import { Spinner } from "@/components/ui/spinner";
import { PeriodPicker } from "@/components/period-picker";
import { groupAndSortCategorias } from "@/lib/lancamentos/categoria-helpers";
import { LANCAMENTO_PAYMENT_METHODS } from "@/lib/lancamentos/constants";
import { getTodayDateString } from "@/lib/utils/date";
import { createMonthOptions } from "@/lib/utils/period";
import type { PeriodPreferences } from "@/lib/user-preferences/period";
import { RiAddLine, RiDeleteBinLine } from "@remixicon/react";
import { useMemo, useState } from "react";
import { toast } from "sonner";
@@ -52,7 +51,6 @@ interface MassAddDialogProps {
categoriaOptions: SelectOption[];
estabelecimentos: string[];
selectedPeriod: string;
periodPreferences: PeriodPreferences;
defaultPagadorId?: string | null;
}
@@ -93,7 +91,6 @@ export function MassAddDialog({
categoriaOptions,
estabelecimentos,
selectedPeriod,
periodPreferences,
defaultPagadorId,
}: MassAddDialogProps) {
const [loading, setLoading] = useState(false);
@@ -120,17 +117,6 @@ export function MassAddDialog({
},
]);
// Period options
const periodOptions = useMemo(
() =>
createMonthOptions(
selectedPeriod,
periodPreferences.monthsBefore,
periodPreferences.monthsAfter
),
[selectedPeriod, periodPreferences.monthsBefore, periodPreferences.monthsAfter]
);
// Categorias agrupadas e filtradas por tipo de transação
const groupedCategorias = useMemo(() => {
const filtered = categoriaOptions.filter(
@@ -336,18 +322,11 @@ export function MassAddDialog({
{/* Period */}
<div className="space-y-2">
<Label htmlFor="period">Período</Label>
<Select value={period} onValueChange={setPeriod}>
<SelectTrigger id="period" className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{periodOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
<PeriodPicker
value={period}
onChange={setPeriod}
className="w-full truncate"
/>
</div>
{/* Conta/Cartao */}