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:
91
components/period-picker.tsx
Normal file
91
components/period-picker.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { MonthPicker } from "@/components/ui/monthpicker";
|
||||
import { RiCalendarLine } from "@remixicon/react";
|
||||
import { useState } from "react";
|
||||
import { format } from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import { cn } from "@/lib/utils/ui";
|
||||
|
||||
interface PeriodPickerProps {
|
||||
value: string; // "YYYY-MM" format
|
||||
onChange: (value: string) => void;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
variant?: "default" | "outline" | "ghost";
|
||||
size?: "default" | "sm" | "lg";
|
||||
}
|
||||
|
||||
export function PeriodPicker({
|
||||
value,
|
||||
onChange,
|
||||
disabled = false,
|
||||
className,
|
||||
placeholder = "Selecione o período",
|
||||
variant = "outline",
|
||||
size = "default",
|
||||
}: PeriodPickerProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
// Convert period string (YYYY-MM) to Date object
|
||||
const periodToDate = (period: string): Date => {
|
||||
const [year, month] = period.split("-").map(Number);
|
||||
return new Date(year, month - 1, 1);
|
||||
};
|
||||
|
||||
// Convert Date object to period string (YYYY-MM)
|
||||
const dateToPeriod = (date: Date): string => {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
return `${year}-${month}`;
|
||||
};
|
||||
|
||||
// Format date for display
|
||||
const formatDisplay = (period: string): string => {
|
||||
try {
|
||||
const date = periodToDate(period);
|
||||
return format(date, "MMMM yyyy", { locale: ptBR });
|
||||
} catch {
|
||||
return placeholder;
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelect = (date: Date) => {
|
||||
const period = dateToPeriod(date);
|
||||
onChange(period);
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={variant}
|
||||
size={size}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
"justify-start text-left font-normal capitalize",
|
||||
!value && "text-muted-foreground",
|
||||
className
|
||||
)}
|
||||
>
|
||||
<RiCalendarLine className="h-4 w-4" />
|
||||
{value ? formatDisplay(value) : placeholder}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<MonthPicker
|
||||
selectedMonth={value ? periodToDate(value) : new Date()}
|
||||
onMonthSelect={handleSelect}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user