budget-view-finance/src/pages/Calendario.tsx
gpt-engineer-app[bot] f315af5ed7 Fix: Activate and connect menu items
Connects the "Transações", "Categorias", and "Calendário" menu items to their respective functionalities. Ensures data from Supabase is displayed in these sections.
2025-05-17 23:44:35 +00:00

150 lines
5.7 KiB
TypeScript

import { useState, useEffect } from 'react';
import Layout from '@/components/layout/Layout';
import { Card, CardContent } from '@/components/ui/card';
import { Calendar } from "@/components/ui/calendar";
import { getTransacoes } from '@/services/transacaoService';
import { Transaction } from '@/types/financialTypes';
import { useToast } from "@/components/ui/use-toast";
import { Badge } from "@/components/ui/badge";
import { isSameDay, format } from 'date-fns';
import { ptBR } from 'date-fns/locale';
const CalendarioPage = () => {
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date());
const [filteredTransactions, setFilteredTransactions] = useState<Transaction[]>([]);
const { toast } = useToast();
useEffect(() => {
async function loadTransactions() {
try {
setIsLoading(true);
console.log("Carregando transações para o calendário...");
const data = await getTransacoes();
console.log(`${data.length} transações carregadas para o calendário`);
setTransactions(data);
} catch (error) {
console.error("Erro ao carregar transações:", error);
toast({
title: "Erro ao carregar transações",
description: "Não foi possível obter os dados do Supabase",
variant: "destructive"
});
} finally {
setIsLoading(false);
}
}
loadTransactions();
}, [toast]);
useEffect(() => {
if (selectedDate && transactions.length > 0) {
const filtered = transactions.filter(transaction =>
isSameDay(new Date(transaction.quando), selectedDate)
);
setFilteredTransactions(filtered);
} else {
setFilteredTransactions([]);
}
}, [selectedDate, transactions]);
const formatCurrency = (value: number) => {
return new Intl.NumberFormat('pt-BR', {
style: 'currency',
currency: 'BRL',
}).format(value);
};
// Função para verificar se um dia tem transações
const hasDayTransaction = (date: Date) => {
return transactions.some(transaction =>
isSameDay(new Date(transaction.quando), date)
);
};
return (
<Layout>
<div className="space-y-6">
<div className="flex justify-between items-center">
<h1 className="text-2xl font-bold tracking-tight">Calendário de Transações</h1>
</div>
<div className="grid md:grid-cols-5 gap-6">
<Card className="md:col-span-2">
<CardContent className="pt-6">
<Calendar
mode="single"
selected={selectedDate}
onSelect={setSelectedDate}
locale={ptBR}
className="max-w-full pointer-events-auto"
modifiers={{
hasTransaction: (date) => hasDayTransaction(date),
}}
modifiersStyles={{
hasTransaction: {
fontWeight: "bold",
textDecoration: "underline",
backgroundColor: "rgba(16, 185, 129, 0.1)"
}
}}
/>
<div className="mt-4 text-sm text-muted-foreground text-center">
Dias com transações estão destacados
</div>
</CardContent>
</Card>
<Card className="md:col-span-3">
<CardContent className="p-6">
<h2 className="text-lg font-semibold mb-4">
{selectedDate ? format(selectedDate, "dd 'de' MMMM 'de' yyyy", { locale: ptBR }) : "Selecione uma data"}
</h2>
{isLoading ? (
<div className="space-y-3">
{[1, 2, 3].map((i) => (
<div key={i} className="p-4 border rounded-md animate-pulse">
<div className="h-4 bg-muted rounded w-1/4 mb-2"></div>
<div className="h-6 bg-muted rounded w-1/2"></div>
</div>
))}
</div>
) : filteredTransactions.length === 0 ? (
<div className="text-center py-10 text-muted-foreground">
Nenhuma transação nesta data
</div>
) : (
<div className="space-y-3">
{filteredTransactions.map((transaction) => (
<div key={transaction.id} className="p-4 border rounded-md hover:bg-muted/50 transition-colors">
<div className="flex justify-between items-center mb-1">
<div className="font-medium">{transaction.estabelecimento}</div>
<Badge variant={transaction.tipo === 'entrada' ? "success" : "destructive"}>
{transaction.tipo === 'entrada' ? 'Receita' : 'Despesa'}
</Badge>
</div>
<div className="text-sm text-muted-foreground mb-2">{transaction.detalhes}</div>
<div className="flex justify-between">
<Badge variant="outline">{transaction.categoria}</Badge>
<span className={transaction.tipo === 'entrada' ? "text-finance-green font-medium" : "text-finance-red font-medium"}>
{transaction.tipo === 'entrada' ? '+' : '-'}{formatCurrency(Math.abs(transaction.valor))}
</span>
</div>
</div>
))}
</div>
)}
</CardContent>
</Card>
</div>
</div>
</Layout>
);
};
export default CalendarioPage;