diff --git a/components/relatorios/cartoes/card-category-breakdown.tsx b/components/relatorios/cartoes/card-category-breakdown.tsx index 21262c0..d2d9cd2 100644 --- a/components/relatorios/cartoes/card-category-breakdown.tsx +++ b/components/relatorios/cartoes/card-category-breakdown.tsx @@ -1,109 +1,120 @@ "use client"; +import MoneyValues from "@/components/money-values"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { WidgetEmptyState } from "@/components/widget-empty-state"; import type { CardDetailData } from "@/lib/relatorios/cartoes-report"; +import { + buildCategoryInitials, + getCategoryBgColor, + getCategoryColor, +} from "@/lib/utils/category-colors"; import { getIconComponent } from "@/lib/utils/icons"; +import { title_font } from "@/public/fonts/font_index"; import { RiPieChartLine } from "@remixicon/react"; type CardCategoryBreakdownProps = { data: CardDetailData["categoryBreakdown"]; }; -const COLORS = [ - "#ef4444", - "#3b82f6", - "#10b981", - "#f59e0b", - "#8b5cf6", - "#ec4899", - "#14b8a6", - "#f97316", - "#6366f1", - "#84cc16", -]; - export function CardCategoryBreakdown({ data }: CardCategoryBreakdownProps) { - const formatCurrency = (value: number) => { - return new Intl.NumberFormat("pt-BR", { - style: "currency", - currency: "BRL", - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(value); - }; - if (data.length === 0) { return ( - - - + + + + Gastos por Categoria -
- -

Nenhum gasto neste período

-
+ } + title="Nenhuma categoria encontrada" + description="Quando houver despesas categorizadas, elas aparecerão aqui." + />
); } + const totalAmount = data.reduce((acc, c) => acc + c.amount, 0); + return ( - - - + + + + Gastos por Categoria - - {data.map((category, index) => { - const IconComponent = category.icon - ? getIconComponent(category.icon) - : null; - const color = COLORS[index % COLORS.length]; - return ( -
-
-
- {IconComponent ? ( - - ) : ( + +
+ {data.map((category, index) => { + const IconComponent = category.icon + ? getIconComponent(category.icon) + : null; + const color = getCategoryColor(index); + const bgColor = getCategoryBgColor(index); + const initials = buildCategoryInitials(category.name); + + return ( +
+
+
+ {IconComponent ? ( + + ) : ( + + {initials} + + )} +
+ + {/* Name and percentage */} +
+ + {category.name} + + + {category.percent.toFixed(0)}% do total + +
+
+ + {/* Value */} +
+ - )} - - {category.name} - +
- - {formatCurrency(category.amount)} - -
-
-
-
+ + {/* Progress bar */} +
+
- - {category.percent.toFixed(0)}% -
-
- ); - })} + ); + })} +
); diff --git a/components/relatorios/cartoes/card-top-expenses.tsx b/components/relatorios/cartoes/card-top-expenses.tsx index c187964..7542fb7 100644 --- a/components/relatorios/cartoes/card-top-expenses.tsx +++ b/components/relatorios/cartoes/card-top-expenses.tsx @@ -1,7 +1,12 @@ "use client"; +import MoneyValues from "@/components/money-values"; +import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { WidgetEmptyState } from "@/components/widget-empty-state"; import type { CardDetailData } from "@/lib/relatorios/cartoes-report"; +import { title_font } from "@/public/fonts/font_index"; import { RiShoppingBag3Line } from "@remixicon/react"; type CardTopExpensesProps = { @@ -9,71 +14,95 @@ type CardTopExpensesProps = { }; export function CardTopExpenses({ data }: CardTopExpensesProps) { - const formatCurrency = (value: number) => { - return new Intl.NumberFormat("pt-BR", { - style: "currency", - currency: "BRL", - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }).format(value); - }; - if (data.length === 0) { return ( - - - - Maiores Gastos + + + + + Top 10 Gastos do Mês -
- -

Nenhum gasto neste período

-
+ + } + title="Nenhum gasto encontrado" + description="Quando houver gastos registrados, eles aparecerão aqui." + />
); } + const maxAmount = Math.max(...data.map((e) => e.amount)); + return ( - - - + + + + Top 10 Gastos do Mês - -
+ +
{data.map((expense, index) => (
-
- - {index + 1}. - -
-

- {expense.name} -

-
- {expense.date} - {expense.category && ( - <> - - +
+
+ {/* Rank number */} +
+ + {index + 1} + +
+ + {/* Name and details */} +
+ + {expense.name} + +
+ + {expense.date} + + {expense.category && ( + {expense.category} - - - )} + + )} +
+ + {/* Value */} +
+ +
+
+ + {/* Progress bar */} +
+
- - {formatCurrency(expense.amount)} -
))}
diff --git a/components/relatorios/cartoes/cards-overview.tsx b/components/relatorios/cartoes/cards-overview.tsx index e78d77a..64ee2ce 100644 --- a/components/relatorios/cartoes/cards-overview.tsx +++ b/components/relatorios/cartoes/cards-overview.tsx @@ -3,14 +3,15 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import type { CartoesReportData } from "@/lib/relatorios/cartoes-report"; -import { - RiBankCard2Line, - RiArrowUpLine, - RiArrowDownLine, -} from "@remixicon/react"; import { cn } from "@/lib/utils"; -import Link from "next/link"; +import { title_font } from "@/public/fonts/font_index"; +import { + RiArrowDownLine, + RiArrowUpLine, + RiBankCard2Line, +} from "@remixicon/react"; import Image from "next/image"; +import Link from "next/link"; import { useSearchParams } from "next/navigation"; type CardsOverviewProps = { @@ -78,7 +79,8 @@ export function CardsOverview({ data }: CardsOverviewProps) { return ( - + + Resumo dos Cartões @@ -95,7 +97,10 @@ export function CardsOverview({ data }: CardsOverviewProps) { return ( - + + Resumo dos Cartões