Fix: Dashboard and Transactions page improvements
- Fixed missing "Despesas" category in the pie chart. - Re-added month/year filter to Dashboard and Transactions pages. - Improved responsiveness of summary cards on smaller screens.
This commit is contained in:
parent
1d1135cbe4
commit
7b39bcd5aa
@ -16,7 +16,7 @@ const DashboardSummaryCards: React.FC<DashboardSummaryCardsProps> = ({ resumo, f
|
|||||||
const saldo = resumo ? resumo.totalReceitas - resumo.totalDespesas - (resumo.totalCartoes || 0) : 0;
|
const saldo = resumo ? resumo.totalReceitas - resumo.totalDespesas - (resumo.totalCartoes || 0) : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid gap-4 sm:gap-6 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
|
<div className="grid gap-4 sm:gap-6 grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
|
||||||
{/* Card Receitas - Clicável */}
|
{/* Card Receitas - Clicável */}
|
||||||
<Card
|
<Card
|
||||||
className="relative overflow-hidden border-2 border-green-200 bg-gradient-to-br from-green-50 to-emerald-100 shadow-lg hover:shadow-xl transition-all duration-300 cursor-pointer group transform hover:scale-105"
|
className="relative overflow-hidden border-2 border-green-200 bg-gradient-to-br from-green-50 to-emerald-100 shadow-lg hover:shadow-xl transition-all duration-300 cursor-pointer group transform hover:scale-105"
|
||||||
@ -34,7 +34,7 @@ const DashboardSummaryCards: React.FC<DashboardSummaryCardsProps> = ({ resumo, f
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 sm:space-y-2">
|
<div className="space-y-1 sm:space-y-2">
|
||||||
<p className="text-xs sm:text-sm font-semibold text-green-700">Receitas</p>
|
<p className="text-xs sm:text-sm font-semibold text-green-700">Receitas</p>
|
||||||
<p className="text-lg sm:text-2xl lg:text-3xl font-bold text-green-600 break-words">
|
<p className="text-base sm:text-xl xl:text-2xl font-bold text-green-600 leading-tight">
|
||||||
{resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'}
|
{resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-green-600 opacity-80">Clique para ver detalhes</p>
|
<p className="text-xs text-green-600 opacity-80">Clique para ver detalhes</p>
|
||||||
@ -59,7 +59,7 @@ const DashboardSummaryCards: React.FC<DashboardSummaryCardsProps> = ({ resumo, f
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 sm:space-y-2">
|
<div className="space-y-1 sm:space-y-2">
|
||||||
<p className="text-xs sm:text-sm font-semibold text-red-700">Despesas</p>
|
<p className="text-xs sm:text-sm font-semibold text-red-700">Despesas</p>
|
||||||
<p className="text-lg sm:text-2xl lg:text-3xl font-bold text-red-600 break-words">
|
<p className="text-base sm:text-xl xl:text-2xl font-bold text-red-600 leading-tight">
|
||||||
{resumo ? formatCurrency(resumo.totalDespesas) : 'R$ 0,00'}
|
{resumo ? formatCurrency(resumo.totalDespesas) : 'R$ 0,00'}
|
||||||
</p>
|
</p>
|
||||||
{resumo && resumo.totalCartoes > 0 && (
|
{resumo && resumo.totalCartoes > 0 && (
|
||||||
@ -86,7 +86,7 @@ const DashboardSummaryCards: React.FC<DashboardSummaryCardsProps> = ({ resumo, f
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 sm:space-y-2">
|
<div className="space-y-1 sm:space-y-2">
|
||||||
<p className="text-xs sm:text-sm font-semibold text-blue-700">Saldo</p>
|
<p className="text-xs sm:text-sm font-semibold text-blue-700">Saldo</p>
|
||||||
<p className={`text-lg sm:text-2xl lg:text-3xl font-bold break-words ${
|
<p className={`text-base sm:text-xl xl:text-2xl font-bold leading-tight ${
|
||||||
saldo >= 0 ? 'text-blue-600' : 'text-red-600'
|
saldo >= 0 ? 'text-blue-600' : 'text-red-600'
|
||||||
}`}>
|
}`}>
|
||||||
{resumo ? formatCurrency(saldo) : 'R$ 0,00'}
|
{resumo ? formatCurrency(saldo) : 'R$ 0,00'}
|
||||||
@ -106,10 +106,10 @@ const DashboardSummaryCards: React.FC<DashboardSummaryCardsProps> = ({ resumo, f
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-1 sm:space-y-2">
|
<div className="space-y-1 sm:space-y-2">
|
||||||
<p className="text-xs sm:text-sm font-semibold text-purple-700">Economia</p>
|
<p className="text-xs sm:text-sm font-semibold text-purple-700">Economia</p>
|
||||||
<p className="text-lg sm:text-2xl lg:text-3xl font-bold text-purple-600 break-words">
|
<p className="text-base sm:text-xl xl:text-2xl font-bold text-purple-600 leading-tight">
|
||||||
-22.2%
|
-22.2%
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-purple-500 break-words">{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}</p>
|
<p className="text-xs text-purple-500 leading-tight">{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}</p>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@ -9,17 +9,21 @@ import DashboardLoadingState from "@/components/dashboard/DashboardLoadingState"
|
|||||||
import DashboardSummaryCards from "@/components/dashboard/DashboardSummaryCards";
|
import DashboardSummaryCards from "@/components/dashboard/DashboardSummaryCards";
|
||||||
import DashboardCharts from "@/components/dashboard/DashboardCharts";
|
import DashboardCharts from "@/components/dashboard/DashboardCharts";
|
||||||
import DashboardRecentTransactions from "@/components/dashboard/DashboardRecentTransactions";
|
import DashboardRecentTransactions from "@/components/dashboard/DashboardRecentTransactions";
|
||||||
|
import { MonthFilter } from "@/components/filters/MonthFilter";
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const [resumo, setResumo] = useState<ResumoFinanceiro | null>(null);
|
const [resumo, setResumo] = useState<ResumoFinanceiro | null>(null);
|
||||||
const [categories, setCategories] = useState<CategorySummary[]>([]);
|
const [categories, setCategories] = useState<CategorySummary[]>([]);
|
||||||
const [monthlyData, setMonthlyData] = useState<MonthlyData[]>([]);
|
const [monthlyData, setMonthlyData] = useState<MonthlyData[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [selectedMonth, setSelectedMonth] = useState(() => {
|
||||||
|
const now = new Date();
|
||||||
|
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
});
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const getCurrentMonth = () => {
|
const getCurrentMonth = () => {
|
||||||
const now = new Date();
|
return selectedMonth;
|
||||||
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -69,7 +73,7 @@ const Dashboard = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadResumo();
|
loadResumo();
|
||||||
}, [toast]);
|
}, [toast, selectedMonth]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <DashboardLoadingState />;
|
return <DashboardLoadingState />;
|
||||||
@ -79,6 +83,15 @@ const Dashboard = () => {
|
|||||||
<div className="space-y-6" data-tour="dashboard-content">
|
<div className="space-y-6" data-tour="dashboard-content">
|
||||||
<DashboardHeader />
|
<DashboardHeader />
|
||||||
|
|
||||||
|
{/* Filtro de Mês/Ano */}
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<h2 className="text-2xl font-bold">Dashboard</h2>
|
||||||
|
<MonthFilter
|
||||||
|
selectedMonth={selectedMonth}
|
||||||
|
onMonthChange={setSelectedMonth}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<DashboardSummaryCards
|
<DashboardSummaryCards
|
||||||
resumo={resumo}
|
resumo={resumo}
|
||||||
formatCurrency={formatCurrency}
|
formatCurrency={formatCurrency}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { useTransactions } from '@/hooks/useTransactions';
|
import { useTransactions } from '@/hooks/useTransactions';
|
||||||
import { TransactionSummaryCards } from '@/components/transacoes/TransactionSummaryCards';
|
import { TransactionSummaryCards } from '@/components/transacoes/TransactionSummaryCards';
|
||||||
@ -7,9 +7,15 @@ import { TransactionDialogs } from '@/components/transacoes/TransactionDialogs';
|
|||||||
import { TransactionHeader } from '@/components/transacoes/TransactionHeader';
|
import { TransactionHeader } from '@/components/transacoes/TransactionHeader';
|
||||||
import TransactionsTable from '@/components/dashboard/TransactionsTable';
|
import TransactionsTable from '@/components/dashboard/TransactionsTable';
|
||||||
import { SimpleCard } from "@/components/ui/simple-card";
|
import { SimpleCard } from "@/components/ui/simple-card";
|
||||||
|
import { MonthFilter } from "@/components/filters/MonthFilter";
|
||||||
|
|
||||||
const Transacoes = () => {
|
const Transacoes = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const [selectedMonth, setSelectedMonth] = useState(() => {
|
||||||
|
const now = new Date();
|
||||||
|
return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
transactions,
|
transactions,
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -31,7 +37,7 @@ const Transacoes = () => {
|
|||||||
handleOpenDialog,
|
handleOpenDialog,
|
||||||
handleOpenCartaoCreditoDialog,
|
handleOpenCartaoCreditoDialog,
|
||||||
loadTransactions
|
loadTransactions
|
||||||
} = useTransactions();
|
} = useTransactions({ monthFilter: selectedMonth });
|
||||||
|
|
||||||
// Aplicar filtro inicial se vier do dashboard
|
// Aplicar filtro inicial se vier do dashboard
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -54,6 +60,14 @@ const Transacoes = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<h1 className="text-2xl font-bold">Transações</h1>
|
||||||
|
<MonthFilter
|
||||||
|
selectedMonth={selectedMonth}
|
||||||
|
onMonthChange={setSelectedMonth}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<TransactionHeader
|
<TransactionHeader
|
||||||
onOpenDialog={handleOpenDialog}
|
onOpenDialog={handleOpenDialog}
|
||||||
onOpenCartaoCreditoDialog={handleOpenCartaoCreditoDialog}
|
onOpenCartaoCreditoDialog={handleOpenCartaoCreditoDialog}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import { supabase } from "@/integrations/supabase/client";
|
import { supabase } from "@/integrations/supabase/client";
|
||||||
import { CategorySummary, MonthlyData, ResumoFinanceiro } from "@/types/financialTypes";
|
import { CategorySummary, MonthlyData, ResumoFinanceiro } from "@/types/financialTypes";
|
||||||
import { getUserEmail, getUserGroups } from "./baseService";
|
import { getUserEmail, getUserGroups } from "./baseService";
|
||||||
@ -164,37 +165,38 @@ export async function getCategorySummary(tipo: string = 'despesa'): Promise<Cate
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`📋 [getCategorySummary] Dados recebidos:`, data.map(d => ({ categoria: d.categoria, valor: d.valor, tipo: d.tipo })));
|
console.log(`📋 [getCategorySummary] Dados recebidos (${data.length} registros):`, data.slice(0, 5));
|
||||||
|
|
||||||
// Group by category and sum values
|
// Group by category and sum values
|
||||||
const categoryMap: { [key: string]: number } = {};
|
const categoryMap: { [key: string]: number } = {};
|
||||||
let total = 0;
|
let total = 0;
|
||||||
|
|
||||||
data.forEach((transaction) => {
|
data.forEach((transaction) => {
|
||||||
// Usar a categoria exata ou 'Outros' se for null/undefined/vazia
|
// Tratar categorias vazias, nulas ou indefinidas
|
||||||
const categoria = transaction.categoria && transaction.categoria.trim() !== ''
|
let categoria = 'Outros';
|
||||||
? transaction.categoria.trim()
|
|
||||||
: 'Outros';
|
if (transaction.categoria && typeof transaction.categoria === 'string') {
|
||||||
|
const cleanCategory = transaction.categoria.trim();
|
||||||
|
if (cleanCategory.length > 0) {
|
||||||
|
categoria = cleanCategory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const valor = Math.abs(Number(transaction.valor || 0));
|
const valor = Math.abs(Number(transaction.valor || 0));
|
||||||
|
|
||||||
console.log(`📋 [getCategorySummary] Processando: categoria='${categoria}', valor=${valor}`);
|
if (valor > 0) {
|
||||||
|
|
||||||
categoryMap[categoria] = (categoryMap[categoria] || 0) + valor;
|
categoryMap[categoria] = (categoryMap[categoria] || 0) + valor;
|
||||||
total += valor;
|
total += valor;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`📋 [getCategorySummary] Mapeamento final de categorias:`, categoryMap);
|
console.log(`📋 [getCategorySummary] Categorias encontradas:`, Object.keys(categoryMap));
|
||||||
console.log(`📋 [getCategorySummary] Total geral: ${total}`);
|
console.log(`📋 [getCategorySummary] Total geral: ${total}`);
|
||||||
|
|
||||||
// Enhanced color palette with more distinct colors - avoiding white/light colors
|
// Enhanced color palette with more distinct colors - avoiding white/light colors
|
||||||
const colors = [
|
const colors = [
|
||||||
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
|
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
|
||||||
'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
|
'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9'
|
||||||
'#F8C471', '#82E0AA', '#F1948A', '#85C1E9', '#D7BDE2',
|
|
||||||
'#A3E4D7', '#FAD7A0', '#D5A6BD', '#AED6F1', '#A9DFBF',
|
|
||||||
'#FF8A80', '#80CBC4', '#81C784', '#FFB74D', '#F48FB1',
|
|
||||||
'#CE93D8', '#90CAF9', '#A5D6A7', '#FFCC02', '#FFAB40'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Convert to CategorySummary array with colors
|
// Convert to CategorySummary array with colors
|
||||||
@ -207,7 +209,7 @@ export async function getCategorySummary(tipo: string = 'despesa'): Promise<Cate
|
|||||||
}))
|
}))
|
||||||
.sort((a, b) => b.valor - a.valor);
|
.sort((a, b) => b.valor - a.valor);
|
||||||
|
|
||||||
console.log(`📋 [getCategorySummary] ${categoryArray.length} categorias processadas:`, categoryArray);
|
console.log(`📋 [getCategorySummary] Resultado final:`, categoryArray);
|
||||||
return categoryArray;
|
return categoryArray;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('💥 [getCategorySummary] Erro geral:', error);
|
console.error('💥 [getCategorySummary] Erro geral:', error);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user