From 7fbd572371f674c4cdfba0c96c89b65b064ed3c9 Mon Sep 17 00:00:00 2001 From: marcoitaloesp-ai Date: Mon, 15 Dec 2025 16:18:52 +0000 Subject: [PATCH] =?UTF-8?q?v1.36.0=20-=20Redesign=20se=C3=A7=C3=A3o=20Maio?= =?UTF-8?q?res=20Despesas=20com=20KPI=20cards=20+=20gr=C3=A1fico=20barras?= =?UTF-8?q?=20+=20tabela=20profissional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 16 ++ VERSION | 2 +- frontend/src/i18n/locales/en.json | 7 + frontend/src/i18n/locales/es.json | 7 + frontend/src/i18n/locales/pt-BR.json | 7 + frontend/src/pages/Reports.jsx | 254 +++++++++++++++++++++++---- 6 files changed, 261 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce7dc13..5722bfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ O formato segue [Keep a Changelog](https://keepachangelog.com/pt-BR/). Este projeto adota [Versionamento Semântico](https://semver.org/pt-BR/). +## [1.36.0] - 2025-12-15 + +### Improved +- **UI/UX da Seção Maiores Despesas** - Interface completamente redesenhada + - 4 Cards KPI com gradientes: Maior Despesa, Média, Menor Despesa, Total de Transações + - Gráfico de Barras Horizontais mostrando Top 10 despesas com degradê de cores + - Tabela detalhada completa com: + * Badges coloridos para posições (top 3 em vermelho, top 10 em amarelo) + * Barra de progresso visual mostrando % do total + * Categorias em badges + * Formatação profissional com sticky header + * Scroll independente para listas longas + - Layout responsivo em grid com altura controlada + - Tooltips do gráfico com informações completas (valor, categoria, data) + - Traduções: topExpensesAnalysis, highestExpense, averageExpense, lowestExpense, totalTransactions, top10Expenses, detailedList + ## [1.35.0] - 2025-12-15 ### Improved diff --git a/VERSION b/VERSION index 2aeaa11..39fc130 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.35.0 +1.36.0 diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index b682fb2..2b1bec8 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -1860,6 +1860,13 @@ "description": "Description", "date": "Date", "top20Expenses": "Top 20 Monthly Expenses", + "topExpensesAnalysis": "Top Expenses Analysis", + "highestExpense": "Highest Expense", + "averageExpense": "Average Expense", + "lowestExpense": "Lowest Expense", + "totalTransactions": "Total Transactions", + "top10Expenses": "Top 10 Expenses", + "detailedList": "Detailed List", "expensesByDayOfWeek": "Expenses by Day of Week", "totalSpent": "Total spent", "totalIncome": "Total Income", diff --git a/frontend/src/i18n/locales/es.json b/frontend/src/i18n/locales/es.json index 457129f..2a3e83d 100644 --- a/frontend/src/i18n/locales/es.json +++ b/frontend/src/i18n/locales/es.json @@ -1843,6 +1843,13 @@ "description": "Descripción", "date": "Fecha", "top20Expenses": "Top 20 Gastos del Mes", + "topExpensesAnalysis": "Análisis de Mayores Gastos", + "highestExpense": "Mayor Gasto", + "averageExpense": "Promedio de Gastos", + "lowestExpense": "Menor Gasto", + "totalTransactions": "Total de Transacciones", + "top10Expenses": "Top 10 Mayores Gastos", + "detailedList": "Lista Detallada", "expensesByDayOfWeek": "Gastos por Día de la Semana", "totalSpent": "Total gastado", "totalIncome": "Total Ingresos", diff --git a/frontend/src/i18n/locales/pt-BR.json b/frontend/src/i18n/locales/pt-BR.json index 14d1454..1d440eb 100644 --- a/frontend/src/i18n/locales/pt-BR.json +++ b/frontend/src/i18n/locales/pt-BR.json @@ -1862,6 +1862,13 @@ "description": "Descrição", "date": "Data", "top20Expenses": "Top 20 Despesas do Mês", + "topExpensesAnalysis": "Análise das Maiores Despesas", + "highestExpense": "Maior Despesa", + "averageExpense": "Média das Despesas", + "lowestExpense": "Menor Despesa", + "totalTransactions": "Total de Transações", + "top10Expenses": "Top 10 Maiores Despesas", + "detailedList": "Lista Detalhada", "expensesByDayOfWeek": "Despesas por Dia da Semana", "totalSpent": "Total gasto", "totalIncome": "Total Receitas", diff --git a/frontend/src/pages/Reports.jsx b/frontend/src/pages/Reports.jsx index b7d8253..11ca9a6 100644 --- a/frontend/src/pages/Reports.jsx +++ b/frontend/src/pages/Reports.jsx @@ -874,39 +874,231 @@ const Reports = () => { const renderTopExpenses = () => { if (!topExpenses) return null; + const top10 = topExpenses.data.slice(0, 10); + const averageExpense = topExpenses.total / topExpenses.data.length; + const maxExpense = topExpenses.data.length > 0 ? topExpenses.data[0].amount : 0; + const minExpense = topExpenses.data.length > 0 ? topExpenses.data[topExpenses.data.length - 1].amount : 0; + return ( -
-
-
- - {t('reports.top20Expenses')} -
- {currency(topExpenses.total, topExpenses.currency)} +
+ {/* Header */} +
+
+
+ + {t('reports.topExpensesAnalysis')} +
+ + {t('reports.total')}: {currency(topExpenses.total, topExpenses.currency)} + +
-
-
- - - - - - - - - - - - {topExpenses.data.map((item, i) => ( - - - - - - - - ))} - -
#{t('reports.description')}{t('reports.category')}{t('reports.date')}{t('reports.amount')}
{i + 1}{item.description}{item.category || '-'}{item.date}{currency(item.amount, item.currency || topExpenses.currency)}
+ + {/* Cards KPI */} +
+
+
+
+
+
{t('reports.highestExpense')}
+

{currency(maxExpense, topExpenses.currency)}

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
{t('reports.averageExpense')}
+

{currency(averageExpense, topExpenses.currency)}

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
{t('reports.lowestExpense')}
+

{currency(minExpense, topExpenses.currency)}

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
{t('reports.totalTransactions')}
+

{topExpenses.data.length}

+
+
+ +
+
+
+
+
+ + {/* Gráfico de Barras Horizontais - Top 10 */} +
+
+
+
+ + {t('reports.top10Expenses')} +
+
+
+ `${i + 1}. ${item.description.substring(0, 30)}${item.description.length > 30 ? '...' : ''}`), + datasets: [{ + label: t('reports.amount'), + data: top10.map(item => item.amount), + backgroundColor: top10.map((_, i) => { + const opacity = 1 - (i * 0.08); + return `rgba(239, 68, 68, ${opacity})`; + }), + borderColor: '#EF4444', + borderWidth: 2, + borderRadius: 6, + }], + }} + options={{ + indexAxis: 'y', + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { display: false }, + tooltip: { + backgroundColor: 'rgba(15, 23, 42, 0.95)', + titleColor: '#fff', + bodyColor: '#94a3b8', + borderColor: '#334155', + borderWidth: 1, + padding: 12, + callbacks: { + label: function(context) { + const item = top10[context.dataIndex]; + return [ + `${t('reports.amount')}: ${currency(context.parsed.x, topExpenses.currency)}`, + `${t('reports.category')}: ${item.category || '-'}`, + `${t('reports.date')}: ${item.date}` + ]; + } + } + } + }, + scales: { + x: { + ticks: { + color: '#94a3b8', + callback: function(value) { + return currency(value, topExpenses.currency); + } + }, + grid: { color: 'rgba(148, 163, 184, 0.1)' } + }, + y: { + ticks: { + color: '#94a3b8', + font: { size: 11 } + }, + grid: { display: false } + } + } + }} + /> +
+
+
+ + {/* Tabela Detalhada */} +
+
+
+
+ + {t('reports.detailedList')} ({topExpenses.data.length} {t('reports.transactions')}) +
+
+
+
+ + + + + + + + + + + + + {topExpenses.data.map((item, i) => { + const percentage = (item.amount / topExpenses.total) * 100; + return ( + + + + + + + + + ); + })} + +
#{t('reports.description')}{t('reports.category')}{t('reports.date')}{t('reports.amount')}% {t('reports.total')}
+ + {i + 1} + + +
+ {item.description} +
+
+ {item.category || '-'} + {item.date} + + {currency(item.amount, item.currency || topExpenses.currency)} + + +
+
+
+
+ + {percentage.toFixed(1)}% + +
+
+
+