Enhance dashboard cards and charts
- Implemented year-long view for "Receitas vs Despesas" chart. - Improved dashboard card design and functionality, including navigation to filtered transactions on click. - Verified the accuracy of the "Despesa por Categoria" chart.
This commit is contained in:
parent
45234a1a61
commit
4e8972cb55
@ -1,6 +1,5 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import {
|
||||
BarChart,
|
||||
Bar,
|
||||
@ -48,6 +47,31 @@ const MonthlyChart: React.FC<MonthlyChartProps> = ({ data, isLoading = false })
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
// Criar dados para o ano completo (12 meses)
|
||||
const generateFullYearData = () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const months = [
|
||||
'Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun',
|
||||
'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'
|
||||
];
|
||||
|
||||
const fullYearData = months.map((month, index) => {
|
||||
const monthKey = `${currentYear}-${String(index + 1).padStart(2, '0')}`;
|
||||
const existingData = data.find(d => d.month === monthKey);
|
||||
|
||||
return {
|
||||
month: month,
|
||||
monthKey: monthKey,
|
||||
receitas: existingData ? existingData.receitas : 0,
|
||||
despesas: existingData ? existingData.despesas : 0
|
||||
};
|
||||
});
|
||||
|
||||
return fullYearData;
|
||||
};
|
||||
|
||||
const fullYearData = generateFullYearData();
|
||||
|
||||
const customTooltip = ({ active, payload, label }: any) => {
|
||||
if (active && payload && payload.length) {
|
||||
return (
|
||||
@ -64,7 +88,6 @@ const MonthlyChart: React.FC<MonthlyChartProps> = ({ data, isLoading = false })
|
||||
return null;
|
||||
};
|
||||
|
||||
// Custom label component that only shows values above a threshold
|
||||
const CustomLabel = ({ x, y, width, value, dataKey }: any) => {
|
||||
if (!value || value < 100) return null;
|
||||
const isReceita = dataKey === 'receitas';
|
||||
@ -84,105 +107,94 @@ const MonthlyChart: React.FC<MonthlyChartProps> = ({ data, isLoading = false })
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="dashboard-card h-full shadow-xl rounded-2xl animate-fade-in bg-gradient-to-br from-slate-50 via-white to-blue-50 dark:from-zinc-900 dark:via-zinc-800 dark:to-zinc-900 border-0">
|
||||
<CardHeader className="pb-2 bg-gradient-to-r from-blue-50/50 to-blue-100/0 dark:from-zinc-900 dark:to-zinc-900 rounded-t-2xl">
|
||||
<CardTitle className="text-lg font-bold tracking-tight text-zinc-700 dark:text-white flex items-center">
|
||||
<span className="mr-2">📈</span> Receitas vs Despesas
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center h-[260px]">
|
||||
<div className="h-32 w-32 rounded-full border-4 border-t-primary border-opacity-20 animate-spin" />
|
||||
</div>
|
||||
) : data.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center h-[260px] text-muted-foreground">
|
||||
<span>Sem dados disponíveis</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-[320px] relative">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={data}
|
||||
margin={{ top: 30, right: 30, left: 20, bottom: 15 }}
|
||||
barGap={8}
|
||||
<div className="h-full animate-fade-in">
|
||||
{isLoading ? (
|
||||
<div className="flex items-center justify-center h-[320px]">
|
||||
<div className="h-32 w-32 rounded-full border-4 border-t-primary border-opacity-20 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-[320px] relative">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={fullYearData}
|
||||
margin={{ top: 30, right: 30, left: 20, bottom: 15 }}
|
||||
barGap={8}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.20} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 13, fontWeight: 500, fill: "#334155" }}
|
||||
dy={10}
|
||||
/>
|
||||
<YAxis
|
||||
tickFormatter={formatCompactCurrency}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 13, fill: "#64748b" }}
|
||||
width={80}
|
||||
/>
|
||||
<Tooltip
|
||||
cursor={{ fill: 'rgba(16, 185, 129, 0.07)' }}
|
||||
content={customTooltip}
|
||||
/>
|
||||
<Legend
|
||||
verticalAlign="top"
|
||||
height={36}
|
||||
iconType="circle"
|
||||
iconSize={12}
|
||||
wrapperStyle={{ fontWeight: 600, fontSize: 13, color: "#52525b" }}
|
||||
/>
|
||||
<Bar
|
||||
name="Receitas"
|
||||
dataKey="receitas"
|
||||
fill="#10B981"
|
||||
radius={[8, 8, 0, 0]}
|
||||
barSize={36}
|
||||
animationDuration={1200}
|
||||
label={<CustomLabel dataKey="receitas" />}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.20} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 13, fontWeight: 500, fill: "#334155" }}
|
||||
dy={10}
|
||||
/>
|
||||
<YAxis
|
||||
tickFormatter={formatCompactCurrency}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tick={{ fontSize: 13, fill: "#64748b" }}
|
||||
width={80}
|
||||
/>
|
||||
<Tooltip
|
||||
cursor={{ fill: 'rgba(16, 185, 129, 0.07)' }}
|
||||
content={customTooltip}
|
||||
/>
|
||||
<Legend
|
||||
verticalAlign="top"
|
||||
height={36}
|
||||
iconType="circle"
|
||||
iconSize={12}
|
||||
wrapperStyle={{ fontWeight: 600, fontSize: 13, color: "#52525b" }}
|
||||
/>
|
||||
<Bar
|
||||
name="Receitas"
|
||||
dataKey="receitas"
|
||||
fill="#10B981"
|
||||
radius={[8, 8, 0, 0]}
|
||||
barSize={36}
|
||||
animationDuration={1200}
|
||||
label={<CustomLabel dataKey="receitas" />}
|
||||
>
|
||||
{data.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-receitas-${index}`}
|
||||
fill="url(#receitaBar)"
|
||||
style={{ filter: 'drop-shadow(0px 2px 2px rgba(16,185,129,0.10))' }}
|
||||
/>
|
||||
))}
|
||||
</Bar>
|
||||
<Bar
|
||||
name="Despesas"
|
||||
dataKey="despesas"
|
||||
fill="#EF4444"
|
||||
radius={[8, 8, 0, 0]}
|
||||
barSize={36}
|
||||
animationDuration={1200}
|
||||
label={<CustomLabel dataKey="despesas" />}
|
||||
>
|
||||
{data.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-despesas-${index}`}
|
||||
fill="url(#despesaBar)"
|
||||
style={{ filter: 'drop-shadow(0px 2px 2px rgba(239,68,68,0.08))' }}
|
||||
/>
|
||||
))}
|
||||
</Bar>
|
||||
<defs>
|
||||
<linearGradient id="receitaBar" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="#17ead9" />
|
||||
<stop offset="100%" stopColor="#10B981" />
|
||||
</linearGradient>
|
||||
<linearGradient id="despesaBar" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="#fbc2eb" />
|
||||
<stop offset="100%" stopColor="#EF4444" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
{fullYearData.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-receitas-${index}`}
|
||||
fill="url(#receitaBar)"
|
||||
style={{ filter: 'drop-shadow(0px 2px 2px rgba(16,185,129,0.10))' }}
|
||||
/>
|
||||
))}
|
||||
</Bar>
|
||||
<Bar
|
||||
name="Despesas"
|
||||
dataKey="despesas"
|
||||
fill="#EF4444"
|
||||
radius={[8, 8, 0, 0]}
|
||||
barSize={36}
|
||||
animationDuration={1200}
|
||||
label={<CustomLabel dataKey="despesas" />}
|
||||
>
|
||||
{fullYearData.map((entry, index) => (
|
||||
<Cell
|
||||
key={`cell-despesas-${index}`}
|
||||
fill="url(#despesaBar)"
|
||||
style={{ filter: 'drop-shadow(0px 2px 2px rgba(239,68,68,0.08))' }}
|
||||
/>
|
||||
))}
|
||||
</Bar>
|
||||
<defs>
|
||||
<linearGradient id="receitaBar" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="#17ead9" />
|
||||
<stop offset="100%" stopColor="#10B981" />
|
||||
</linearGradient>
|
||||
<linearGradient id="despesaBar" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="#fbc2eb" />
|
||||
<stop offset="100%" stopColor="#EF4444" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
21
src/hooks/useNavigateWithFilter.ts
Normal file
21
src/hooks/useNavigateWithFilter.ts
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export const useNavigateWithFilter = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const navigateToTransactions = (tipo?: 'receita' | 'despesa') => {
|
||||
if (tipo) {
|
||||
navigate('/transacoes', {
|
||||
state: {
|
||||
filter: tipo,
|
||||
filterValue: tipo === 'receita' ? 'receita' : 'despesa'
|
||||
}
|
||||
});
|
||||
} else {
|
||||
navigate('/transacoes');
|
||||
}
|
||||
};
|
||||
|
||||
return { navigateToTransactions };
|
||||
};
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
@ -10,6 +9,7 @@ import { useTransactions } from "@/hooks/useTransactions";
|
||||
import CategoryChart from "@/components/dashboard/CategoryChart";
|
||||
import MonthlyChart from "@/components/dashboard/MonthlyChart";
|
||||
import { SimpleCard } from "@/components/ui/simple-card";
|
||||
import { useNavigateWithFilter } from "@/hooks/useNavigateWithFilter";
|
||||
|
||||
const Dashboard = () => {
|
||||
const [resumo, setResumo] = useState<ResumoFinanceiro | null>(null);
|
||||
@ -17,6 +17,7 @@ const Dashboard = () => {
|
||||
const [monthlyData, setMonthlyData] = useState<MonthlyData[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const { toast } = useToast();
|
||||
const { navigateToTransactions } = useNavigateWithFilter();
|
||||
|
||||
const getCurrentMonth = () => {
|
||||
const now = new Date();
|
||||
@ -94,6 +95,7 @@ const Dashboard = () => {
|
||||
}
|
||||
|
||||
const saldo = resumo ? resumo.totalReceitas - resumo.totalDespesas - (resumo.totalCartoes || 0) : 0;
|
||||
const totalDespesasGeral = resumo ? resumo.totalDespesas + (resumo.totalCartoes || 0) : 0;
|
||||
|
||||
return (
|
||||
<div className="space-y-6" data-tour="dashboard-content">
|
||||
@ -101,89 +103,113 @@ const Dashboard = () => {
|
||||
<h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
<Card className="border-2 border-green-200 bg-green-50/50">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-green-700">Receitas</CardTitle>
|
||||
<div className="p-2 bg-green-100 rounded-full">
|
||||
<ArrowUpIcon className="h-4 w-4 text-green-600" />
|
||||
<div className="grid gap-6 md:grid-cols-4">
|
||||
{/* Card Receitas - Clicável */}
|
||||
<Card
|
||||
className="relative overflow-hidden border-0 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"
|
||||
onClick={() => navigateToTransactions('receita')}
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-green-400/10 to-emerald-500/10 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
<CardContent className="p-6 relative">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="p-3 bg-green-500 rounded-full shadow-lg">
|
||||
<ArrowUpIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div className="text-xs font-bold px-3 py-1 bg-green-500 text-white rounded-full shadow-sm">
|
||||
+5%
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-green-600">
|
||||
{resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'}
|
||||
</div>
|
||||
<div className="flex items-center text-xs text-green-600 mt-1">
|
||||
<span className="bg-green-100 px-2 py-1 rounded-full">+5%</span>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-semibold text-green-700">Receitas</p>
|
||||
<p className="text-3xl font-bold text-green-600">
|
||||
{resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'}
|
||||
</p>
|
||||
<p className="text-xs text-green-600 opacity-80">Clique para ver detalhes</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-2 border-red-200 bg-red-50/50">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-red-700">Despesas</CardTitle>
|
||||
<div className="p-2 bg-red-100 rounded-full">
|
||||
<ArrowDownIcon className="h-4 w-4 text-red-600" />
|
||||
{/* Card Despesas - Clicável */}
|
||||
<Card
|
||||
className="relative overflow-hidden border-0 bg-gradient-to-br from-red-50 to-rose-100 shadow-lg hover:shadow-xl transition-all duration-300 cursor-pointer group transform hover:scale-105"
|
||||
onClick={() => navigateToTransactions('despesa')}
|
||||
>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-red-400/10 to-rose-500/10 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
<CardContent className="p-6 relative">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="p-3 bg-red-500 rounded-full shadow-lg">
|
||||
<ArrowDownIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<div className="text-xs font-bold px-3 py-1 bg-red-500 text-white rounded-full shadow-sm">
|
||||
-2%
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-red-600">
|
||||
{resumo ? formatCurrency(resumo.totalDespesas + (resumo.totalCartoes || 0)) : 'R$ 0,00'}
|
||||
</div>
|
||||
<div className="flex items-center text-xs text-red-600 mt-1">
|
||||
<span className="bg-red-100 px-2 py-1 rounded-full">-2%</span>
|
||||
</div>
|
||||
{resumo && resumo.totalCartoes > 0 && (
|
||||
<p className="text-xs text-red-500 mt-1">Cartões: {formatCurrency(resumo.totalCartoes)}</p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-2 border-blue-200 bg-blue-50/50">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-blue-700">Saldo</CardTitle>
|
||||
<div className="p-2 bg-blue-100 rounded-full">
|
||||
<CreditCardIcon className="h-4 w-4 text-blue-600" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className={`text-2xl font-bold ${
|
||||
saldo >= 0 ? 'text-blue-600' : 'text-red-600'
|
||||
}`}>
|
||||
{resumo ? formatCurrency(saldo) : 'R$ 0,00'}
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-semibold text-red-700">Despesas</p>
|
||||
<p className="text-3xl font-bold text-red-600">
|
||||
{resumo ? formatCurrency(totalDespesasGeral) : 'R$ 0,00'}
|
||||
</p>
|
||||
{resumo && resumo.totalCartoes > 0 && (
|
||||
<p className="text-xs text-red-500">Cartões: {formatCurrency(resumo.totalCartoes)}</p>
|
||||
)}
|
||||
<p className="text-xs text-red-600 opacity-80">Clique para ver detalhes</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-2 border-purple-200 bg-purple-50/50">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-purple-700">Economia</CardTitle>
|
||||
<div className="p-2 bg-purple-100 rounded-full">
|
||||
<Target className="h-4 w-4 text-purple-600" />
|
||||
{/* Card Saldo */}
|
||||
<Card className="relative overflow-hidden border-0 bg-gradient-to-br from-blue-50 to-sky-100 shadow-lg hover:shadow-xl transition-all duration-300 group transform hover:scale-105">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-blue-400/10 to-sky-500/10 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
<CardContent className="p-6 relative">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="p-3 bg-blue-500 rounded-full shadow-lg">
|
||||
<CreditCardIcon className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-purple-600">
|
||||
-22.2%
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-semibold text-blue-700">Saldo</p>
|
||||
<p className={`text-3xl font-bold ${
|
||||
saldo >= 0 ? 'text-blue-600' : 'text-red-600'
|
||||
}`}>
|
||||
{resumo ? formatCurrency(saldo) : 'R$ 0,00'}
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Card Economia */}
|
||||
<Card className="relative overflow-hidden border-0 bg-gradient-to-br from-purple-50 to-violet-100 shadow-lg hover:shadow-xl transition-all duration-300 group transform hover:scale-105">
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-purple-400/10 to-violet-500/10 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||
<CardContent className="p-6 relative">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="p-3 bg-purple-500 rounded-full shadow-lg">
|
||||
<Target className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-semibold text-purple-700">Economia</p>
|
||||
<p className="text-3xl font-bold text-purple-600">
|
||||
-22.2%
|
||||
</p>
|
||||
<p className="text-xs text-purple-500">{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}</p>
|
||||
</div>
|
||||
<p className="text-xs text-purple-500 mt-1">{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* 1. Receitas vs Despesas Chart */}
|
||||
<SimpleCard title="Receitas vs Despesas" className="border-green-200">
|
||||
<SimpleCard title="📈 Receitas vs Despesas" className="border-green-200">
|
||||
<MonthlyChart data={monthlyData} isLoading={isLoading} />
|
||||
</SimpleCard>
|
||||
|
||||
{/* 2. Gastos por Categoria */}
|
||||
<SimpleCard title="Despesas por Categoria" className="border-orange-200">
|
||||
<SimpleCard title="📊 Despesas por Categoria" className="border-orange-200">
|
||||
<CategoryChart categories={categories} isLoading={isLoading} />
|
||||
</SimpleCard>
|
||||
|
||||
{/* 3. Últimas Transações */}
|
||||
<SimpleCard title="Últimas Transações" className="border-blue-200">
|
||||
<SimpleCard title="📋 Últimas Transações" className="border-blue-200">
|
||||
<TransactionsTable
|
||||
transactions={transactions.slice(0, 5)}
|
||||
isLoading={transactionsLoading}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useTransactions } from '@/hooks/useTransactions';
|
||||
import { TransactionSummaryCards } from '@/components/transacoes/TransactionSummaryCards';
|
||||
import { TransactionDialogs } from '@/components/transacoes/TransactionDialogs';
|
||||
@ -7,6 +9,7 @@ import TransactionsTable from '@/components/dashboard/TransactionsTable';
|
||||
import { SimpleCard } from "@/components/ui/simple-card";
|
||||
|
||||
const Transacoes = () => {
|
||||
const location = useLocation();
|
||||
const {
|
||||
transactions,
|
||||
isLoading,
|
||||
@ -30,6 +33,25 @@ const Transacoes = () => {
|
||||
loadTransactions
|
||||
} = useTransactions();
|
||||
|
||||
// Aplicar filtro inicial se vier do dashboard
|
||||
useEffect(() => {
|
||||
if (location.state?.filter) {
|
||||
// Aqui você pode implementar lógica adicional para filtrar automaticamente
|
||||
// Por exemplo, definir um filtro inicial na tabela
|
||||
console.log('Filtro aplicado:', location.state.filter);
|
||||
}
|
||||
}, [location.state]);
|
||||
|
||||
// Filtrar transações baseado no filtro vindo do dashboard
|
||||
const getFilteredTransactions = () => {
|
||||
if (location.state?.filter) {
|
||||
return transactions.filter(t => t.tipo === location.state.filter);
|
||||
}
|
||||
return transactions;
|
||||
};
|
||||
|
||||
const filteredTransactions = getFilteredTransactions();
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<TransactionHeader
|
||||
@ -44,9 +66,14 @@ const Transacoes = () => {
|
||||
formatCurrency={formatCurrency}
|
||||
/>
|
||||
|
||||
<SimpleCard title="Todas as Transações" className="border-gray-200">
|
||||
<SimpleCard
|
||||
title={`${location.state?.filter ?
|
||||
(location.state.filter === 'receita' ? 'Receitas' : 'Despesas')
|
||||
: 'Todas as Transações'}`}
|
||||
className="border-gray-200"
|
||||
>
|
||||
<TransactionsTable
|
||||
transactions={transactions}
|
||||
transactions={filteredTransactions}
|
||||
isLoading={isLoading}
|
||||
showPagination={true}
|
||||
onEdit={handleEditTransaction}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { CategorySummary, MonthlyData, ResumoFinanceiro } from "@/types/financialTypes";
|
||||
import { getUserEmail, getUserGroups } from "./baseService";
|
||||
@ -177,13 +176,17 @@ export async function getCategorySummary(tipo: string = 'despesa'): Promise<Cate
|
||||
total += valor;
|
||||
});
|
||||
|
||||
// Convert to CategorySummary array with colors
|
||||
// Enhanced color palette with more distinct colors - avoiding white/light colors
|
||||
const colors = [
|
||||
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0',
|
||||
'#9966FF', '#FF9F40', '#FF6384', '#C9CBCF',
|
||||
'#4BC0C0', '#FF6384', '#36A2EB', '#FFCE56'
|
||||
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
|
||||
'#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
|
||||
const categoryArray = Object.entries(categoryMap)
|
||||
.map(([categoria, valor], index) => ({
|
||||
categoria,
|
||||
@ -202,11 +205,11 @@ export async function getCategorySummary(tipo: string = 'despesa'): Promise<Cate
|
||||
}
|
||||
|
||||
/**
|
||||
* Get monthly data for charts
|
||||
* Get monthly data for charts - full year
|
||||
* @returns Promise with array of monthly data
|
||||
*/
|
||||
export async function getMonthlyData(): Promise<MonthlyData[]> {
|
||||
console.log("📈 [getMonthlyData] Obtendo dados mensais...");
|
||||
console.log("📈 [getMonthlyData] Obtendo dados mensais do ano completo...");
|
||||
|
||||
const normalizedEmail = getUserEmail();
|
||||
|
||||
@ -227,10 +230,10 @@ export async function getMonthlyData(): Promise<MonthlyData[]> {
|
||||
query = query.eq('login', normalizedEmail);
|
||||
}
|
||||
|
||||
// Get last 12 months
|
||||
const endDate = new Date();
|
||||
const startDate = new Date();
|
||||
startDate.setMonth(startDate.getMonth() - 11);
|
||||
// Get full current year
|
||||
const currentYear = new Date().getFullYear();
|
||||
const startDate = new Date(currentYear, 0, 1); // January 1st
|
||||
const endDate = new Date(currentYear, 11, 31); // December 31st
|
||||
|
||||
query = query
|
||||
.gte('quando', startDate.toISOString().split('T')[0])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user