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:
gpt-engineer-app[bot] 2025-06-24 18:38:44 +00:00
parent 45234a1a61
commit 4e8972cb55
5 changed files with 260 additions and 171 deletions

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { import {
BarChart, BarChart,
Bar, Bar,
@ -48,6 +47,31 @@ const MonthlyChart: React.FC<MonthlyChartProps> = ({ data, isLoading = false })
}).format(value); }).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) => { const customTooltip = ({ active, payload, label }: any) => {
if (active && payload && payload.length) { if (active && payload && payload.length) {
return ( return (
@ -64,7 +88,6 @@ const MonthlyChart: React.FC<MonthlyChartProps> = ({ data, isLoading = false })
return null; return null;
}; };
// Custom label component that only shows values above a threshold
const CustomLabel = ({ x, y, width, value, dataKey }: any) => { const CustomLabel = ({ x, y, width, value, dataKey }: any) => {
if (!value || value < 100) return null; if (!value || value < 100) return null;
const isReceita = dataKey === 'receitas'; const isReceita = dataKey === 'receitas';
@ -84,105 +107,94 @@ const MonthlyChart: React.FC<MonthlyChartProps> = ({ data, isLoading = false })
}; };
return ( 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"> <div className="h-full animate-fade-in">
<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"> {isLoading ? (
<CardTitle className="text-lg font-bold tracking-tight text-zinc-700 dark:text-white flex items-center"> <div className="flex items-center justify-center h-[320px]">
<span className="mr-2">📈</span> Receitas vs Despesas <div className="h-32 w-32 rounded-full border-4 border-t-primary border-opacity-20 animate-spin" />
</CardTitle> </div>
</CardHeader> ) : (
<CardContent> <div className="h-[320px] relative">
{isLoading ? ( <ResponsiveContainer width="100%" height="100%">
<div className="flex items-center justify-center h-[260px]"> <BarChart
<div className="h-32 w-32 rounded-full border-4 border-t-primary border-opacity-20 animate-spin" /> data={fullYearData}
</div> margin={{ top: 30, right: 30, left: 20, bottom: 15 }}
) : data.length === 0 ? ( barGap={8}
<div className="flex flex-col items-center justify-center h-[260px] text-muted-foreground"> >
<span>Sem dados disponíveis</span> <CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.20} />
</div> <XAxis
) : ( dataKey="month"
<div className="h-[320px] relative"> axisLine={false}
<ResponsiveContainer width="100%" height="100%"> tickLine={false}
<BarChart tick={{ fontSize: 13, fontWeight: 500, fill: "#334155" }}
data={data} dy={10}
margin={{ top: 30, right: 30, left: 20, bottom: 15 }} />
barGap={8} <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} /> {fullYearData.map((entry, index) => (
<XAxis <Cell
dataKey="month" key={`cell-receitas-${index}`}
axisLine={false} fill="url(#receitaBar)"
tickLine={false} style={{ filter: 'drop-shadow(0px 2px 2px rgba(16,185,129,0.10))' }}
tick={{ fontSize: 13, fontWeight: 500, fill: "#334155" }} />
dy={10} ))}
/> </Bar>
<YAxis <Bar
tickFormatter={formatCompactCurrency} name="Despesas"
axisLine={false} dataKey="despesas"
tickLine={false} fill="#EF4444"
tick={{ fontSize: 13, fill: "#64748b" }} radius={[8, 8, 0, 0]}
width={80} barSize={36}
/> animationDuration={1200}
<Tooltip label={<CustomLabel dataKey="despesas" />}
cursor={{ fill: 'rgba(16, 185, 129, 0.07)' }} >
content={customTooltip} {fullYearData.map((entry, index) => (
/> <Cell
<Legend key={`cell-despesas-${index}`}
verticalAlign="top" fill="url(#despesaBar)"
height={36} style={{ filter: 'drop-shadow(0px 2px 2px rgba(239,68,68,0.08))' }}
iconType="circle" />
iconSize={12} ))}
wrapperStyle={{ fontWeight: 600, fontSize: 13, color: "#52525b" }} </Bar>
/> <defs>
<Bar <linearGradient id="receitaBar" x1="0" y1="0" x2="0" y2="1">
name="Receitas" <stop offset="0%" stopColor="#17ead9" />
dataKey="receitas" <stop offset="100%" stopColor="#10B981" />
fill="#10B981" </linearGradient>
radius={[8, 8, 0, 0]} <linearGradient id="despesaBar" x1="0" y1="0" x2="0" y2="1">
barSize={36} <stop offset="0%" stopColor="#fbc2eb" />
animationDuration={1200} <stop offset="100%" stopColor="#EF4444" />
label={<CustomLabel dataKey="receitas" />} </linearGradient>
> </defs>
{data.map((entry, index) => ( </BarChart>
<Cell </ResponsiveContainer>
key={`cell-receitas-${index}`} </div>
fill="url(#receitaBar)" )}
style={{ filter: 'drop-shadow(0px 2px 2px rgba(16,185,129,0.10))' }} </div>
/>
))}
</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>
); );
}; };

View 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 };
};

View File

@ -1,4 +1,3 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { useToast } from "@/hooks/use-toast"; import { useToast } from "@/hooks/use-toast";
@ -10,6 +9,7 @@ import { useTransactions } from "@/hooks/useTransactions";
import CategoryChart from "@/components/dashboard/CategoryChart"; import CategoryChart from "@/components/dashboard/CategoryChart";
import MonthlyChart from "@/components/dashboard/MonthlyChart"; import MonthlyChart from "@/components/dashboard/MonthlyChart";
import { SimpleCard } from "@/components/ui/simple-card"; import { SimpleCard } from "@/components/ui/simple-card";
import { useNavigateWithFilter } from "@/hooks/useNavigateWithFilter";
const Dashboard = () => { const Dashboard = () => {
const [resumo, setResumo] = useState<ResumoFinanceiro | null>(null); const [resumo, setResumo] = useState<ResumoFinanceiro | null>(null);
@ -17,6 +17,7 @@ const Dashboard = () => {
const [monthlyData, setMonthlyData] = useState<MonthlyData[]>([]); const [monthlyData, setMonthlyData] = useState<MonthlyData[]>([]);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const { toast } = useToast(); const { toast } = useToast();
const { navigateToTransactions } = useNavigateWithFilter();
const getCurrentMonth = () => { const getCurrentMonth = () => {
const now = new Date(); const now = new Date();
@ -94,6 +95,7 @@ const Dashboard = () => {
} }
const saldo = resumo ? resumo.totalReceitas - resumo.totalDespesas - (resumo.totalCartoes || 0) : 0; const saldo = resumo ? resumo.totalReceitas - resumo.totalDespesas - (resumo.totalCartoes || 0) : 0;
const totalDespesasGeral = resumo ? resumo.totalDespesas + (resumo.totalCartoes || 0) : 0;
return ( return (
<div className="space-y-6" data-tour="dashboard-content"> <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> <h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
</div> </div>
<div className="grid gap-4 md:grid-cols-4"> <div className="grid gap-6 md:grid-cols-4">
<Card className="border-2 border-green-200 bg-green-50/50"> {/* Card Receitas - Clicável */}
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <Card
<CardTitle className="text-sm font-medium text-green-700">Receitas</CardTitle> 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"
<div className="p-2 bg-green-100 rounded-full"> onClick={() => navigateToTransactions('receita')}
<ArrowUpIcon className="h-4 w-4 text-green-600" /> >
<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> </div>
</CardHeader> <div className="space-y-2">
<CardContent> <p className="text-sm font-semibold text-green-700">Receitas</p>
<div className="text-2xl font-bold text-green-600"> <p className="text-3xl font-bold text-green-600">
{resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'} {resumo ? formatCurrency(resumo.totalReceitas) : 'R$ 0,00'}
</div> </p>
<div className="flex items-center text-xs text-green-600 mt-1"> <p className="text-xs text-green-600 opacity-80">Clique para ver detalhes</p>
<span className="bg-green-100 px-2 py-1 rounded-full">+5%</span>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card className="border-2 border-red-200 bg-red-50/50"> {/* Card Despesas - Clicável */}
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <Card
<CardTitle className="text-sm font-medium text-red-700">Despesas</CardTitle> 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"
<div className="p-2 bg-red-100 rounded-full"> onClick={() => navigateToTransactions('despesa')}
<ArrowDownIcon className="h-4 w-4 text-red-600" /> >
<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> </div>
</CardHeader> <div className="space-y-2">
<CardContent> <p className="text-sm font-semibold text-red-700">Despesas</p>
<div className="text-2xl font-bold text-red-600"> <p className="text-3xl font-bold text-red-600">
{resumo ? formatCurrency(resumo.totalDespesas + (resumo.totalCartoes || 0)) : 'R$ 0,00'} {resumo ? formatCurrency(totalDespesasGeral) : 'R$ 0,00'}
</div> </p>
<div className="flex items-center text-xs text-red-600 mt-1"> {resumo && resumo.totalCartoes > 0 && (
<span className="bg-red-100 px-2 py-1 rounded-full">-2%</span> <p className="text-xs text-red-500">Cartões: {formatCurrency(resumo.totalCartoes)}</p>
</div> )}
{resumo && resumo.totalCartoes > 0 && ( <p className="text-xs text-red-600 opacity-80">Clique para ver detalhes</p>
<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> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card className="border-2 border-purple-200 bg-purple-50/50"> {/* Card Saldo */}
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <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">
<CardTitle className="text-sm font-medium text-purple-700">Economia</CardTitle> <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" />
<div className="p-2 bg-purple-100 rounded-full"> <CardContent className="p-6 relative">
<Target className="h-4 w-4 text-purple-600" /> <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> </div>
</CardHeader> <div className="space-y-2">
<CardContent> <p className="text-sm font-semibold text-blue-700">Saldo</p>
<div className="text-2xl font-bold text-purple-600"> <p className={`text-3xl font-bold ${
-22.2% 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> </div>
<p className="text-xs text-purple-500 mt-1">{resumo ? formatCurrency(Math.abs(saldo)) : 'R$ 0,00'}</p>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
<div className="space-y-6"> <div className="space-y-6">
{/* 1. Receitas vs Despesas Chart */} {/* 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} /> <MonthlyChart data={monthlyData} isLoading={isLoading} />
</SimpleCard> </SimpleCard>
{/* 2. Gastos por Categoria */} {/* 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} /> <CategoryChart categories={categories} isLoading={isLoading} />
</SimpleCard> </SimpleCard>
{/* 3. Últimas Transações */} {/* 3. Últimas Transações */}
<SimpleCard title="Últimas Transações" className="border-blue-200"> <SimpleCard title="📋 Últimas Transações" className="border-blue-200">
<TransactionsTable <TransactionsTable
transactions={transactions.slice(0, 5)} transactions={transactions.slice(0, 5)}
isLoading={transactionsLoading} isLoading={transactionsLoading}

View File

@ -1,4 +1,6 @@
import { useEffect } from 'react';
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';
import { TransactionDialogs } from '@/components/transacoes/TransactionDialogs'; import { TransactionDialogs } from '@/components/transacoes/TransactionDialogs';
@ -7,6 +9,7 @@ import TransactionsTable from '@/components/dashboard/TransactionsTable';
import { SimpleCard } from "@/components/ui/simple-card"; import { SimpleCard } from "@/components/ui/simple-card";
const Transacoes = () => { const Transacoes = () => {
const location = useLocation();
const { const {
transactions, transactions,
isLoading, isLoading,
@ -30,6 +33,25 @@ const Transacoes = () => {
loadTransactions loadTransactions
} = useTransactions(); } = 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 ( return (
<div className="space-y-6"> <div className="space-y-6">
<TransactionHeader <TransactionHeader
@ -44,9 +66,14 @@ const Transacoes = () => {
formatCurrency={formatCurrency} 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 <TransactionsTable
transactions={transactions} transactions={filteredTransactions}
isLoading={isLoading} isLoading={isLoading}
showPagination={true} showPagination={true}
onEdit={handleEditTransaction} onEdit={handleEditTransaction}

View File

@ -1,4 +1,3 @@
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";
@ -177,13 +176,17 @@ export async function getCategorySummary(tipo: string = 'despesa'): Promise<Cate
total += valor; total += valor;
}); });
// Convert to CategorySummary array with colors // Enhanced color palette with more distinct colors - avoiding white/light colors
const colors = [ const colors = [
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
'#9966FF', '#FF9F40', '#FF6384', '#C9CBCF', '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9',
'#4BC0C0', '#FF6384', '#36A2EB', '#FFCE56' '#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) const categoryArray = Object.entries(categoryMap)
.map(([categoria, valor], index) => ({ .map(([categoria, valor], index) => ({
categoria, 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 * @returns Promise with array of monthly data
*/ */
export async function getMonthlyData(): Promise<MonthlyData[]> { export async function getMonthlyData(): Promise<MonthlyData[]> {
console.log("📈 [getMonthlyData] Obtendo dados mensais..."); console.log("📈 [getMonthlyData] Obtendo dados mensais do ano completo...");
const normalizedEmail = getUserEmail(); const normalizedEmail = getUserEmail();
@ -227,10 +230,10 @@ export async function getMonthlyData(): Promise<MonthlyData[]> {
query = query.eq('login', normalizedEmail); query = query.eq('login', normalizedEmail);
} }
// Get last 12 months // Get full current year
const endDate = new Date(); const currentYear = new Date().getFullYear();
const startDate = new Date(); const startDate = new Date(currentYear, 0, 1); // January 1st
startDate.setMonth(startDate.getMonth() - 11); const endDate = new Date(currentYear, 11, 31); // December 31st
query = query query = query
.gte('quando', startDate.toISOString().split('T')[0]) .gte('quando', startDate.toISOString().split('T')[0])