refactor(dashboard): reorganizar módulos em subdiretórios e nova arquitetura de widgets

Arquivos de queries, helpers e controllers dispersos na raiz de dashboard/
foram movidos para subdiretórios temáticos (bills/, invoices/, notes/,
notifications/, overview/, payments/, goals-progress/, categories/).
~25 widgets monolíticos obsoletos removidos em favor de nova arquitetura
baseada em widget-registry com components/widgets/. Novos componentes:
category-breakdown-chart/list, goals-progress-item, percentage-change-indicator.
Imports atualizados em fetch-dashboard-data e transaction-filters limpos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-04-20 17:51:56 +00:00
parent 3e80d5995b
commit ba05985725
99 changed files with 784 additions and 2055 deletions

View File

@@ -0,0 +1,78 @@
"use client";
import { RiLineChartLine } from "@remixicon/react";
import type { DashboardCategoryBreakdownItem } from "@/features/dashboard/categories/category-breakdown-helpers";
import { PercentageChangeIndicator } from "@/features/dashboard/components/percentage-change-indicator";
import { CategoryIconBadge } from "@/shared/components/entity-avatar";
import MoneyValues from "@/shared/components/money-values";
import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
import { formatPercentage } from "@/shared/utils/percentage";
type CategoryTrendsWidgetProps = {
categories: DashboardCategoryBreakdownItem[];
};
export function CategoryTrendsWidget({
categories,
}: CategoryTrendsWidgetProps) {
const trending = categories
.filter((c) => c.percentageChange !== null && c.previousAmount > 0)
.sort(
(a, b) =>
Math.abs(b.percentageChange ?? 0) - Math.abs(a.percentageChange ?? 0),
)
.slice(0, 10);
if (trending.length === 0) {
return (
<WidgetEmptyState
icon={<RiLineChartLine className="size-6 text-muted-foreground" />}
title="Dados insuficientes"
description="As variações aparecem após lançamentos em dois meses consecutivos."
/>
);
}
return (
<ul className="flex flex-col space-y-1">
{trending.map((category) => {
const change = category.percentageChange ?? 0;
return (
<li key={category.categoryId}>
<div className="-mx-2 flex items-center gap-3 rounded-md p-2">
<CategoryIconBadge
icon={category.categoryIcon}
name={category.categoryName}
size="md"
/>
<div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium text-foreground">
{category.categoryName}
</p>
<p className="text-xs text-muted-foreground">
<MoneyValues amount={category.previousAmount} /> vs{" "}
<MoneyValues
amount={category.currentAmount}
className="font-semibold"
/>
</p>
</div>
<PercentageChangeIndicator
value={change}
label={formatPercentage(change, {
absolute: true,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
})}
positiveTrend="down"
className="shrink-0 text-sm font-semibold"
iconClassName="size-3.5"
/>
</div>
</li>
);
})}
</ul>
);
}